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

Anand Kumar Oct 27, 2021
Share:
Build Alexa-Hosted Skills
Blog_Header_Post_Img

第1回では、音声による権限付与を使い、Timer APIを呼び出してAlexaスキルでタイマーをセットする方法をご紹介しました。第2回では、読み取り、一時停止、再開、削除などのTimer APIで行う操作をご紹介します。

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

特定のタイマー情報を得る方法

読み取りの操作を実行するには、スキルで権限を有効にする必要があります。スキルがTimer APIを使ってタイマーを作成するたびに、一意の「ID」がスキルへの応答に返されます。この「ID」は、Alexaデバイスでセットされた特定のタイマーを識別するのに使用します。

以後、この「ID」は読み取り、削除、一時停止、再開のすべての操作に使います。

以下は、読み取りのTimer APIを呼び出すサンプルリクエストです。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

このAPI呼び出しは次に応答を返します。応答には、タイマーのid、status、duration、triggerTime、createdTime、updatedTimeが含まれます。

応答の例

Copied to clipboard
{ 
    "id": "a3aac326-c504-458b-8520-15fd048f086a",
    "status": "ON",
    "duration": "PT10M",
    "triggerTime": "2021-08-13T10:25:30Z",
    "createdTime": "2021-08-13T10:15:30Z",
    "updatedTime": "2021-08-13T10:15:30Z" 
}

作成されたタイマーが以前に一時停止されていた場合、「remainingTimeWhenPaused」プロパティが応答に追加されます。以下は、残り時間が3分3秒のタイマーの例です。

Copied to clipboard
{ 
      "id": "a3aac326-c504-458b-8520-15fd048f086a",
      "status": "PAUSED",
      "duration": "PT5M",
      "timerLabel": "ピザ",
      "createdTime": "2019-12-03T10:15:30Z",
      "updatedTime": "2019-12-03T10:12:03Z",
      "remainingTimeWhenPaused": "PT3M3S" 
}

すべてのタイマーを読み取る方法

指定したユーザーのタイマーを取得します。スキル内で作成されたタイマーはAlexaアカウントに登録されたすべてのデバイスに表示されます。返される際、設定時間が最短のものから最長のものの順に並べられます。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

このAPIは、スキルを通してこのユーザーが作成したすべてのタイマーの詳細を返します。

以下は、あるタイマーがアクティブで別のタイマーが一時停止されている場合の応答例です。

Copied to clipboard
{ 
    "timers": [ 
        { 
            "id": "a3aac326-c504-458b-8520-15fd048f086a",
            "status": "ON",
            "duration": "PT10M",
            "triggerTime": "2019-12-03T10:25:30Z",
            "createdTime": "2019-12-03T10:15:30Z",
            "updatedTime": "2019-12-03T10:15:30Z",
        },
        { 
            "id": "a3aac326-c504-458b-8520-15fd048f086a",
            "status": "PAUSED",
            "duration": "PT5M",
            "timerLabel": "ピザ",
            "createdTime": "2019-12-03T10:15:30Z",
            "updatedTime": "2019-12-03T10:12:03Z",
            "remainingTimeWhenPaused": "PT3M3S" 
        } 
    ],
    "totalCount": 2,
    "nextToken": null 
}

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

Copied to clipboard
async handle(handlerInput) {
    const {serviceClientFactory} = handlerInput;
    try {
        const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
        // getTimers()で作成されたすべてのタイマーのリストを取得します。
        const timersList = await timerServiceClient.getTimers();
        console.log('タイマーの読み取り:' + JSON.stringify(timersList));
        const totalCount = timersList.totalCount;
        if(timerId || totalCount > 0) {
            timerId = timerId ? timerId : timersList.timers[0].id; 
            // getTimer(timerId)は、"timerId"で指定された"id"に従って特定のタイマーの詳細を取得します。
            let timerResponse = await timerServiceClient.getTimer(timerId);       
            console.log('タイマーの読み取り:' + JSON.stringify(timerResponse));
            const timerStatus = timerResponse.status;
            return handlerInput.responseBuilder
                .speak("タイマーの読み取り操作が完了しました")
                .getResponse();
        } else {
            return handlerInput.responseBuilder
                .speak("作成されたタイマーはありません")
                .getResponse();
        }
    } catch (error) {
        console.log('タイマーの読み取りエラー' + JSON.stringify(error));
        // エラーコードが401の場合、音声による権限付与をユーザーに送信してタイマーの権限を付与します。
        if(error.statusCode === 401) {
            console.log('権限がありません');
            // 音声で有効にするリクエストを送信します
            // 結果を処理する別のハンドラーが必要です。AskForResponseHandlerを参照してください
            return handlerInput.responseBuilder
                .addDirective({
                type: 'Connections.SendRequest',
                'name': 'AskFor',
                'payload': {
                    '@type': 'AskForPermissionsConsentRequest',
                    '@version': '1',
                    'permissionScope': TIMERS_PERMISSION
                },
                token: 'verifier'
            }).getResponse();
        }
        else
            return handlerInput.responseBuilder
                        .speak("タイマーがセットされていません。「タイマーをセットして」と言ってみてください。")
                        .getResponse();
    }
}

指定したタイマーを削除する方法

このAPIを呼び出すと、現在のデバイスの特定のタイマーを削除できます。「id」は特定のタイマーを識別する一意の識別子です。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

すべてのタイマーを削除する方法

このAPIを呼び出すと、ユーザーが作成したすべてのタイマーを削除できます。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

