Google Homeとobnizで部屋の電気をON/OFFする

2019年2月16日 追記 package.jsonを追記しました。

2018年12月29日 追記
obniz単体だとエンドポイントを作れないと思っていたので、RunKitでエンドポイントを作っていたのですが、実際はobniz単体でも、Event機能でWebhookを選択すればエンドポイントを作れました。失礼しました。訂正します。


この記事はobniz Advent Calendar 2018 10日目の記事です。

obnizとサーボモータで部屋の電気をON/OFFできるようにして、Google Homeから音声操作できるようにしました。 まずは動画をご覧ください。スマート電球を使わず物理的にスイッチを叩いて電気をON/OFFしている様子がお分りいただけると思います。(カメラのライトをつけているので明るさはあまり変わってませんが。)


Google Homeとobnizで部屋の電気をON/OFFする

私はこれまで電子工作もVUIアプリ開発もほとんど経験がなかったのですが、obnizのハンズオンに参加して「こりゃ簡単すぎて自分でも何か作らなきゃ嘘だぜ」と思ってこのアプリを作りました。
電子工作、VUIアプリ開発の双方でたくさん学びがあったので、この記事では実施した内容とそこで得たノウハウを順を追って書いていきます。この記事が、私のような初心者の方の参考になれば幸いです。
記事は「1. 準備編」「2. 実装編」「3. 運用編」の3部構成です。

1. 準備編

今回使ったものはGoogle Home mini, obniz, サーボモータ, スイッチカバーです。

1-1. obnizとサーボモータの接続

アプリ開発の第一歩。張り切ってobnizとサーボモータを接続しよう!としたところ、接続部分が受け口と受け口で付けられませんでした。

f:id:sonomirai:20181201221004j:plain:w300
受け口と受け口!

変換用の部品が存在することは知っていたのですが、名前が分からずネットで注文できなかったので、サーボモータ側のコードを切ってねじってobnizに差し込んで動かしました。その後、変換用部品は「ピンヘッダ」という名前であると知りました。

f:id:sonomirai:20181208104645p:plain
ピンヘッダ

1-2. スイッチカバーへのサーボモータの取り付け

元々のスイッチカバーは丸みを帯びていてサーボモータを固定しづらそう&部屋のもの傷つけるのが嫌だったので、サーボモータの取り付け方で迷いました。
ヒントを求めて向かったホームセンターで、サーボモータを固定しやすそうな角ばったスイッチカバーが80円で売っていたので、それを買ってサーボモータをアロンアルファで固定して、元のスイッチカバーと付け替えました。特に問題なく付け替えられて一安心。

f:id:sonomirai:20181208104708j:plain:w400
左が元々のスイッチカバーで右が今回のスイッチカバー

これで準備は終わりです。

2. 実装編

実装は以下のように段階的に進めました。【】内はざっくりとした作業カテゴリです。
1.【IoT化】obnizのWeb画面からサーボモータを動かす
2.【API化】RunKitからサーボモータを動かす
3.【VUI化】音声でRunKitを叩いてサーボモータを動かす
4.【UI改善】Google Home周りのユーザビリティを上げる

実装の流れをざっくりと概念図で示すと下記の通りです。

f:id:sonomirai:20181201223245p:plain
実装の流れ

2-1.【IoT化】obnizのWeb画面からサーボモータを動かす

ハンズオンやパーツライブラリのサンプルコードを参考に、obnizのWeb画面でこちらのプログラムを作成しました。実行画面は以下の通りで、ボタンをタップすると電気が点灯/消灯します。

f:id:sonomirai:20181201225140p:plain:w200
実行画面

2-2.【API化】RunKitからサーボモータを動かす

次にこれをGoogle Homeから実行しようとしたところで、obnizのクラウドシステムには外部からプログラムを叩くためのエンドポイントを作成する機能がないので、別のサービスを使う必要があることに気付きました。
[訂正]上記は間違いで、obnizのEvent機能でWebhookを選択すればエンドポイントを作成することができました。
AWSのLambdaなどのサービスを使う必要がある?と思いつつググっていたところ、RunKitというサービスでエンドポイントを作っている資料があったので、とりあえずRunKitを使ってみることにしました。
RunKitはとても便利で、作成したコードを叩くためのエンドポイントを勝手に作成してくれます。
点灯用のコードと消灯用のコードを分けて作成しました。点灯用のコードはこちらです。

