5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Alexa スマートホームスキル イベントゲートウェイにChangeReportを送信する

Last updated at Posted at 2020-03-29

はじめに

Alexa センサー用のスマートホームスキルでChangeReportをAlexaのイベントゲートウェイに送信する際に、ユーザーをAlexaで認証する必要がある。その認証で必要なトークンの取得方法からイベントゲートウェイへの送信方法の覚書。

前提

  • Alexaスキル モデル:スマートホーム(センサー用)
  • OAuthプロバイダー:LWA(Login with Amazon)

流れ

  1. LWAからトークンを取得
  2. ChangeReportを作成
  3. イベントゲートウェイに送信

センサー用スマートホームスキルのエンドポイントのプロパティ値を変更した場合は必ずプロアクティブにChangeReportイベントを送信する必要がある。

LWAからトークンを取得

トークンの有効期限は取得後60分。60分を超え、無効になったトークンを使用してリクエストを送信すると、401 Unauthorizedが返却され認証されない。そのため、有効期限が切れた場合は、前回取得したトークンに含まれるrefresh_tokenを使用してトークンを再発行する必要がある。

新規リクエスト(初回)

一番最初にトークンを取得する場合のリクエスト。
AcceptGrantディレクティブのcodeフィールドの値を使用して、LWAにアクセストークンリクエストを送信し、アクセストークンを取得する。

トークン新規発行リクエスト
POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;Accept-Charset=UTF-8
 
grant_type=authorization_code&code=SplxlOBezQQYbYS6WxSbIA&client_id=【AlexaクライアントID:】&client_secret=【Alexaクライアントシークレット:】

パラメータ

No. 項目 備考
1 grant_type authorization_code 固定値
2 code SRgccpEPdzDayxqHFsma AcceptGrantから取得
3 client_id 【AlexaクライアントID:】 alexa developer console(※)から取得
4 client_secret 【Alexaクライアントシークレット:】 alexa developer console(※)から取得

※alexa developer console -> 対象スキル -> ビルド -> アクセス権限 -> Alexaスキルメッセージング

レスポンス

200 OK
{
  "access_token":"Atza_IwEBI...Fq2w8uYFfE",
  "refresh_token":"Atzr_IwEBI...f6ohOBg3ig",
  "token_type": "bearer",
  "expires_in": 3600
}

※code値の取得方法

code値AcceptGrantレスポンスから取得する。
Alexaアプリを開き、対象のスマートホームスキルを有効にして、スキルとアカウントをリンクする。アカウントリンクが成功すると、AcceptGrantがスキルに送信されるので、CloudWatchログにAcceptGrantを出力させて、directive.payload.grant.codeを取得する。Lambda関数を作成してAcceptGrant取得する方法はこちらに記載

※もう一度AcceptGrantを送信したい場合は、Alexaアプリで対象スキルをスキルを無効にするにして、再有効化する。有効化時にアカウントリンクを設定するとAcceptGrantが送信される。

AcceptGrant
{
  "directive": {
    "header": {
      "namespace": "Alexa.Authorization",
      "name": "AcceptGrant",
      "messageId": "873c203b-833c-46a5-8ed6-9c7d2444df35",
      "payloadVersion": "3"
    },
    "payload": {
      "grant": {
        "type": "OAuth2.AuthorizationCode",
        "code": "SRgccpEPdzDayxqHFsma"          これ
      },
      "grantee": {
        "type": "BearerToken",
        "token": "Atza_IwEBI...z71DaTIJnI"
      }
    }
  }
}

curlでaccess_tokenを取得してみる

Windowsのコマンドプロンプトで以下を実行する。

curl
c:\> curl -i -X POST -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" -d "grant_type=authorization_code&code=<directive.payload.grant.code>&client_id=<AlexaクライアントID>&client_secret=<Alexaクライアントシークレット>" https://api.amazon.com/auth/o2/token

こんな感じで結果が返ってくる。

HTTP/1.1 200 OK
Server: Server
Date: Wed, 12 Jan 2022 08:59:55 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 656
Connection: keep-alive
x-amz-rid: H3JRCKNG4SD4H96ZZ41V
x-amzn-RequestId: d22f0700-c8a4-43e1-adbe-664b59ec80ba
X-Amz-Date: Wed, 12 Jan 2022 08:59:55 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Content-Type,Accept-Encoding,X-Amzn-CDN-Cache,X-Amzn-AX-Treatment,User-Agent
Permissions-Policy: interest-cohort=()

