もっとGoogle Homeで作ったスマートホームを自慢したい男たち

こちらは RCC OBOG Advent Calendar 2017 - Adventar の9日目の記事です。

前日は irgaly さんの KotlinなAndroidプロジェクトがBreakpointで止められない問題 - Qiita でした。

まずは前置き

GoogleHomeのこと書こうとしたら5日目、PG_nokkii大先輩の Google Homeで作ったスマートホームを自慢したい男たち - Qiita に完全に先を取られたので、なんとかして差分を作るか別のことを書こうと思ったのですが、まあ物事には限度ってやつがあるので当初の予定通りGoogle Homeの話を書きます。

Google Homeって?

昨今話題のスマートスピーカーの一種です。Googleが開発し販売しています。内部にはGoogle Assistantが搭載されており、これ自体はAndroidでも利用可能なものです。 GoogleHomeにはユーザインターフェースとして画面は搭載されておらず、マイクとスピーカーでしかユーザとのコミュニケーションが取れません。 VUI(Voice User Interface)としての色が濃く、表示できる情報量、ユーザからのインプット手法が普段のアプリケーションとは大きく違います。 このあたりの特色についてはこちらの資料 https://docs.google.com/presentation/d/14EO9b9DitmtZ1SGTA1-9L6M7XkU4Pv0FgMgxvhgN6G8/htmlpresent が大変参考になるのでぜひご覧になってください。

何をしたか

今回はGoogleHomeに「テレビつけて」というとFireTVが起動し、「テレビ消して」というとFireTVがオフになる仕組みを作りました。

まずはシステム全体図がこちら。

全体像

f:id:programmerMOT:20171209134745p:plain

全体像はGoogleHomeからスタートしていますが、逆のテレビをつける仕組みから説明したほうが簡単なのでそちらから順に説明します。

仕組み

テレビの操作

テレビと言っていますが裏はFireTVです。FireTVがHDMIスイッチャーを介してモニタに接続されています。 まずFireTVのon/off制御ですが以下のPythonスクリプトを利用します。

github.com

こちらは読んで字のごとく、PythonからFireTVを操作できるすごいやつです。 内部の仕組みとしてはすごい力技で見どころです。 そもそもFireTVは内部的にはAndroidで動いています。Androidにはadbというデバッグツールがありますが、 このデバッグツールはネットワーク越しにアドレスとポートを指定してホームボタンイベントを発行したり、戻るボタンイベントを発行させることができます。 そうですね、adbでFireTVを叩いてやればネットワーク越しに操作が可能ということになりますね。

さて取り出したるはGoogle謹製のPythonのみで書かれたadbコマンド実装

github.com

こいつを操作するためのサーバサイド実装がpython-firetvです。これであとはcurlを叩けばFireTVが操作できるようになるっていう寸法です。

HDMIスイッチャーの操作

さてHDMIスイッチャーも操作する必要があるのですがそれはこちらを使います。

iBUFFALO HDMI切替器 3台用 リモコン付  Nintendo Switch動作確認済 ブラック BSAK302

iBUFFALO HDMI切替器 3台用 リモコン付 Nintendo Switch動作確認済 ブラック BSAK302

このスイッチャーは赤外線に対応していますのでささっとラズパイに赤外線LEDをつけて叩くようにしましょう。 参考にしたサイトがリンク切れで死んでいてキャッシュしかみつからなかったのでとりあえずこれで勘弁してください。

Raspbian Jessie 2017-07最終版で LIRCを使って学習リモコン、赤外線リモコンを送受信する方法 (ラズパイ3で赤外線受信センサと赤外線 LEDで IrDAリモコン信号を送受信して家電等の外部機器を制御する方法)

これは後日改めて自分でまとめたいと思います。

FireTVAPIを叩き、赤外線飛ばしてくれるHubotくん

さてあとはFireTV APIを叩いて赤外線を飛ばせば良いんですが、毎回ログインしたりするのは面倒なので、Hubotにやらせてslack越しに触らせましょう。 Hubotのコードは以下

github.com

実際のコードはここ、https://github.com/pgmot/bot/blob/master/src/scripts/remote_control.js 非常にシンプルでコマンドに合わせて irsendcurl を叩いているだけです。簡単。

f:id:programmerMOT:20171209142655p:plain

このようにコマンドに合わせて動いてくれました。

