IFTTTを使って、GoogleHomeに話しかけたら最寄りのバス停留所の時刻情報を教えてくれるようにした

私は都下に住んでおり、家からバス停が近いので、バスを使うことが多いです。

ですが、都心部よりもバスの頻度が低いし、遅れることもあるので、バス会社のリアルタイム運行情報をスクレイピングしてSlackなどと連携させて使っていたりします。

というわけで、
Google Home + IFTTT + Raspberry Pi を組み合わせた古典的なWebhook連携で、何かを聞くと、答えを発言してくれる家庭内システムを作りました。
もちろん、Raspberry Pi 側の実装次第で、発言する内容はなんでもオッケーです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66867/08e2621e-4842-caa5-146a-3dc19f7092fc.png)



# 前提

- Google Home のセットアップが完了済み
- インターネットからRaspberryPiにアクセスできる
    - インターネットに公開できない環境なら、ngrokを使ったり、何かしらのメッセージ・キューを使った実装をしてください。

# IFTTT Applet を作る

**Google Homeの発言をトリガにして、Raspberry Pi上のHTTPハンドラを叩く**までをIFTTTで行います。

## トリガを設定する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66867/4a2fc305-2f8f-a559-42a7-e2af0314c2a0.png)


**Google Assistant** の **Say a simple phrase** をトリガにします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/66867/8ac41387-a283-6d1f-4afe-0c62e33dc6e1.png)

*「おっけーグーグル、バスの時間教えて」*

キーワードは３つまで設定でき、一字一句、正しく発言しないとキャッチしてくれません。

「Google Assistant」を使うと、Google Home に呼びかけたキーワードにトリガを設定できます。IFTTTにGoogleアカウントでOAuthログインしていれば、特に追加設定は不要です。

## アクションを設定する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66867/3780f699-28c2-f105-3b34-aed2a45e19f1.png)

Webhooks の **Make a Web Request** を使います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66867/45b13718-0c12-b860-15ff-f92fd29ddca6.png)

Raspberry PiのURLを指定します。

# Raspberry Pi を準備する

## Raspberry Pi で動かすプログラムを作る

google-home-notifierというnpmパッケージを使うと簡単にテキストをGoogleHomeで再生できます。
https://github.com/noelportugal/google-home-notifier

Express使ったHTTPサーバを立てます。コードを一部だけ抜粋します。

```js
const fetchRealtimeBusInfo = /* スクレイピングを行うモジュールを別途作る */
const googlehome = require('google-home-notifier');

const speak = (message) => {
  googlehome.device('リビング', 'ja'); /* デバイス名 */
  googlehome.ip('192.168.0.xx'); /* IPアドレス */
  googlehome.accent('ja');
  googlehome.notify(message, function (res) {
    console.log(res);
  });
};

const handler = (req, res, next) => {
  fetchRealtimeBusInfo().then(function (dia) {
    if (dia.length) {
      let content = '次のバスは' + dia[0].status; /* "あと5分です。"などの文字列が入ります。 */
      if (dia.length >= 2) {
        content += '。その次は' + dia[1].status;
      }
      speak(content);
    } else {
      speak('バスはありません');
    }
  });
  res.status(200).send('OK');
};

router.post('/googlehome/bus', handler);

```

Raspberry Pi で動かす前にPCで動作確認しておくと安心でしょう。この段階で、うまくいっていれば、GoogleHomeから音が出ます。

## Raspberry Pi で動かす。

私はRaspbianの上でNode.jsを動かしています。Node.jsのインストール方法は割愛します。
依存しているNPMパッケージ`mdns`のビルドエラーが出るかもしれませんが、`libavahi-compat-libdnssd-dev` をインストールしておくことで解消します。

```bash
apt-get install libavahi-compat-libdnssd-dev
```
# google-home-notifier について

純正では、外部からのプッシュを契機にGoogle Homeでテキストを再生する方法は提供されていないので、今回はこれを使います。

`google-home-notifier` の中身はシンプルです。

どうやって GoogleHome から音を出しているのか、というと・・・、 `node-castv2-client` パッケージでやっているようです。
https://www.npmjs.com/package/castv2-client

GoogleHome は ChromeCast と同じプロトコルを使っているようなので、これで音を再生できるっぽい。
`node-castv2-client`自体は、ChromeCastに繋げば、写真を表示するなどの制御が出来るようです。

テキストを音声に変えるには、別のパッケージ `google-tts-api`  を使っています。

https://www.npmjs.com/package/google-tts-api

Google翻訳のTTS(Text To Speach) APIを叩いてmp3のURLを取得するコードで、200文字まで対応しています。
ただ、このGoogle翻訳のAPIは、非公開APIのようなので、Googleが本来意図した使い方では無い可能性もあり、いつまで使えるかはわかりませんね。

---

# 感想

現時点で、IFTTTを使った方法で会話の往復を実現するのはちょっと面倒でした。

api.ai を使う方法があるので、こっちが適しているケースもあると思います。
https://qiita.com/syarihu/items/53ea1a65f481f8121109

GoogleHomeに音声ファイルを投げるには、ローカルネットワークにサーバーを立てる必要があるのも面倒です。すでにRaspberryPiなどで家庭内サーバがお家にあれば、敷居は低いと思います。


数日使ってみましたが、「自分で設定したトリガワードを忘れる」という問題に直面して、起動できないことがしばしば・・・。
普通のGoogleHomeの感覚でいくと、多少の、曖昧な表現や語順の変化でも受け入れてもらえるのですが、IFTTTの`Say a simple phrase`では一字一句の間違いも許されないので、かなり使い勝手が悪かったです。
キーワードは3つまで設定できるものの、もっと柔軟に判断してほしい・・・。会話型インターフェースの難しさを感じました。