{"access_token":"Atza|IwEBIDtWO-tfB5kMY5Evs-iDOIKVysDoxdqdak8F15dwAdZgNCtC-a8TXsr8Y3Pzjn1TT6riulDI8KseIPgqZoRe8AHkqGVLhO2tcj3_OL-RCV2ZEk9KkKukBo7YNmOHqZhbs1z-VBqNzBaeVlH8q2liVA8FYy8E8Jir6jmvVv3QX6g4NvOYxB9TYDeRlBEg_XvfECbn5cjbXEc7hhgdffDhJnLVLLfii_DnhVr7kKInuaXO_jEZ2ZIiVEHVqA5LwSPbZeXL8KbAnkP_Jf33Rd83K_eR","refresh_token":"Atzr|IwEBILi1ETOk-rWAqVRVI-ClT3Rf212dSv5QM3ohHQBqMz4X4D80Iojh8BaSc-gOsppXeDNAHvxuWTIP_l80JbaLZ0SwicDLYqe2av_NNO5pIpE_hzDccntZ_FUD-ZGi4Xz5TrZAnaVz4CIonATb8ei9fG01lqC5vh3UGkxrgGpkXLILZT_F6ZujMU7qoSPQGSCPwohrZAr9vo4J9xaXCnas_kOBvRmES4Ji59JaRcIKVvRLpU94h_3Thm7Jn5WURh_gFFFb6wxgJwPhnmnsxFKMYSmb","token_type":"bearer","expires_in":3600}

更新リクエスト(2回目以降)

2回目以降のトークン取得。URLは変わってないが、リクエストのパラメータが変わっているので注意。codeではなくrefresh_tokenを使用する。

トークン更新リクエスト
POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;Accept-Charset=UTF-8
 
grant_type=refresh_token&refresh_token=Atzr_IwEBI...f6ohOBg3ig&client_id=【AlexaクライアントID:】&client_secret=【Alexaクライアントシークレット:】

パラメータ

No. 項目 備考
1 grant_type refresh_token 固定値
2 refresh_token Atzr_IwEBI...f6ohOBg3ig
3 client_id 【AlexaクライアントID:】 alexa developer console(※)から取得
4 client_secret 【Alexaクライアントシークレット:】 alexa developer console(※)から取得

※alexa developer console -> 対象スキル -> ビルド -> アクセス権限 -> Alexaスキルメッセージング

レスポンス

200 OK
{
  "access_token":"Atza_IwEBI...MMbdgEWYWI",
  "refresh_token":"Atzr_IwEBI...f6ohOBg3ig",
  "token_type": "bearer",
  "expires_in": 3600
}

curlでrefresh_tokenを取得してみる

Windowsのコマンドプロンプトで以下を実行する。

curl
c:\> curl -i -X POST -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" -d "grant_type=refresh_token&refresh_token=<1回目で取得したrefresh_token>&client_id=<AlexaクライアントID>&client_secret=<Alexaクライアントシークレット>" https://api.amazon.com/auth/o2/token

こんな感じで結果が返ってくる。

HTTP/1.1 200 OK
Server: Server
Date: Wed, 12 Jan 2022 08:42:45 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 678
Connection: keep-alive
x-amz-rid: 1ME24VEDQSZAW9ZF13D1
x-amzn-RequestId: fb439232-7e44-466c-886b-bd55ca9ddace
X-Amz-Date: Wed, 12 Jan 2022 08:42:45 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Content-Type,Accept-Encoding,X-Amzn-CDN-Cache,X-Amzn-AX-Treatment,User-Agent
Permissions-Policy: interest-cohort=()