GoogleHomeからコマンド発行をする

さてあとは簡単な話です。GoogleHomeの入力をどうやって受け取るかというとIFTTTを利用します。 IFTTTにはGoogle Assistantとの連携機能が実装されていますのでこれを使います。 IFTTTはSlackにPostする機能もあるのでこれを組み合わせればGoogleHomeからSlackを操作してbot操作が可能になります。

IFTTTでは4つの種類の処理が可能です。

f:id:programmerMOT:20171209135943p:plain

  • Say a simple phrase: 特定の文字列に反応します
  • Say a phrase with a number: 特定の数値に反応し、後続の処理に数値を引き渡せます
  • Say a phrase with a text ingredient: 特定の文字列に反応し、後続の処理に文字列を引き渡せます
  • Say a phrase with both a number and a text ingredient: numberとtextの組み合わせができます

今回はつけるか消すかなので、Say a simple phraseを利用します。

f:id:programmerMOT:20171209140257p:plain

ひとつの連携に3つまでのフレーズが登録可能です。適宜設定しましょう。

あとは「テレビつけて」というフレーズが来たら、Slackに「tv on」と通知すれば、Hubotが読み取ってHDMIスイッチャーの操作とFireTVの操作をしてくれるようになりました。 やったー

問題点にぶつかる

これは問題点っていうほどではないんですけど、これを連携させるとSlackが大変なことになりました。

f:id:programmerMOT:20171209143159p:plain

画像中ではエアコンの操作をしていますが、これをgeneralでガンガンされると不要な通知がガンガン来まくって最悪になります。 そこでbot専用部屋を作って対応しました。ボット部屋にはマスターであるところの自分を入れないことで通知が来なくなり快適になりました。 というかなんですか、ボットたちが裏でよしなに連携取り合ってるっていうシチュエーション良くないですか???ありえんよさみが深い、、、、

Google Homeを喋らせる

さてGoogle Homeなかなかいいおもちゃでしたが、1つ問題点があります。 それはGoogle Homeから喋らせることができないのです。基本的にはOk Googleから始めることしかできないので、たとえば何らかの通知をさせたいといったことはできません。 はて困ったと色々調べていると便利なソフトを見つけました。

github.com

こちらGoogle Homeを喋らせるnodeのライブラリです。今日久々に調べたら導入してみた系記事がいくつかあったのでそちらを参考にすると良いでしょう。 仕組みはこちらも力技で、まずテキストをGoogle TTS(Text to Speech)でmp4に変換してその音源をChromecastの要領でGoogle Homeにぶん投げるという実装がなされています。なので微妙に声が違います。 こちらの実装はbot中ではこちらにあります。https://github.com/pgmot/bot/blob/master/src/scripts/google-home-notifier.js

こちら実際に喋って便利かなと思い、たとえばリプライを通知しよう!となって実装しようとしたところで、ちょっとまて、絶対それ深夜にリプライ飛ばしてくる異常者が発生するやろこれアカンやつやとなりましたので実は特に通知部分の実装をしていません。

この問題の回避にはユーザの状況を認識して適切なタイミングで通知するような仕組みが必要で、まずユーザのコンテキスト認識する研究を引っ張ってきてだな、スマートフォンを用いた、ウェアラブルバイスが普及し、、行動認識技術が、、、加速度センサ、、、、ウッ頭が、、、、、、

まあマジレスすると部屋の電気がついてるかどうかを取ればいいと思います。ついてたら家にいて起きてるときなので。

その他問題点

  • GoogleHomeには予約語が設定されているので予約語は命令に使えない

これはなかなか致命的で、しかも後からアップデートで予約語が増えたりします。実際にテレビ消してコマンドが乗っ取られた。

  • Actions on Google/Dialogflowだと最初に「○○(アプリ名)につなげて」の準備コマンドが必要になる

これ毎回いうの絶対マヌケなのでなんとかしてほしい、IFTTTはそういう準備コマンドがいらないので最高

  • IFTTTで登録できる文言数が少ない

反対にIFTTTは登録できる文言数が3つまでしかなく、いろいろなパターンを一括で登録みたいな機能もないのでコマンド追加は地獄のように大変。IFTTTは今すぐAPIを提供してほしい。

まとめ

まあいいおもちゃだし、今なんか安いから今のうちに買っとけ