Smart Home Skillsを使ってみる

## Smart Home Skillとは？

一部のデバイス（Philips HueやBelkin WeMo）は同じネットワーク上にあれば、Amazon Echoからを直接検出して操作することが可能ですが、Alexa Voice Serviceを使った自作のEchoや、サードパーティーや自作のスマートホームデバイスを利用したい場合は、この[Smart Home Skill API](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/overviews/understanding-the-smart-home-skill-api)を使うことが推奨されています。

![alexa_smart_home_ecosystem.png](https://qiita-image-store.s3.amazonaws.com/0/36184/145eefd4-2acd-4230-d5ee-531e4a656a0b.png "alexa_smart_home_ecosystem.png")

<font color="red">現在のSmart Home Skillの最新はv3です。この記事はv2の時の内容ですので、リクエストのJSONなど微妙にちがいます。
v3のサンプルソースはこちらを参照して下さい。</font>
https://github.com/sparkgene/amazon_alexa_sample/tree/master/smarthome

## カスタムスキルとの違い

- Amazonがスマートホームデバイス向けのinteraction modelを用意しているので、Custom Skillsのようにintraction modelを設計する必要がない
- Smart Home SkillsはLambda上で実装する必要がある。Custom Skillsは自分でホストしても構わない
- OAuth2.0を利用したアカウント連携を実装する必要がある
- デバイスの検出と操作のために、クラウドベースのAPIにアクセスできる必要がある

[カスタムスキルを使ってスマートホームデバイスを利用する](https://www.hackster.io/sparkgene/alexa-makes-home-smarter-7e1981)ことも可能ではありますが、この例では一般公開はしづらい物が出来上がってしまいます。
また、通常のSkillではSkill名を含めて実行する必要があるため、`Alexa, turn on living lights`みたいに直感的な発話で操作できません。

## 注意

Smart Home Skillsは、クラウドで管理されたデバイスを使うことが前提です。
その為には、SkillでOAuthによって認可したユーザーとデバイスを紐付けたり、クラウドからデバイスを操作したりユーザとのヒモ付を管理する仕組みは、自分で用意する必要があります。
この投稿では全体の流れを知るために、簡単なLogin with AmazonをOAuthプロバイダとして利用しており、デバイスとユーザのヒモ付に関する実装には触れません。


# Login With Amazon(LWA) security profileを作成する

今回はOAuthプロバイダとしてAmazon.comを利用するのでデベロッパーコンソールからSecurity Profileを作成します。

## デベロッパーコンソール

https://developer.amazon.com/home.html

`APPS & SERVICES`の中にある`Login with Amazon`をクリック。

![s-01.png](https://qiita-image-store.s3.amazonaws.com/0/36184/9eee4144-a592-bd4f-fdc9-d8ede32e512c.png "s-01.png")

`Create n New Security Profile` をクリック。

![s-02.png](https://qiita-image-store.s3.amazonaws.com/0/36184/606cf45d-6091-6702-8bee-ce691bde9202.png "s-02.png")

必要な情報を入力。
`Consent Privacy Notice URL` には自分のサービスのプライバシーポリシーサイトを入力する。

![s-03.png](https://qiita-image-store.s3.amazonaws.com/0/36184/d0e82b67-938d-80aa-9595-88405d96996f.png "s-03.png")

作られました！

![s-04.png](https://qiita-image-store.s3.amazonaws.com/0/36184/a785b253-c5cb-a343-860d-b0e712407e26.png "s-04.png")

`Client ID`と`Client Secret`は後で使うのでメモっておく。

![s-05.png](https://qiita-image-store.s3.amazonaws.com/0/36184/dcfa5c57-b649-f58a-d2c9-afe13337447e.png "s-05.png")

# Smart Home Skillsを作成

## Skillを登録（１）

デベロッパーコンソールのメニューから`Alexa`を選択し、Alexa Skills Kitの`Get Started`をクリックします。

![s-06.png](https://qiita-image-store.s3.amazonaws.com/0/36184/3afd64a1-0062-1abb-ddab-f264a56bd2fc.png "s-06.png")

Skillの一覧画面が表示されるので、`Add a New Skill`をクリックします。
基本情報を入力する画面が表示されたら、Skill Typeで`Smart Home Skill`を選択して、その他の必要な情報を入力します。

![s-07.png](https://qiita-image-store.s3.amazonaws.com/0/36184/2247078e-a9ab-501e-b6a1-530a171b16ec.png "s-07.png")

登録が完了すると、Interaction Modelに進みますが、Smart Home Skillの場合は、自分でこのモデルを作成する必要はありません。

![s-08.png](https://qiita-image-store.s3.amazonaws.com/0/36184/e3fd9d8e-ed78-4748-3bc9-79dc6c90fa01.png "s-08.png")

このあとの手順でLambdaファンクションのヒモ付を登録するので、一旦`Skill Information`に戻ります。
このSkillのApplication Idが表示されているので、これを元にLambdaファンクションの登録に進みます。
![s-09.png](https://qiita-image-store.s3.amazonaws.com/0/36184/1123200d-a66e-6d22-1a1e-5c051a7b2879.png "s-09.png")


## 空のLambdaファンクションを登録

2016/10月現在は、Skillの作成は以下のリージョンでしか行なえません。（イギリス、ドイツの対応でEUのリージョンが追加されましたね）

- us-east-1
- eu-west-1

Lambdaの登録をすすめるとBlue Printの選択が出てくるので、検索のところに`alexa`と入力して、Smart Home Skillのblue printを選択します。

![l-01.png](https://qiita-image-store.s3.amazonaws.com/0/36184/49661c53-9dcf-3dc7-a79e-660acfab3742.png "l-01.png")

先程Skillを登録した際に発行されたApplication Idを入力します。
`Enable Triger`にもチェックを付けます。

![l-02.png](https://qiita-image-store.s3.amazonaws.com/0/36184/4a4bc7c5-0a5e-2425-352e-9c48e3993567.png "l-02.png")

適当な名前を付けてます（現状Smart Home Skillのblue printはnode.jsしか無いので、RuntimeはNode.jsを利用します）

![l-03.png](https://qiita-image-store.s3.amazonaws.com/0/36184/28c108e7-ed91-e4b5-a6be-31a852ac5b1b.png "l-03.png")

Lambdaファンクションに付与するRoleを作成します。

![l-04.png](https://qiita-image-store.s3.amazonaws.com/0/36184/46167f97-83fd-a78f-9ae5-8b13e475ac6b.png "l-04.png")

わかりやすい名前を付け、`Allow`をクリックしてRoleを作成します。

![l-05.png](https://qiita-image-store.s3.amazonaws.com/0/36184/91f7d1a3-b564-6103-85d5-829a24f1352d.png "l-05.png")

今作成したRoleを選択し、Lambdaファンクションの作成を完了させます。

![l-06.png](https://qiita-image-store.s3.amazonaws.com/0/36184/e1f48e6b-8e64-b9a3-4374-6fe542818399.png "l-06.png")

Lambdaファンクションが作成されると、画面の右上にARNが表示されるので、この値をコピーします。

![l-07.png](https://qiita-image-store.s3.amazonaws.com/0/36184/b92972c8-c22b-6c29-5d11-2c2017dbb459.png "l-07.png")

## Skillの登録（２）

Skillから呼び出すLambdaファンクションの準備ができたので、Skillの設定画面に戻って、続きを入力します。
`Configuration`をクリックして、`North America`にチェックを付けるとARNを入力するところが表示されるので、先程作成したLambdaファンクションのARNを入力します。

![s-10.png](https://qiita-image-store.s3.amazonaws.com/0/36184/364eec7d-0b3d-4a2a-69d9-91872829cce5.png "s-10.png")

Acount Linkingの各項目を入力します。

![s-11.png](https://qiita-image-store.s3.amazonaws.com/0/36184/830316d7-d101-78ab-4dcb-c445a3b8650b.png "s-11.png")



| 項目名 | 値 | 説明 |
|-------|----|-----|
|Authorization URL|https://www.amazon.com/ap/oa?redirect_uri=https://pitangui.amazon.com/api/skill/link/hogefuga |OAuthプロバイダでLWAを利用しているので、そのエンドポイントと`Redirect URLs`に書かれているURL一つを`redirect_uri=`に指定。lambdaがUSなのでUSがいいのかな |
|Client Id|| LWAので発行されたClient Id|
|Domain List|オプション|Authorization URLがフェッチするドメイン（最大15個まで）|
| Scope | profile |LWAで取得できる情報の指定。[customer profile](https://developer.amazon.com/public/apis/engage/login-with-amazon/docs/customer_profile.html)|
|Authorization Grant Type|Auth Code Grant|Smart Home Skilsの場合は`Auth Code Grant`が必須です|
|Access Token URI|https://api.amazon.com/auth/o2/token|LWAを利用しているので|
|Client Secret||LWAので発行されたClient Secret|
|Client Authentication Scheme|HTTP Basic (recommended)|変更しないでこのまま|
|Privacy Policy URL| |このSkillを利用するに当たってのプライバシーポリシーが書かれているURL（LWAで登録したのと同じになるかな）|

`Save`ボタンをクリックして入力した内容を登録します。

### Login with Amazon(LWA)の設定更新

Skillの登録を進めた際に、Redirect URLsにリダイレクト先のURLが表示されたかと思いますが、このURLをLWA側の許可リストに追加します。
Security Profileの画面で`Web Settings`をクリックして、`Allowed Return URLs`にSkillsの画面で指定したリダイレクトURLを入力します。

![s-12.png](https://qiita-image-store.s3.amazonaws.com/0/36184/ece58ba8-9b0a-de44-e9fd-105151c74c34.png "s-12.png")

ここまで登録したところでやっとSmart Home Skillを利用するための認証＆認可の動作確認ができるようになります。

![s-13.png](https://qiita-image-store.s3.amazonaws.com/0/36184/28d7a4df-524a-c994-506f-c4bb81cbf62f.png "s-13.png")

## 動作確認

http://alexa.amazon.com/spa/index.html
Alexaのポータルにログインして、作成したSkillの画面から`Your Skills`を選択します。
すると、今回作成したSkillが表示されます。（Account linkingが必須と表示されてますね）
![s-14.png](https://qiita-image-store.s3.amazonaws.com/0/36184/67768dfd-ba0c-3432-f4f1-9f0eb44155a9.png "s-14.png")

Skillの詳細を表示するとSkillを有効にできるので、`Enable Skill`をクリックします。

![s-15.png](https://qiita-image-store.s3.amazonaws.com/0/36184/b77797ca-c3b9-df70-a453-cfcf771dce95.png "s-15.png")

Amazon.comの認証画面が表示されました。

![s-16.png](https://qiita-image-store.s3.amazonaws.com/0/36184/811ba289-b6b0-12a9-cc21-b77ad69758c4.png "s-16.png")

ログインすると提供する情報のリストが表示されます。
この画面にプライバシーポリシーのリンクが表示されますね。

![s-17.png](https://qiita-image-store.s3.amazonaws.com/0/36184/d838f6a8-5ac3-9905-8f41-210ff6428ba6.png "s-17.png")

作成したSmart Home SkillがAlexaで利用できるようになりました！

![s-18.png](https://qiita-image-store.s3.amazonaws.com/0/36184/65cf2350-833a-f677-a470-ff891b96de8f.png "s-18.png")

Alexaの画面に戻ると、デバイスを検索するかポップアップが表示されます。

![s-19.png](https://qiita-image-store.s3.amazonaws.com/0/36184/52b39329-1b06-2cce-e08d-eeb151d5ea79.png "s-19.png")

試しに探してもらいましょう。
まだLambdaの方を全然コーディングしていないので、何も見つからないけど。。
Amazon EchoやAlexa Voice Serviceを実装したデバイスからも、`Alexa, Discover Devices`と話しかけて検索することも可能です。

![s-21.png](https://qiita-image-store.s3.amazonaws.com/0/36184/429b3b68-7074-0acb-3a9f-c8f80c031b17.png "s-21.png")

Lambda側のMonitorを見ると、呼び出されたのがわかります。

![s-20.png](https://qiita-image-store.s3.amazonaws.com/0/36184/8b3d9f68-12c8-cf1f-48e6-fe819b56e35c.png "s-20.png")


以上で、Smart Home Skillの登録が完了しました。
とは言ってもまだこれでは家の中のデバイスを操作することは出来ません。
Skillの本体であるLambdaファンクションと実際に操作するデバイスのセットアップが必要です。

# 動くLambdaファンクションの作成

## Smart Home Skillのリクエストの種類

Smart Home skillでは、デバイスを操作するためのInteraction Modelが元から組み込まれているため、操作するためのリクエスのと種類が決まっています。

https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference

代表的なものを幾つか解説したいと思います。

### DiscoverAppliancesRequest

`Alexa, discover my smart home devices` や `Alexa, discover devices` と話しかけると、デバイスの検出のためにLambdaファンクションへ送られてくるリクエストです。

```
{
    "header": {
        "messageId": "aaaa-bbbb-cccc-dddd-eeee",
        "name": "DiscoverAppliancesRequest",
        "namespace": "Alexa.ConnectedHome.Discovery",
        "payloadVersion": "2"
    },
    "payload": {
        "accessToken": "OAuth Token"
    }
}
```

このように送られてくるリクエストは`header`と`payload`の組み合わせとなっています。
payloadに含まれているのはOAuthプロバイダと認可の手続きを行った際に発行されたtokenですので、このtokenを使って誰からのリクエストなのかを判別します。
今回はLogin with Amazonを利用したので、Amazon APIのエンドポイントに問い合わせると、このリクエストを送ってきたユーザの情報を取得することが出来ます。

```
curl -H 'x-amz-access-token:<your token>' https://api.amazon.com/user/profile
```

このリクエストの戻り値に検出したデバイスの情報 **DiscoverApplianceResponse** として以下のようなフォーマットで返します。

```
{
  "header": {
    "payloadVersion": "2",
    "namespace": "Alexa.ConnectedHome.Control",
    "name": "DiscoverAppliancesResponse",
    "messageId": "aaaa-bbbb-cccc-dddd-ffff"
  },
  "payload": {
    "discoveredAppliances": [
      {
        "friendlyDescription": "some awsome light description.",
        "modelName": "my-device-model-1",
        "additionalApplianceDetails": {
            "SpecialInfo1": "something special description"
        },
        "version": "1",
        "manufacturerName": "sparkgene.com",
        "friendlyName": "awsome light",
        "actions": [
          "turnOn",
          "turnOff"
        ],
        "applianceId": "my-device-unique-id",
        "isReachable": true
      }
    ]
  }
}
```

`discoveredAppliances`には検出したデバイスすべてを列挙します。
**actions** に指定されているのが、このデバイスに対して行える操作です。

- incrementTargetTemperature
- decrementTargetTemperature
- setPercentage
- incrementPercentage
- decrementPercentage
- turnOff
- turnOn

### TurnOnRequest

`Alexa, turn on the awsome light` と話しかけると送られてきます。

```
{
  "header": {
    "payloadVersion": "2",
    "namespace": "Alexa.ConnectedHome.Control",
    "name": "TurnOnRequest",
    "messageId": "aaa-bbb-ccc-ddd-eee"
  },
  "payload": {
    "appliance": {
      "additionalApplianceDetails": {},
      "applianceId": "my-device-unique-id"
    },
    "accessToken": "OAuth Token"
  }
}
```

このリクエストの戻り値に検出したデバイスの情報 **TurnOnConfirmation** として以下のようなフォーマットで返します。

```
{
  "header": {
    "payloadVersion": "2",
    "namespace": "Alexa.ConnectedHome.Control",
    "name": "TurnOnConfirmation",
    "messageId": "aaa-bbb-2222-ddd-1111"
  },
  "payload": {}
}
```


### TurnOffRequest

`Alexa, turn on the awsome light` と話しかけると送られてきます。

```
{
  "header": {
    "payloadVersion": "2",
    "namespace": "Alexa.ConnectedHome.Control",
    "name": "TurnOffRequest",
    "messageId": "aaa-bbb-ccc-ddd-eee"
  },
  "payload": {
    "appliance": {
      "additionalApplianceDetails": {},
      "applianceId": "my-device-unique-id"
    },
    "accessToken": "OAuth Token"
  }
}
```

このリクエストの戻り値に検出したデバイスの情報 **TurnOffConfirmation** として以下のようなフォーマットで返します。

```
{
  "header": {
    "payloadVersion": "2",
    "namespace": "Alexa.ConnectedHome.Control",
    "name": "TurnOffConfirmation",
    "messageId": "aaa-bbb-2222-ddd-1111"
  },
  "payload": {}
}
```

## サンプル

実際にデバイスの検出から、照明のOn/OffができるSkillを用意してみました。（Lambdaとデバイスは繋がっていないので、照明は操作されません）

[![Alexa Smart Home Skill Sample](http://img.youtube.com/vi/WOsadmefSqk/0.jpg)](http://www.youtube.com/watch?v=WOsadmefSqk)

### ソース

https://github.com/sparkgene/smart_home_skill

サンプルソースはPythonで書いてます。上記の手順では、LambdaファンクションのruntimeでNode.jsを選択していますが、runtimeを`Python 2.7`に変更し、Handlerに`lambda_function.lambda_handler`と入力すれば、Pythonで動かすことが出来ます。

## まとめ

Smart Home Skillを利用することでInteraction Modelの設計が不要であったり、Alexaでの発話が自然になります。
しかし、このSkillはデバイスメーカーが自社のデバイスをAlexaを使って操作するイメージ（と思ってる）であるため、ユーザの登録やデバイスの管理といった仕組みを自分で作る必要があります。

とは言え、個人で家のデバイスをコントロールするのであれば、Lambdaファンクションにデバイスとの連携を直接書いてしまえばいいのかなと思います。（もちろん、公開できませんけどね）

## 参考リンク

- https://developer.amazon.com/public/community/post/Tx4WG410EHXIYQ/Five-Steps-Before-Developing-a-Smart-Home-Skill

- https://developer.amazon.com/public/community/post/Tx3CX1ETRZZ2NPC/Alexa-Account-Linking-5-Steps-to-Seamlessly-Link-Your-Alexa-Skill-with-Login-wit

- https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference

- https://developer.amazon.com/public/apis/engage/login-with-amazon/docs/obtain_customer_profile.html