アラームやリマインダーに並び、タイマーもAlexaの最もよく使われる機能の1つです。レシピに沿って料理をしたり、エクササイズのルーチンをこなしたり、ときには20分だけ仮眠をとるなど、さまざまなシーンで活躍するタイマーは、すぐに使えてセットしやすいことが何より重要です。
しかし、これまでAlexaユーザーがタイマーを使うには、一度スキルセッションを出なければなりませんでした。こうしたエクスペリエンスを改善するため、このたび、Alexaスキルに直接タイマー機能を追加する機能を導入しました。この機能は、Alexaがサポートするすべてのロケールで利用できます。
このブログで2回にわたって詳しく紹介していきますが、第1回では、ユーザーの許可を取得する方法、そして許可の取得後にTimer APIを呼び出す方法を説明します。
注: このチュートリアルのサンプルコードはすべて、Node.js ASK SDKを使って作成しています。
タイマーを作成するには、明示的にユーザーの許可をとる必要があります。Alexaサービスは、スキルごとにタイマーを使用する権限を提供します。ユーザーがスキルにタイマー作成のアクセス権限を付与していない場合、スキルでユーザーにアクセス権限の付与方法を説明し、Alexaアプリにスキルのアクセス権限ページへのリンクを記載したホームカードを送信してください。
タイマーを作成するこれら2つの権限セットを取得するには、2つの方法があります。
Alexaアプリで権限カードを送信する方法
const {responseBuilder} = handlerInput;
const consentToken = requestEnvelope.context.System.apiAccessToken;
if(!consentToken){
return responseBuilder
.withAskForPermissionsConsentCard(“alexa::alerts:timers:skill:readwrite”)
.getResponse();
}
Alexaアプリに表示される権限カードの例
音声で権限リクエストを送信する方法
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ディレクティブが送信されるので、スキルはユーザーに代わってタイマーの作成を続行できます。
{
"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スキルを応答した後に終了します。
{
"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スキルを応答した後に終了します。
{
"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"
}
}
タイマーを作成するには、セッション内アクセストークンを使ってAPIエンドポイントの(POST)呼び出しを行う必要があります。スキルでは、簡単な通知をしたり、お知らせを提供したり、タスクを起動したりするためにタイマーをトリガーできます。
なお、スキルセッション外でタイマーを作成することはできません。またタイマーを作成する際にはセッション内アクセストークンを使う必要があります。
注: トリガー時刻はリクエストを受信した時点の時刻に基づいて計算され、タイマーラベルはリクエストごとに一意である必要があります。
以下の例では、10分間の"ANNOUNCE"タイマーの後、「ではストレッチを止めてランニングを始めましょう」というメッセージをユーザーに伝えるTimer APIを呼び出しています。
タイマーを作成する際のPOST API呼び出し例
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呼び出しのコードを一から作成する必要はありません。
サンプルコード
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();
}
}
タイマーの時間になったらカスタムタスクを起動することもできます。ただし、この機能は現在開発者プレビュー段階のため、ご希望の方はこちらからご登録ください。