curlでRunKitのエンドポイントを叩くと、電気が点灯/消灯されるところまで確認しました。

2-3.【VUI化】音声でRunKitを叩いてサーボモータを動かす

点灯/消灯のエンドポイントを準備できたので、次は音声操作でエンドポイントを叩けるようGoogle Homeの設定をします。
Google Homeでのアプリ開発ではGoogleアシスタント, Action on Google, Dialogflowといった複数のツールが出てきますが、詳細は割愛します。WEB+DB PRESS Vol.105のスマートスピーカの記事が分かりやすかったです。

今回は以下の通り設定しました。

  1. Action on Googleのプロジェクト名を設定する
  2. DialogflowのIntentsでFulfillmentを有効化する
  3. IntentsとFulfillmentの関数を紐付ける

2-3-1. Action on Googleのプロジェクト名を設定する

VUIアプリ開発にあたり、まず最初にAction on Googleのプロジェクトを以下のどちらで作るか迷いました。

  1. 点灯用と消灯用でプロジェクトを分けてそれぞれのDefault Welcome Intentで処理をする
  2. プロジェクトは1つにして、Intentによって点灯と消灯の処理を分ける

前者だとプロジェクト名のみの発話でいいので、「OK Google, 電気つけて」「OK Google, 電気消して」という短い発話で操作ができます。
ただ発話毎にプロジェクトを分けるのは流石にイケてなさそうと言う気がしました。
いっぽう後者は、例えばプロジェクト名を「ルームライト」とした場合、「OK Google, ルームライト」と発話して、Google Homeの応答を待ってから、「電気消して」と発話することになるので、かなり使いづらそうだと悩みました。
そこでヒントを求めて読んだWEB+DB PRESS Vol.105Google Homeの記事に「プロジェクト名を使ってフレーズ名」という発話ができると書いてあって、コレだ!と思いました。これなら少し発話は長くなりますが、「OK Google, ルームライトを使って電気つけて」と1フレーズで操作ができるのでユーザビリティとしては許容範囲だと判断だし、後者で実装することにしました。

2-3-2. DialogflowのIntentsでFulfillmentを有効化する

Action on GoogleのActionsからDialogflowの編集画面を開いて、インテントを設定します。点灯用のインテントの設定は以下の通りです。点灯用インテントから先ほど設定したRunKitの点灯用コードを実行するため、最後の「Enable webhook call for this intent」を有効にします。

f:id:sonomirai:20181202235940p:plain:w400
点灯用インテントの設定

2-3-3. IntentsとFulfillmentの関数を紐付ける

DialogflowのFulfillmentに移動して、RunKitのエンドポイントを実行するための設定をしようとしたのですが、ここでつまづきました。感覚的に、Intentsとそれに対応するFulfillmentを1:1で紐付けするためのGUIがあるはずだと思ったのですが、Intentsの設定画面にもFulfillmentの設定画面にもそのようなGUIがなかったのです。
そこで有識者の方に伺って、IntentsとFulfillmentを紐付けするGUIはないので、そこは自分でIntentsとFulfillmentを紐付けするコードと振分けするコードを書く必要がある、と教えていただきました。(よく見るとInline Editorのサンプルコードにこの辺りのことが書いてありましたが、気づきませんでした。。。)

f:id:sonomirai:20181207215445p:plain:w500
インテントとフルフィルメントのマッピング

それではIntentsとFulfillmentを紐付けます。Fulfillmentから外部サービスを呼び出すこともできますが、今回は素直にInline Editorに紐付けのコードを書くことにしました。index.jsはこちら, package.jsonこちらです。(Inline Editorの裏ではCloud Functions for Firebaseが動くので、いくらか課金されます。)
ここまで設定してActions on GoogleのSimulatorを実行すると、「ルームライトを使って電気つけて」で電気をつけられるようになり、実運用できるようになります。