{"access_token":"Atza|IwEBIF1cVmtHDvsBx8tnufdj97glJDvZyTBDM1ZMLXWQHSN1nlJSFJ-YTDomMV6vIGqHa7_lQ1nzHvKsg_PLFjVRq21_d_KFP_E8jb48kz_MctvPZNOsHcJCEAo7swbG0l5pyEUaCpKyDDU3Qlh8kxns_9PMj_ehTqQbhxLC0__RmJzRZuxkgt6w9z-qa7y77V5gdZxf1VIwkbwEqGY9wal4kpI5i4THtNawLQzmtlFhVNkP5RtOvSfNsspMHDG5huF7NvlBYc9XtRMEU8GgKwLWMfmILU18-tN6s50vC1yzbnOUQA","refresh_token":"Atzr|IwEBICo1PeLUZFMDzi_al8nCxH5hQYDky_6nI9Tmmvl-NJ4u7xO0-fkMr0rxSGJPOmVTm8-0AVMDmglzCE0ebnt8oUgo1BBXTY2gy5U1inxHx-o8-oO5UzWXIfHCbprXPncLQdF_ROeMHfOpeCNm31vooVjzpNFoNMCB3Ww64ROFSQlM1duUWqb2OLZRFgE2G_OuYNczaPoeDhHCoT9ee8UwvHfaWXn-Iccw2rfmhBPd9m_uVzu_R8dxJ-4rO8bzSvhOge6IyTGfMFRWwMMPm5bGBNVb","token_type":"bearer","expires_in":3600}

ChangeReportを作成

event.endpoint.scope.tokeに上記で取得した access_token を設定する。
endpointIdなどに、作成したスマートホームスキルの情報を設定する。

ChangeReport
{
  "context": {},
  "event": {
    "header": {
      "messageId": "tkr-123-def-456",
      "namespace": "Alexa",
      "name": "ChangeReport",
      "payloadVersion": "3"
    },
    "endpoint": {
      "scope": {
        "type":"BearerToken",
        "token":"Atza_IwEBI...MMbdgEWYWI"    access_token
       },
       "endpointId" :  "sensor-001" 
    },
    "payload": {
      "change": {
        "cause": {
          "type": "PHYSICAL_INTERACTION"
        },
        "properties": [
          {
            "namespace": "Alexa.MotionSensor",
            "name": "detectionState",
            "value": "DETECTED",
            "timeOfSample": "2020-03-22T16:20:50.52Z",
            "uncertaintyInMilliseconds": 0
          }
        ]
      }
    }
  }
}

イベントゲートウェイに送信

スマートホームスキルの言語を英語で作成したとしても、日本のAmazonアカウントを使用している場合は、エンドポイントに極東を使用する。

エンドポイント

リクエスト

HTTPヘッダーAuthorizationBearerの後に半角スペースを空け、上記で取得した access_token を設定する。

イベント送信リクエスト
POST /v3/events HTTP/1.1
Host: api.fe.amazonalexa.com
Authorization: Bearer Atza_IwEBI...MMbdgEWYWI
Content-Type: application/json

{
  "context": {},
  "event": {
    "header": {
      "messageId": "tkr-123-def-456",
      "namespace": "Alexa",
      "name": "ChangeReport",
      "payloadVersion": "3"
    },
    "endpoint": {
      "scope": {
        "type":"BearerToken",
        "token":"Atza_IwEBI...MMbdgEWYWI"
       },
       "endpointId" :  "sensor-001" 
    },
    "payload": {
      "change": {
        "cause": {
          "type": "PHYSICAL_INTERACTION"
        },
        "properties": [
          {
            "namespace": "Alexa.MotionSensor",
            "name": "detectionState",
            "value": "DETECTED",
            "timeOfSample": "2020-03-22T16:20:50.52Z",
            "uncertaintyInMilliseconds": 0
          }
        ]
      }
    }
  }
}

レスポンス(成功)

202 Acceptedが返却されれば成功。

202 Accepted

※何も返却されない。

レスポンス(失敗)

トークンの有効期限が切れている場合は、401 Unauthorizedが返却されるので、トークンを更新した後、再リクエストする。他のエラーの場合はマニュアルを参照し対応する。

401 Unauthorized
{
  "header": {
    "namespace": "System",
    "name": "Exception",
    "messageId": "fddd317c-2acf-4cba-a88e-fc0433385be8"
  },
  "payload": {
    "code": "INVALID_ACCESS_TOKEN_EXCEPTION",
    "description": "Access token is not valid."
  }
}

おわりに

定型アクションで、スマートホーム(センサー)をトリガーにして、Alexaがアクションするところまで確認した。
今回は、センサーデバイスからではなくブラウザを使用して、ベントゲートウェイへChengeReportリクエストを送信した。

定型アクション

デモ

記載している内容は、2020年3月30日時点での情報。変更されている可能性があるので注意。

参考

関連

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?