ちょっと話題の記事

[日本語Alexa] プロアクティブイベントでごみ収集の通知を送ってみた

2019.06.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

AIソリューション部の平内(SIN)です。

Alexaの ProactiveEvents APIを使用して、ゴミ収集について通知してみました。

最初に、動作しているようすです。スキルの有効化と通知の許可を設定し、ローカルのJavaScriptから通知を送ってます。

作業した手順は、以下のとりです。

  • スキルの作成 (特に何も実装していません)
  • プロアクティブイベントの追加
  • 通知の許可
  • 通知の送信

2 スキルの作成

今回のスキルは、通知を受け取るためだけに使用するので、特に何も実装していません。 Lambdaの配置もお任せということで、「Alexaがホスト」を使用して作成しました。

SMAPIからスキルを指定するために必要なので、スキルIDをコピーしておきます。

続いて、アクセス権限を開いて、一番下に表示されているAlexaスキルメッセージングクライアントIDクライアントシークレットをコピーしておきます。

この2つは、通知を送信する時に必要になります。

3 プロアクティブイベントの追加

スキルのマニフェストにpermissionsと、eventsを追加する作業です。現在、この作業はコンソールから行うことができないため、SMAPIが必要です。

取得

$ ask api get-skill -s amzn1.ask.skill.xxxxx-xxxx-xxxx > skill.json

更新

$ ask api update-skill -s amzn1.ask.skill.xxxxx-xxxx-xxxx -f skill.json

マニフェストの文法などに誤りがあると、更新に失敗するので、update-skillがちゃんと書き換えに成功しているかどうか、念のため、get-skillで更新されたものを確認することをお勧めします。

更新前後のマニフェストは、以下のとおりです。permissionsalexa::devices:all:notifications:write を追加し、events に使用するイベントの種類を指定します。

endpointは、どこで使用されているのか、ちょっと分からないのですが、有効なLambdaのarnである必要があるようです。

更新前

{
  "manifest": {
    "apis": {
      "custom": {
        "endpoint": {
          "uri": "arn:aws:lambda:us-east-1:647216831504:function:de401ac6-7b67-4c36-963f-56dd13736589:Release_0"
        }
      }
    },
    "permissions": [],
    "publishingInformation": {
      "locales": {
        "ja-JP": {
          "name": "通知サンプル"
        }
      }
    }
  }
}

更新後

{
  "manifest": {
    "apis": {
      "custom": {
        "endpoint": {
          "uri": "arn:aws:lambda:us-east-1:647216831504:function:de401ac6-7b67-4c36-963f-56dd13736589:Release_0"
        },
        "interfaces": []
      }
    },
    "permissions": [
      {
        "name": "alexa::devices:all:notifications:write"
      }
    ],
    "events": {
      "publications": [
        {
          "eventName": "AMAZON.TrashCollectionAlert.Activated"
        }
      ],
      "endpoint": {
        "uri": "arn:aws:lambda:us-east-1:xxxxxxxxx:function:sample"
      },
      "subscriptions": [
        {
          "eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED"
        }
      ]
    },
    "publishingInformation": {
      "locales": {
        "ja-JP": {
          "name": "通知サンプル"
        }
      }
    }
  }
}

今回、設定した、ごみ収集のリマインダー以外のイベントについては、以下をご参照下さい。
プロアクティブイベントAPI

4 通知の許可

マニフェストを更新すると、Alexaアプリでのスキルの表示が変わります。

「設定」からこれを許可することで、スキルは通知を受け取ることができるようになります。

5 通知の送信

通知を送るには、次の2つ作業が必要です。

  • アクセストークン取得
  • ProactiveEvents APIの呼び出し

(1) アクセストークン取得

開発者コンソールでコピーした、クライアントIDとクライアントシークレットを使用してOAuth2サーバからトークンを取得します。サンプルでは、getToken(clientId, clientSecret) で実装しました。

(2) ProactiveEvents APIの呼び出し

トークンを使用して、イベントに応じたJSONをproactiveEventsのエンドポイントに送信します。 サンプルでは、sendEvent(token)で実装しました。

イベントごとの送信するJSONは、以下をご参照下さい。
プロアクティブイベントのスキーマ

今回は、簡略化のためtrashCollectionAlertEvent()で決め打ちで実装しています。

(3) コード

実装したコードの全部です。

const rp = require('request-promise');

const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;

notify(); 

async function notify() {
    const token = await getToken(clientId, clientSecret);
    await sendEvent(token);
}

async function getToken(clientId, clientSecret) {
    const uri = 'https://api.amazon.com/auth/o2/token'

    let body = 'grant_type=client_credentials';
    body += '&client_id=' + clientId;
    body += '&client_secret=' + clientSecret;
    body += '&scope=alexa::proactive_events';

    const options = {
        method: 'POST',
        uri: uri,
        timeout: 30 * 1000,
        body: body,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    };
    const data = await rp(options);
    return JSON.parse(data).access_token;
}

async function sendEvent(token) {

    const body = JSON.stringify(trashCollectionAlertEvent());
    const uri = 'https://api.fe.amazonalexa.com/v1/proactiveEvents/stages/development'
    //const uri = 'https://api.fe.amazonalexa.com/v1/proactiveEvents/' // 公開スキルでは、こちら

    const options = {
        method: 'POST',
        uri: uri,
        timeout: 30 * 1000,
        body: body,
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': body.length,
            'Authorization' : 'Bearer ' + token
        }
    };
    await rp(options);
}

function trashCollectionAlertEvent() {

    let timestamp = new Date();
    let expiryTime = new Date();
    expiryTime.setMinutes(expiryTime.getMinutes() + 60);

    return {
        'timestamp': timestamp.toISOString(),
        'referenceId': 'id-'+ new Date().getTime(),
        'expiryTime': expiryTime.toISOString(),
        'event': {
            'name': 'AMAZON.TrashCollectionAlert.Activated',
            'payload': {
                'alert': {
                    'garbageTypes': [
                        'PET_BOTTLES',
                        'RECYCLABLE_PLASTICS',
                        'WASTE_PAPER',
                        'COMPOSTABLE',
                    ],
                    'collectionDayOfWeek': 'TUESDAY'
                }
            }
        },
        'localizedAttributes': [
            {
                'locale': 'ja-JP',
                'sellerName': 'TrashCollection'
            }
        ],
        'relevantAudience': {
            'type': 'Multicast',
            'payload': {}
        }
    }
}

6 最後に

今回は、Alexaのプロアクティブ・イベントでゴミ収集について通知してみました。 この仕様は、日本語で利用できるようになって、しばらく時間がたったと思うのですが、思ったより日本語での情報が公開されていない印象です。

イベントの種類によって、使い方が少し変わってきそうなので、もう少し、確認作業を進めたいと思っています。

7 参考リンク


通知の概要
プロアクティブイベントAPI
プロアクティブイベントのスキーマ
スキルマニフェストのスキーマ
スキルにイベントを追加する
Alexa Proactive Events API


弊社では、Amazon Connectに関するキャンペーンを行なっています。
【6/27(木)東京】「1時間でクラウド型コンタクトセンターを構築できるようになる!無料Amazon Connectハンズオンセミナー」を開催します

また、音声を中心とした各種ソリューションの開発支援を行なっております。