【Ruby】Googleカレンダーに服薬記録をつけるAlexaスキル作ってみた


背景

最近買ったEcho Show 5で、頓服薬の服薬記録をつけられたら便利だなと思ったことがきっかけです。

  • 既存の服薬記録系Alexaスキルだと、Echo Showやスマホの画面で記録を確認することが難しそう
  • スマホからの記録の表示や変更・削除はできるだけ楽に実現したい(できれば開発したくない)ので、記録をGoogleカレンダーに予定として入れたい
  • 利用者(家族)が使いやすいよう、できるだけシンプルな操作で記録をつけたい
  • Alexaのデフォルトカレンダーとして設定しているGoogleカレンダーと、服薬記録用のGoogleカレンダーを別IDに分けたい

という理由で、自分でスキルを作ることにしました。

概要

スキルを呼び出すと、話しかけた内容によって下記3つの挙動をします。

  1. 「アレクサ、[スキル名]を開いて、記録をつけて」
    →Googleカレンダー上に、現在時刻〜5分後の予定(=服薬記録)を作る
  2. 「アレクサ、[スキル名]を開いて、記録を見せて」
    →画面に当日の服薬記録を表示する
  3. 「アレクサ、[スキル名]を開いて」
    →利用方法の案内を表示する

構成図

用意したもの

  • Ruby 2.7.3の動作環境

作り方(概要)

大まかに下記の流れで作りました。

  1. Google Cloud Platformでサービスアカウントと秘密鍵を作成する
  2. 連携先のGoogleカレンダーをサービスアカウントに共有する
  3. Alexa開発者アカウントを作る
  4. Alexaスキルを作る
  5. Rubyコードを書く
  6. Lambda関数を作る
  7. AlexaスキルとLambda関数を連携する

基本的には既存記事の組み合わせなので、各工程の詳細手順は省略します。
下記記事を参考にさせていただきました。

【Ruby】Googleカレンダーから予定を取得してSlack通知を飛ばしてみる
→ 下記1, 2, 5, 6の手順で参考にさせていただきました。
 1.Google Cloud Platformでサービスアカウントと秘密鍵を作成する
 2.連携先のGoogleカレンダーをサービスアカウントに共有する
 5.Rubyコードを書く
 6.Lambda関数を作る

【PHP】Laravelを使ってGoogleドライブにファイルをアップロードしてみる
→ 1.Google Cloud Platformでサービスアカウントと秘密鍵を作成する の手順で参考にさせていただきました。

Google Calendar APIで予定のCRUD操作を行う
→ 5. Rubyコードを書く の手順で参考にさせていただきました。

Alexa 開発者アカウントのハマりどころ
→ 3. Alexa開発者アカウントを作る の手順で参考にさせていただきました。

失敗しないAlexa開発者アカウントの作り方
→ 3. Alexa開発者アカウントを作る の手順で参考にさせていただきました。

AlexaスキルをPython/Lambdaで実装する
→ 下記4, 6, 7の手順で参考にさせていただきました。
4. Alexaスキルを作る
6. Lambda関数を作る
7. AlexaスキルとLambda関数を連携する

作り方(補足)

Alexaスキルについて

オリジナルの部分のスクショを載せておきます。

Rubyコードについて

下記の処理をオリジナルで追加しています。

  • インテントによって処理を分岐させる
  • Echo Showの画面に出したい文字をレスポンスのJSONに含める

該当の部分のみ下記に抜粋します。

app.rb
def build_response(text, card_title=nil, card_content=nil)
  output_speech = {
    'type' => 'PlainText',
    'text' => text
  }
  
  if card_content
    card = {
      'type' => 'Simple',
      'title' => card_title,
      'content' => card_content
    }
    
    data = {
      'version' => '1.0',
      'response' => {
        'outputSpeech' => output_speech,
        'card' => card,
        'shouldEndSession' => true
      }
    }
    
  else
    data = {
      'version' => '1.0',
      'response' => {
        'outputSpeech' => output_speech,
        'shouldEndSession' => true
      }
    }
  end
  
  data
end


def handler(event:, context:)
  if event["request"]["type"] == "IntentRequest" && event["request"]["intent"]["name"] == "ShowRecordsIntent"
    #下記は当日の予定を取得する関数。戻り値はbuild_response("今日のお薬記録です。", "今日のお薬記録", 予定一覧の文字列)
    get_medicine_log
  elsif event["request"]["type"] == "IntentRequest" && event["request"]["intent"]["name"] == "InsertRecordIntent"
    #下記は現在時刻の予定を追加する関数。戻り値はbuild_response('記録をつけました。')
    create_medicine_log
  else
    text = "記録をつけたい時は、「お薬ノートを開いて、記録をつけて」と話してください。今日の記録を見たい時は、「お薬ノートを開いて、記録を見せて」と話してください。"
    card_title = "コマンド一覧"
    card_content = "1.お薬ノートを開いて、記録をつけて\n2.お薬ノートを開いて、記録を見せて"
    build_response(text, card_title, card_content)
  end
end

動作確認

Echo Show 5に「お薬ノート(スキル名)を開いて、記録をつけて」と話しかけたところ、無事にGoogleカレンダー上へ予定が追加されました。

また、「記録を見せて」での予定取得とEcho Show側での画面表示も問題なく動いています。

余談

Echo Showを購入して以来、介護生活の色々な場面でAlexaに助けられています。いつもありがとうAlexa。
12時間ごとに飲む薬もAlexaにリマインドしてもらっている他、見守りカメラや緊急時のナースコールとして使えたり、家族が歩けない時もスマートホーム化によって声だけで家電が操作できたりと色々便利です。
何より、誰でも直観的に使える点がありがたいなと思います。