f:id:sonomirai:20181207224547p:plain:w300
Simulator実行画面

2-4.【UI改善】Google Home周りのユーザビリティを上げる

2-3までの実装で、音声で電気のON/OFFが可能になったので、実際に使い始めたのですが、使って見ると以下のような問題が発生しました。(Google Homeが認識した発話の内容はGoogle Homeアプリのマイアクティビティから確認します。)

  1. 「ルームライトを使って消灯」が「ショート」に誤認識される
  2. ルームライトを使って消灯」が「ウムラウト」に誤認識される
  3. 「ルームライトを使って消灯」をついつい「ルームライト消灯」と言ってしまう

問題3は実装の初期段階から懸念していて、気をつければ大丈夫だろうと思っていたのですが、たまに間違った発話をしてしまうことがありました。
結論から言うと問題1はDialogflowのEntitiesでフレーズ名にエイリアスをつけることで解決できました。また問題2, 3はGoogle Homeアプリのルーティンで発話にエイリアスをつけることで解決できました。それぞれ述べます。

2-4-1. DialogflowのEntitiesでフレーズ名にエイリアスをつける

問題1を解決するため、ルームライト内で「ショート」と認識したら「消灯」と捉えるようにエイリアスをつけます。この設定はDialogflowのEntitiesから以下のように設定します。

f:id:sonomirai:20181208114041p:plain:w400
Entitiesの設定

Simulatorで期待する動作をすることを確認します。

f:id:sonomirai:20181208114200p:plain:w300
Simulator実行画面

2-4-2. Google Homeアプリのルーティンで発話にエイリアスをつける

次に「ルームライト」が「ウムラウト」と誤認識される問題と「ルームライト」と言ってしまい、期待する動作を得られない問題に対処します。前述の通り、今回は「プロジェクト名を使ってフレーズ名」という発話をする想定でいます。問題1はフレーズ名の誤認識に対する対処で、これはDialogflowの設定で解決できたのですが、問題2, 3はDialogflowの世界の外の話なので、Dialogflowの設定では解決できません。
そこで有識者の方に伺ったところ、Google Homeアプリのルーティンでエイリアスを設定できると教えてもらいました。(ルーティンはエイリアスをつけるだけではなく色々なことに使える機能なのですが、説明は割愛します。)この機能はとても強力で「ルームライトを使って電気つけて」に対して「電気つけて」というエイリアスをつけることができるので、「ルームライトを使って」の発話がいらなくなり、問題2, 3が発生しないようにできるのです!(これに気付いた時はめちゃめちゃうれしかった。)

ルーティンの設定は「Google Homeアプリ>GOOGLEアシスタント>その他の設定>アシスタント>ルーティン」から行います。

f:id:sonomirai:20181208160152p:plain:w500
ルーティンの設定

これでプロジェクトの保守性を保ちながら、短い発話で操作することが可能になりました!

3. 運用編

今回作成したアプリを2週間くらい使っての感想です。

  • 就寝時に電気を消しにスイッチまで歩く必要がなくなり、便利になった。(特に最近寒いので、ベッドから出ないで済むのが有難い。)
  • 発話からサーボモータが動くまでのタイムラグ、およびGoogle Homeがしゃべり出すまでのタイムラグが気になるといえば気になりなるので、そこは今後改善したいです。
  • この記事で紹介した内容に加えて、obnizのイベント機能を使って毎朝自動で電気をつける設定もし他のですが、これが思った以上にいい感じでした。今までは目覚まし時計に叩き起こされていたので朝起きるのが辛かったのですが、今は自動で電気がついた5〜10分後に目がパッと覚める感覚になり、気持ちよく起きれるようになりました。

f:id:sonomirai:20181208161915p:plain:w300
イベント設定(時刻指定はUTC

画像の中で設定しているprivate_LightOn.htmlはこちらです。

まとめ

obnizとサーボモータで部屋の電気をON/OFFできるようにして、Google Homeから音声操作できるようにしました。またobnizのイベント機能を使って毎朝自動で電気をつける設定もしました。両方とも2週間くらいいい感じで使えているので、今後も継続して使おうと思っています。