LoginSignup
1

posted at

おいしいコーヒーの淹れ方を教えてくれるAlexaスキルの作成に失敗した

やりたかったこと

いつもコーヒーをタイマー付きのスケールを使って時間と湯量と計りながらコーヒーのドリップをしていたのですが、ぼーっとしているとお湯を注ぎそびれたり、どれくらいお湯を注ごうかなと迷ってしまったり。スケールさえあれば美味しいコーヒーが淹れられたら素敵だなあとおもったのが動機です。
Bespoke Coffee Roastersの畠山さんの基本レシピを使用させていただきました。(ご本人に許可をいただきました)

スキルの概要

  1. スキルを発動する
  2. 準備ができたらタイマーを作成・開始する
    • 1湯目 0:00 「30ccまでお湯を注いでください」
    • 2湯目 0:30 「120ccまでお湯を注いでください」
    • 3湯目 1:00 「150ccまでお湯を注いでください」
    • 4湯目 1:20 「190ccまでお湯を注いでください」
    • 5湯目 1:40 「230ccまでお湯を注いでください」
    • 2:20 落とし切りで終了、「コーヒータイムを楽しんでください!」

失敗している箇所

Androidアプリのアレクサでは問題なかったのですが、公開してEcho showで試したところ、制御不能となり本体の電源を切る羽目となりました。

  • 想定外のタイマーの終了音が鳴ってしまう
  • タイマーをキャンセルしてもタイマーの画面が閉じられない
  • 作成されたタイマーを全てキャンセルしても、タイマーの終了音が止められない

Alexaスキルの開発の始め方

2つのサービスのアカウントが必要です。

  • Amazon開発者アカウント
  • AWSアカウント

スキルの開発

公開されているサンプルコードを使って開発をはじめました。
https://github.com/alexa-samples/skill-sample-python-helloworld-classes/tree/master/lambda/py

コーヒーを淹れる準備ができた時のインデントハンドラー

  1. タイマーの制御権限を許可してもらう
  2. 時間差をつけてタイマーを作成・開始する
  3. 応答を返す
class LetsCoffeeTimeIntentHandler(AbstractRequestHandler):

    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return ask_utils.is_intent_name("LetsCoffeeTimeIntent")(handler_input)

    def handle(self, handler_input):

        accessToken = ask_utils.get_api_access_token(handler_input)
        rb = handler_input.response_builder
        request_envelope = handler_input.request_envelope
        permissions = request_envelope.context.system.user.permissions
        if not (permissions and permissions.consent_token):
            print("user hasn't granted reminder permissions")
            res = (
                rb
                .add_directive(
                    SendRequestDirective(
                        name="AskFor",
                        payload={
                            "@type": "AskForPermissionsConsentRequest",
                            "@version": "1",
                            "permissionScope": "alexa::alerts:timers:skill:readwrite",
                        },
                        token=""
                    )
                )
                .response
            )
            print(res)
            return res
        else: 
            get_custom_task_launch_timer(accessToken, "PT30S", "2湯目", "お湯を120ccまでそそいでください")
            get_custom_task_launch_timer(accessToken, "PT60S", "3湯目", "お湯を150ccまでそそいでください")
            get_custom_task_launch_timer(accessToken, "PT80S", "4湯目", "お湯を190ccまでそそいでください")
            get_custom_task_launch_timer(accessToken, "PT100S", "5湯目", "お湯を230ccまでそそいでください。注いだ後は、お湯が落とし切れるまで待ちましょう。")
            get_custom_task_launch_timer(accessToken, "PT140S", "落とし切ります", "できあがりです!コーヒータイムをたのしんでください!")
            return (
                handler_input.response_builder
                .speak("タイマーを開始しました。お湯を30cc注いでください").response
            )

タイマーを作成する関数

def get_custom_task_launch_timer(accessToken, duration, timerLabel, textToAnnounce):
    options = {"Authorization": "Bearer " + accessToken,"Content-Type": "application/json"}
    timer = { "duration": duration, "timerLabel": timerLabel, "creationBehavior": { "displayExperience": { "visibility": "VISIBLE" } }, "triggeringBehavior": { "operation": { "type": "ANNOUNCE", "textToAnnounce": [ { "locale": "ja-JP", "text": textToAnnounce } ] }, "notificationConfig": { "playAudible": False } } }
    res = requests.post("https://api.fe.amazonalexa.com/v1/alerts/timers", data=json.dumps(timer), headers=options)
  • タイマーの終了音をミュートにする
    playAudibleにFalseを設定することでミュートにすることができました。(AndroidのAlexaアプリ上では無音になりました…)
  • タイマーのAPIのリクエスト先
    タイマーのAPIは、日本の場合「api.fe.amazonalexa.com/v1/alerts/timers」であることに気づかずなかなか苦戦しました。
    https://developer.amazon.com/ja-JP/docs/alexa/smapi/alexa-timers-api-reference.html#create-timer

次回

タイマーをキャンセルしてもキャンセルできない挙動の解決
Echo Showでも安定した挙動を確認する
スキルを公開する

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
What you can do with signing up
1