Alexaスキルにタイマーを追加する:第1回

Anand Kumar Sep 28, 2021
Share:
Build Alexa-Hosted Skills
Blog_Header_Post_Img

アラームやリマインダーに並び、タイマーもAlexaの最もよく使われる機能の1つです。レシピに沿って料理をしたり、エクササイズのルーチンをこなしたり、ときには20分だけ仮眠をとるなど、さまざまなシーンで活躍するタイマーは、すぐに使えてセットしやすいことが何より重要です。

しかし、これまでAlexaユーザーがタイマーを使うには、一度スキルセッションを出なければなりませんでした。こうしたエクスペリエンスを改善するため、このたび、Alexaスキルに直接タイマー機能を追加する機能を導入しました。この機能は、Alexaがサポートするすべてのロケールで利用できます。

このブログで2回にわたって詳しく紹介していきますが、第1回では、ユーザーの許可を取得する方法、そして許可の取得後にTimer APIを呼び出す方法を説明します。

注: このチュートリアルのサンプルコードはすべて、Node.js ASK SDKを使って作成しています。

スキルにTimer APIを追加する手順

1. ユーザーの許可を取得する

タイマーを作成するには、明示的にユーザーの許可をとる必要があります。Alexaサービスは、スキルごとにタイマーを使用する権限を提供します。ユーザーがスキルにタイマー作成のアクセス権限を付与していない場合、スキルでユーザーにアクセス権限の付与方法を説明し、Alexaアプリにスキルのアクセス権限ページへのリンクを記載したホームカードを送信してください。

タイマーを作成するこれら2つの権限セットを取得するには、2つの方法があります。 

  • 1つは、タイマー作成の読み取り/書き込み権限をスキルを有効にする時点で付与してもらう方法です。
  • もう1つは、権限カードや音声での権限リクエストを作成して、スキルを初めて使うユーザーにAlexaスキル内でタイマーに関する権限を付与してもらうようたずねる方法です。

Alexaアプリで権限カードを送信する方法

Copied to clipboard
const {responseBuilder} = handlerInput;
const consentToken = requestEnvelope.context.System.apiAccessToken;
if(!consentToken){
    return responseBuilder
            .withAskForPermissionsConsentCard(“alexa::alerts:timers:skill:readwrite”)
            .getResponse();
}

Alexaアプリに表示される権限カードの例

permission requested

音声で権限リクエストを送信する方法

Copied to clipboard
let {requestEnvelope} = handlerInput;
const {permissions} = requestEnvelope.context.System.user;
if (! (permissions && permissions.consentToken)){
         console.log('権限がありません。');
         return handlerInput.responseBuilder
                    .addDirective({
                        'type': 'Connections.SendRequest',
                        'name': 'AskFor',
                         'payload': {
                               '@type': 'AskForPermissionsConsentRequest',
                                '@version': '1',
                                'permissionScope': 'alexa::alerts:timers:skill:readwrite'
                          },
                      token: 'verifier'
                 }).getResponse();
            }
console.log('権限が見つかりました:' + permissions.consentToken);

このディレクティブを送信すると、Alexaはタイマーの権限を付与するようユーザーにリクエストします。これが、"Connections.Response"リクエストです。body.statusの値をチェックして、ユーザーがリクエストを承認したのか、拒否したのか、それとも何の応答もしなかったのかを確認する必要があります。

注: 以下のテキストのうち、「(Alexaが制御)」となっている文言をスキルで変更することはできません。

ユーザーが音声で権限を付与する場合

ユーザーがAlexaスキルでタイマーをセットする権限の付与を音声で承認した場合について、例を挙げて説明しましょう。

この例では、エクササイズタイマースキルがユーザーにタイマーの権限付与をリクエストしています。

ユーザー: アレクサ、エクササイズタイマーを開いて。

Alexa(スキルが制御): エクササイズタイマースキルへようこそ。エクササイズのお手伝いをするために、このスキルではアレクサでタイマーを使う必要があります。

Alexa(Alexaが制御): エクササイズタイマーにアクティビティのタイマー作成を許可することができます。タイマーの作成が完了したら、スキルのアクティビティに戻るかどうかをおたずねしますね。タイマーの作成を許可しますか?

ユーザー: はい

Alexa(Alexaが制御): わかりました。この許可は、アレクサアプリの「有効なスキル」セクションにある「エクササイズタイマー」でいつでも変更できます。


これにより、"status"が"ACCEPTED"に設定された状態でAlexaスキルにConnections.Responseディレクティブが送信されるので、スキルはユーザーに代わってタイマーの作成を続行できます。

Copied to clipboard
{
    "type": "Connections.Response",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "name": "AskFor",
    "status": {
        "code": "string",
        "message": "string"
    },
    "token": "string",
    "payload": {
    "permissionScope": "alexa::alerts:timers:skill:readwrite",
    "status": "ACCEPTED"
    }
}

ユーザーが音声による権限付与を拒否した場合

Alexaスキルの中でユーザーが音声によってタイマーの権限付与を拒否したとします。この例を詳しく見ていきましょう。

ここでは、ユーザーはエクササイズタイマースキルでタイマーの設定許可を拒否しています。

ユーザー: アレクサ、エクササイズタイマーを開いて。

Alexa(スキルが制御): エクササイズタイマースキルへようこそ。エクササイズのお手伝いをするために、このスキルではアレクサでタイマーを使う必要があります。