ここでASK SDKを使って、以下のように削除操作を作成することもできます。

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

    try {
        const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
        const timersList = await timerServiceClient.getTimers();
        console.log('タイマーの読み取り:' + JSON.stringify(timersList));
        const totalCount = timersList.totalCount;
        if(totalCount === 0) {
            return handlerInput.responseBuilder
                .speak("作成されたタイマーはありません。")
                .getResponse();
        }
            // キャンセルするタイマーIDがない場合の警告です
            await timerServiceClient.deleteTimers();
        
        console.log('タイマーを削除しました');
        return handlerInput.responseBuilder
            .speak("作成したすべてのタイマーを削除しました")
            .getResponse();
    } catch (error) {
        console.log('タイマーの削除エラー:' + JSON.stringify(error));
        if(error.statusCode === 401) {
            console.log('権限がありません');
            // 音声で有効にするリクエストを送信します
            // 結果を処理する別のハンドラーが必要です。AskForResponseHandlerを参照してください
            return handlerInput.responseBuilder
                .addDirective({
                type: 'Connections.SendRequest',
                'name': 'AskFor',
                'payload': {
                    '@type': 'AskForPermissionsConsentRequest',
                    '@version': '1',
                    'permissionScope': TIMERS_PERMISSION
                },
                token: 'verifier'
            }).getResponse();
        }
        else
            return handlerInput.responseBuilder
                .speak("削除操作の実行中に問題が発生しました")
                .getResponse();
    }
}

指定したタイマーを一時停止する方法

セットされていてまだ鳴動していないタイマーのみを一時停止できます。タイマーは停止し、残り時間が保存されます。たとえば、45分後に鳴動するタイマーを一時停止すると、そのタイマーは再開した時点から45分後に鳴動します。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

以下は、ASK SDKを使って特定のタイマーの一時停止操作を行うサンプルコードです。

Copied to clipboard
async handle(handlerInput) {
        const {serviceClientFactory} = handlerInput;
        
        try {
            const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
            const timersList = await timerServiceClient.getTimers();
            console.log('タイマーの読み取り:' + JSON.stringify(timersList));
            const totalCount = timersList.totalCount;

            if(totalCount === 0) {
                return handlerInput.responseBuilder
                    .speak("作成されたタイマーはありません。")
                    .getResponse();
            }
            // すべてのタイマーを一時停止します
            for(const timer of timersList.timers ) {
                if(timer.status === 'ON'){
    // これにより“timer.id”で指定された特定のタイマーが一時停止します。
                    await timerServiceClient.pauseTimer(timer.id);
                }
            };
            return handlerInput.responseBuilder
                .speak("タイマーが一時停止されました。")
                .getResponse();
        } catch (error) {
            console.log('タイマーの一時停止エラー:' + JSON.stringify(error));
            if(error.statusCode === 401) {
                console.log('権限がありません');
                // 音声で有効にするリクエストを送信します
                // 結果を処理する別のハンドラーが必要です。AskForResponseHandlerを参照してください
                return handlerInput.responseBuilder
                    .addDirective({
                    type: 'Connections.SendRequest',
                    'name': 'AskFor',
                    'payload': {
                        '@type': 'AskForPermissionsConsentRequest',
                        '@version': '1',
                        'permissionScope': TIMERS_PERMISSION
                    },
                    token: 'verifier'
                }).getResponse();
            }
            else
                return handlerInput.responseBuilder
                    .speak("タイマーの一時停止中に問題が発生しました。")
                    .getResponse();
        }
    }

指定したタイマーを再開する方法

このAPIを使うと、一時停止したタイマーを再開できます。タイマーが再開されると、一時停止または停止されない限り、残り時間の経過後に鳴動します。

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

このAPIの呼び出しにリクエスト本文は必要ありません。

以下は、ASK SDKを使って再開操作を行うサンプルコードです。

Copied to clipboard
async handle(handlerInput) {
        const {serviceClientFactory} = handlerInput;
        
        try {
            const timerServiceClient = serviceClientFactory.getTimerManagementServiceClient();
            const timersList = await timerServiceClient.getTimers();
            console.log('タイマーの読み取り:' + JSON.stringify(timersList));
            const totalCount = timersList.totalCount;

            if(totalCount === 0) {
                return handlerInput.responseBuilder
                    .speak("作成されたタイマーはありません。")
                    .getResponse();
            }
            // すべてのタイマーを再開します
            for(const timer of timersList.timers ) {
                if(timer.status === 'PAUSED'){
                // これにより一時停止されていたタイマーが再開します。
                    await timerServiceClient.resumeTimer(timer.id);
                }
            };
            return handlerInput.responseBuilder
                .speak("タイマーが正常に再開されました。")
                .getResponse();
        } catch (error) {
            console.log('タイマーの再開エラー:' + JSON.stringify(error));
            if(error.statusCode === 401) {
                console.log('権限がありません');
                // 音声で有効にするリクエストを送信します
                // 結果を処理する別のハンドラーが必要です。AskForResponseHandlerを参照してください
                return handlerInput.responseBuilder
                    .addDirective({
                    type: 'Connections.SendRequest',
                    'name': 'AskFor',
                    'payload': {
                        '@type': 'AskForPermissionsConsentRequest',
                        '@version': '1',
                        'permissionScope': TIMERS_PERMISSION
                    },
                    token: 'verifier'
                }).getResponse();
            }
            else
                return handlerInput.responseBuilder
                    .speak("タイマーの再開操作中に問題が発生しました。")
                    .getResponse();
        }
    }

まとめ

このブログでは、Timer APIで実行できる操作を紹介しました。また、ASK SDKを活用してこのAPIを呼び出し、ユーザーが便利に使えるタイマースキルを作成する方法も説明しました。このブログの内容についてご不明な点がありましたら、こちらの技術資料をご覧ください。

関連記事

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

Subscribe