LINEをトリガーに家のGoogleHomeを喋らせる

# はじめに

[Raspberry PiからGoogle Homeを喋らせる - Qiita](https://qiita.com/ktetsuo/items/8c9cd5714e231aa6ae09) で、GoogleHomeを自由に発話させることができるようになった。
いつも家に帰るときは妻に「帰るよ」というLINEを送っているが、それと同時に家のGoogleHomeが喋ったら面白いと思い、作ってみることにした。
ちょうど、参加中の[OPEN BETA LAB](http://nitoblab.itu-toki.com/)のメンバーの中でLINEbotが流行っており、調べてみるとLINEmessageingAPIというのがあり、LINEのメッセージを受信したり送信したりできることを知ったので、使ってみる。

## 2018/02/03 追記
なんでも喋らせられるようになりました！→[LINEから家のGoogleHomeに好きな言葉を喋らせる](https://qiita.com/ktetsuo/items/6e78b3f98d613f256e2d)

# 成果物

## システム構成

最終的な構成はこんな感じになった。
<img width="819" alt="LINE-GoogleHome.png" src="https://qiita-image-store.s3.amazonaws.com/0/70022/4656181f-9a99-b19c-6f84-7b815a3a1d0f.png">

1. LINEのbotアカウントにメッセージを送ると、botはメッセージ受信をトリガーにIFTTTにwebhookを送る
2. IFTTTがwebhookを受信すると、webhookでbeebotteのREST APIを叩いてメッセージをPublish(配信)する
3. beebotteは、届いたメッセージを貯める
4. 家のRaspberry　Piは、beebotteにMQTTでメッセージをSubscribe(購読)しておく
5. RaspberryPiにbeebotteからメッセージが届いたら、google-home-notifierを使ってGoogleHomeを喋らせる

## 機能

* LINEbotに何か送ると、GoogleHomeが固定の文章を喋る
* LINEで送ったメッセージによって文章を変えることはできていない

# 構成の検討

この構成になるまでは紆余曲折あった。

## RaspberryPiを外から制御する方法
まず参考にしたのは、下記の記事。
[GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます - Qiita](https://qiita.com/azipinsyan/items/db4606aaa51426ac8dac)
RaspberryPiをサーバーにして、HTTPリクエストを投げることによってトリガーにしている模様。しかし、自宅に置いてあるRaspberryPiに家の外からアクセスするためには、RaspberryPiをインターネットに公開する必要があり、セキュリティなどの心配があるため不採用とした。

RaspberryPiをサーバーにするのは敷居が高いので、RaspberryPiはクライアントとしてWeb上のどこかを定期監視してもらい、変化があったら喋らせるようなことがしたい。そんなものを探していたところ、見つかったのが下記の記事。
[IFTTTのトリガーおよびアクションをESP8266で実行する - Qiita](https://qiita.com/mayfair/items/e761c788a9d8787bc610)
IFTTTというのは「If Then This Then That」の通り、「こういうトリガーがあったらこういうアクションをする」というアプリ（アプレット）を簡単に作れるサービス。TwitterやDropboxといった様々なサービスが連携できるパーツが提供されており、入力（トリガー）と出力（アクション）の組み合わせで簡単にアプレットを作ることがきる。
この記事では、IFTTTのアクションとしてbeebotteというMQTTブローカー（IoTのデータを貯めておいたりするサービス）にwebhookを使ってデータを送信し、ESP8266（Wi-Fiマイコン）でbeebotteからデータを取得することでアクションを実現している。
この記事のESP8266の部分をRaspberryPiに置き換えればできるので、RaspberryPiを外から喋らせるのはこの方法を採用することにした。

## LINEからIFTTTにメッセージを届ける方法

IFTTTは様々なサービスと連携できるので、LINEのメッセージをトリガーにすることくらいできるだろうと思っていたが、IFTTTのトリガーに設定可能なサービス一覧にLINEがなかった。（アクションなら、LINEで通知する、というのが設定可能だった。）
LINEのAPIについて調べていると、[LINE Developers](https://developers.line.me/ja/)というのを発見した。LINE Developersに登録すると、LINEbotが作成でき、メッセージを受け取ったときにwebhookが送信できることがわかった。本来はLINEのbotを作るためによく使われるようだが、これを単なる通知として使うことにした。

## IFTTT不要説

感の良い読者なら気づくかもしれないが、LINEbotからwebhookをIFTTTに送信し、IFTTTからwebhookでbeebotteに通知しているため、IFTTTは省略できそうである。しかし、LINEbotから送信されるwebhookのJSONと、beebotteが受信できるwebhookのJSONの形式が一致せず、IFTTTは省略できなかった。

# 作成の手順

LINEbotにIFTTTのアクセスキーが必要で、IFTTTにはbeebotteのアクセスキーが必要なので、逆にbeebotte→IFTTT→LINEbotの順番で設定をするのが良い。

## beebotteチャンネルの作成

基本的には[IFTTTのトリガーおよびアクションをESP8266で実行する - Qiita](https://qiita.com/mayfair/items/e761c788a9d8787bc610)を参考にする。
[beebotte](https://beebotte.com/home)にアクセスし、アカウント登録とチャンネル、リソースを作成する。

- チャンネル名: ifttt
- リソース: action

を作成した。
My Channelsから作成したチャンネルをクリックすると、チャンネルの詳細が出て来ます。「Channel Token: ...」と書いてあるのが、そのチャンネルにアクセスするトークン。IFTTTに入力するのでとっておく。
<img width="898" alt="beebotte.png" src="https://qiita-image-store.s3.amazonaws.com/0/70022/8c141457-7171-1d59-3533-1d55743c6e5c.png">

## IFTTTアプレットの作成

ここも基本的には[IFTTTのトリガーおよびアクションをESP8266で実行する - Qiita](https://qiita.com/mayfair/items/e761c788a9d8787bc610)を参考にする。
IFTTTのアカウント登録を済ませ、[IFTTT Webhooks](https://ifttt.com/maker_webhooks)をConnectしておく。

- トリガー: webhooks
- アクション: webhooks

のアプレットを作成する。
<img width="700" alt="ifttt.png" src="https://qiita-image-store.s3.amazonaws.com/0/70022/981c3a55-9e1f-6fa7-f13a-5d3480ef3345.png">
URLには先ほどbeebotteで取得したチャンネルのアクセストークンを入力する。

https://ifttt.com/maker_webhooks の右上の「Documentation」をクリックすると、「Your key is: ...」にIFTTTのwebhookにアクセスするキーが書いてあるので取っておく。

## LINEbotの作成

[LINE Developers](https://developers.line.me/ja/)のアカウントを作成し、Messaging APIを作成する。作ったbotアカウントの「Channel基本設定」の「メッセージ送受信設定」で、

- Webhook送信を有効に
- Webhook URLに、先ほどIFTTTで取得した　アクセスキーを入力する。

<img width="826" alt="linebot.png" src="https://qiita-image-store.s3.amazonaws.com/0/70022/f1c43389-2347-1989-529a-ef052c21e738.png">

## Raspberry Pi プログラムの作成

### Node.jsとgoogle-home-notifierの設定

[Raspberry PiからGoogle Homeを喋らせる - Qiita](https://qiita.com/ktetsuo/items/8c9cd5714e231aa6ae09) を参考にして、設定する。

### Node.js用MQTTライブラリMQTT.jsのインストール

Node.jsでMQTTが簡単に使えるようにするライブラリ[MQTT.js](https://www.npmjs.com/package/mqtt)をnpm(Node Package Manager)でインストールする。
上記リンク先のInstallationに記載の通り、作業ディレクトリで下記を実行するとインストールできる。

```bash:
$ npm install mqtt --save
```

--saveとつけるのは、npmで生成されるpackages.jsonに「MQTT.jsが必要だよ」という情報を記録するためらしい。

### Node.jsプログラムの作成

作成したソースコードは以下。前回作成したgoogle-home-notifierのソースと、MQTT.jsのサンプルソースを合体させた感じ。

```javascript:mqtt-googlehome.js
const googlehome = require('google-home-notifier');
const mqtt = require('mqtt');

const language = 'ja';
googlehome.device("Google-Home", language);
googlehome.ip("192.168.xxx.xxx");

const client = mqtt.connect('mqtt://mqtt.beebotte.com',
  {username: 'token:token_XXXXXXXXXXXXXX', password: ''} // XXX..の部分にはbeebotteのチャンネルのアクセストークンを入れる
);

client.on('connect', function() {
  client.subscribe('ifttt/action');
});

client.on('message', function(topic, message) {
  console.log(message.toString());
  googlehome.notify('こんにちは世界。', function(res) {
    console.log(res);
  });
});

```

## 動作確認

これで、作成したLINEbotにメッセージを何か送信すると、GoogleHomeが喋るようになるはず。うまくいかない場合は、IFTTTやbeebotteでは動作履歴が記録されているのでデバッグ時の参考にできる。
↓動作中の動画
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">LINEからGoogle Homeを喋らせることに成功！現状、何を送っても同じこと言いますがw<br>LINE BotからIFTTTのwebhook経由でbeebotteにデータ貯めて、自宅のRaspberry Piでbeebotteからデータ取得、Node.jsのgoogle-home-notifierでGoogle Homeに発話させてます。 <a href="https://t.co/YtJnEXmCLM">pic.twitter.com/YtJnEXmCLM</a></p>&mdash; テツオ (@ktetsuo) <a href="https://twitter.com/ktetsuo/status/951835263143051265?ref_src=twsrc%5Etfw">2018年1月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
妻が留守番中に外からこれを実行したら、ただただビックリしていた模様。。

# 所感

LINE MessagingAPI, IFTTT, beebotteといった小さいサービスでも工夫次第で連携して好きなことができて楽しい。「ピタゴラスイッチ的」というのをどこかで見たが、まさにその通り。

# 今後

今回は固定の文章しか喋れなかったが、好きな文章を喋らせるようにしたい。
IFTTTのwebhook受信が、JSONの細かいステータスを読み込むことができなかったのが敗因なので、IFTTTをAWS LambdaやAzure Functionあたりに差し替えて、LINEからどんなメッセージが来たかを読み取ることで実現できるのではないかと構想中。