Alexa(Alexaが制御): エクササイズタイマーにアクティビティのタイマー作成を許可することができます。タイマーの作成が完了したら、スキルのアクティビティに戻るかどうかをおたずねしますね。タイマーの作成を許可しますか?

ユーザー: いいえ

Alexa(Alexaが制御): わかりました


これにより、"status"が"DENIED"に設定された状態でAlexaスキルに"Connections.Response"ディレクティブが送信され、Alexaスキルを応答した後に終了します。

Copied to clipboard
{
    "type": "Connections.Response",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "name": "AskFor",
    "status": {
        "code": "string",
        "message": "string"
    },
    "token": "string",
    "payload": {
    "permissionScope": "alexa::alerts:timers:skill:readwrite",
    "status": "DENIED"
    }
}

ユーザーの応答が不明瞭な場合

タイマーセットの権限付与をリクエストしたAlexaに対して、ユーザーの応答が不明瞭だったとします。Alexaは質問を言い換えて再プロンプトを出し、ユーザーが応答するのを待ちますが、以下のように応答がなかったり、不明瞭な応答が返ってきたりしました。

ユーザー: アレクサ、エクササイズタイマーを開いて。

Alexa(スキルが制御): エクササイズタイマースキルへようこそ。エクササイズのお手伝いをするために、このスキルではアレクサでタイマーを使う必要があります。

Alexa(Alexaが制御): エクササイズタイマーにアクティビティのタイマー作成を許可することができます。タイマーの作成が完了したら、スキルのアクティビティに戻るかどうかをおたずねしますね。タイマーの作成を許可しますか?

ユーザー:<不明瞭または応答なし>

Alexa(Alexaが制御): エクササイズタイマーにアクティビティ用のタイマー作成を許可しますか?

ユーザー:<不明瞭または応答なし>


これにより、"status"が"NOT_ANSWERED"に設定された状態でAlexaスキルに"Connections.Response"ディレクティブが送信され、Alexaスキルを応答した後に終了します。

Copied to clipboard
{
    "type": "Connections.Response",
    "requestId": "string",
    "timestamp": "string",
    "locale": "string",
    "name": "AskFor",
    "status": {
        "code": "string",
        "message": "string"
    },
    "token": "string",
    "payload": {
    "permissionScope": "alexa::alerts:timers:skill:readwrite",
    "status": "NOT_ANSWERED"
    }
}
2. ユーザーが権限を付与したらタイマーを作成する

タイマーを作成するには、セッション内アクセストークンを使ってAPIエンドポイントの(POST)呼び出しを行う必要があります。スキルでは、簡単な通知をしたり、お知らせを提供したり、タスクを起動したりするためにタイマーをトリガーできます。

なお、スキルセッション外でタイマーを作成することはできません。またタイマーを作成する際にはセッション内アクセストークンを使う必要があります。

注: トリガー時刻はリクエストを受信した時点の時刻に基づいて計算され、タイマーラベルはリクエストごとに一意である必要があります。

以下の例では、10分間の"ANNOUNCE"タイマーの後、「ではストレッチを止めてランニングを始めましょう」というメッセージをユーザーに伝えるTimer APIを呼び出しています。

タイマーを作成する際のPOST API呼び出し例

Copied to clipboard
POST /v1/alerts/timers
Host: https://api.fe.amazonalexa.com
Authorization: Bearer <アクセストークン>
Content-Type: application/json

リクエスト本文:

{
            "duration": "PT10M", 
            "timerLabel": "エクササイズ",
            "creationBehavior": {
                "displayExperience": {
                    "visibility": "VISIBLE"
                }
            },
            "triggeringBehavior": {
                "operation": {
                    "type": "ANNOUNCE",
                    "textToAnnounce": [{
                        "locale": "ja-JP",
                        "text": "ではストレッチを止めてランニングを始めましょう"
                    }]         
                },
                "notificationConfig": {
                    "playAudible": True
              }
        }
 }

タイマー作成をサポートするASK SDKも提供しているため、API呼び出しのコードを一から作成する必要はありません。

サンプルコード

Copied to clipboard
async handle(handlerInput) {
        const {requestEnvelope, serviceClientFactory} = handlerInput;

        const timer = {
            "duration": "PT10M", 
            "timerLabel": "エクササイズ",
            "creationBehavior": {
                "displayExperience": {
                    "visibility": "VISIBLE"
                }
            },
            "triggeringBehavior": {
                "operation": {
                    "type": "ANNOUNCE",
                    "textToAnnounce": [{
                        "locale": "ja-JP",
                        "text": "ではストレッチを止めてランニングを始めましょう"
                    }]         
                },
                "notificationConfig": {
                    "playAudible": True
                }
            }
        };

        console.log('タイマーの作成開始:' + JSON.stringify(timer));
        
        try {
            const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
            const timerResponse = await timerServiceClient.createTimer(timer);
            console.log('タイマー作成応答:' + JSON.stringify(timerResponse));
            
            const timerId = timerResponse.id;
            const timerStatus = timerResponse.status;

        } catch(error) {
            return handlerInput.responseBuilder.speak("権限が付与されていません。").getResponse();
        }
    }

タイマーの時間になったらカスタムタスクを起動することもできます。ただし、この機能は現在開発者プレビュー段階のため、ご希望の方はこちらからご登録ください。

まとめ

このブログの内容についてご不明な点がありましたら、こちらの技術資料をご覧ください。第2回では、「読み取り」、「更新」、「削除」といった操作を実装する方法を紹介する予定です。お楽しみに。

Subscribe