Node-REDを使って簡単にGoogle Homeに喋らせよう

# Google Homeに喋らせるのって意外と大変
Google Homeにメッセージを喋らせる方法としては[google-home-notifier](https://github.com/noelportugal/google-home-notifier)を使った方法が有名だと思います。
ただ、google-home-notifierを使うには結構面倒な点が多いです。

- npmで入れただけだと動かない（google-tts-apiのバージョンを上げたりしなければいけない）
- 外部からのメッセージをトリガーに喋らせたい（例えばSlackで投稿した内容を喋らせる）場合はGoogle Apps Script等で中継させなきゃいけない
- Node-RED自体も[ngrok](https://ngrok.com/)等を使って外部に公開させなきゃいけない
- 更に再起動の度にngrokの公開URLが変わるので、それをどこかに保管しておかなければいけない

等々。
もちろん「それくらい調べれば対応できるだろ」と言われればそうなのですが、もっと簡単にできるならその方がいいですよね。
そこで[Node-RED](https://nodered.jp/)を使って、簡単にGoogle Homeを喋らせてみましょう。

# Node-REDとは
[Node-RED](https://nodered.jp/)はフローベースドプログラミングツールと呼ばれ、「ノード」と呼ばれるブラックボックス化されたアプリケーションを線で繋いで「フロー」と呼ばれるプログラムを構築していきます。
基本的なI/O（Http, UDP/TCP, Websocket, MQTT等）のノードは一通りそろっているほか、各種サードパーティによって様々なノードが作られているため、それらを繋いでいくだけで簡単にアプリ同士を連携させていくことができます。
感覚的には[IFTTT](https://ifttt.com/)とかに近いですが、フロー内ではJavaScriptの関数も使用できたりと結構高度なこともできます。

# 手順
ざっくり以下の手順です。

1. Node-REDをインストール
2. Castノードを追加
3. ノードを繋ぐ

## ラズパイで環境構築
Node-REDはNode.jsが動作する環境であればどこでも動作しますが、Raspberry Pi（ラズパイ）なら簡単に環境構築ができて、常時起動も気軽にできます。しかもインストールが簡単なので今回はラズパイを使った方法を紹介します。
ラズパイのOSはインストールされている状態からスタートします。

## ラズパイにNode-REDをインストール
ラズパイのターミナルで以下を実行します。

```shell
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```

基本これだけでOKです。
公式で上記のインストールスクリプトが用意されていて、以下のことをやってくれます[^1]。

- すでにインストールされているNode-REDおよびNode.jsをアンインストール
- 現行のNode.js LTSリリースをインストール
- npmを利用して最新版のNode-REDをインストール
- ラズパイの固有ノード（GPIO等）をインストール
- サービスとしてNode-REDを実行するように設定し、 サービスとして動作するためのコマンド一覧を提供

## Node-RED起動
`node-red-start`コマンドを実行することでNode-REDを起動できます。サービスとして起動しているため、`Ctrl+C`を押してもバックグランドで実行を続けます。
終了するには`node-red-stop`コマンドを実行します。
また、ラズパイ起動時に自動で起動させるには`sudo systemctl enable nodered.service`を実行すればOKです。

`http://[ラズパイのIPアドレス]:1880`にアクセスすると以下のようなフローエディタ画面が表示されます。
ここでフローを編集していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/663b0d14-be9b-c95a-8059-a26fbba0dabc.png)

## Castノードを追加
Google Homeに喋らせるには、Chromecast機能のノードを使用します。
右上のハンバーガーメニューから`パレットの管理`を開き、`ノードを追加`タブを開きます。
検索欄に`node-red-contrib-cast`と入れて、出てきた`node-red-contrib-cast`ノードの「ノードを追加」ボタンを押します。

`node-red-contrib-castv2`というノードもあるのですが、Google Homeに喋らせるには`node-red-contrib-cast`ノードの方が楽なのでこちらを採用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/9a2bf939-3884-489b-d665-0b767334824b.png)
追加されると、左のノード一覧の中に以下の`Cast`ノードが追加されていると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/10559d99-d18c-230c-9d24-78ff08213183.png)
これを真ん中のボードにドラッグ&ドロップして持ってきます。

## Castノードの設定
真ん中に持ってきたノードをダブルクリックするとプロパティの編集画面が開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/446f8f90-8dc6-ada5-b659-106ab2fef1e0.png)

以下の項目を埋めて「完了」を押します。

- `IP`：**Google Home**のIPアドレス
- `language`：「ja」
- `Message`：「こんにちは」

他の項目は空欄でOKです。`Volume`欄に数値（0~100）を入れると喋るときの音量を調整してくれます。

## injectノードを繋いでデプロイ
左上の`inject`ノードを同じように持ってきて、以下のように繋ぎましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/4468988f-80c2-ccd3-d7c0-a2a9015af01b.png)
これでフローが作成されました。
その後、右上の「デプロイ」ボタンを押すとフローが実際にデプロイされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/fd7ba29a-09a2-db01-496e-32215ddd940e.png)
これで準備完了です。

## 実行
injectノードの左についているタグのようなものが実行ボタンになっています。これを押してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/d5e1a1ac-0c49-f701-41ae-1931405ee07b.png)

そうするとあなたのおうちのGoogle Homeが「こんにちは」と喋ってくれたはずです。
非常に簡単にGoogle Homeに喋らせることができました。

# 任意の言葉を喋らせたい
今はCastノードに「こんにちは」というメッセージを固定で入力していましたが、任意のメッセージを入力させることができます。
フロー間はJavaScriptの文字列やオブジェクト形式のデータが`msg`変数に入って流れています。Castノードは`msg.message`または`msg.payload.message`に文字列を入力すると、それを喋らせることができます。
なので、この形式で文字列を入力させるだけで、任意のメッセージを喋らせることができます。

例えば、以下のように`change`ノードを間にはさみ、`msg.message`に「おはようございます」と代入すると、Google Homeは「おはようございます」と喋ります（Castノードの設定より`msg`の入力の方が優先される）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/8d463d2c-a6af-4ed2-6a15-811f30cd1068.png)
Node-REDはほかの外部システムやアプリケーションとも簡単に連携できますので、これを使えば「〇〇したらGoogle Homeに喋らせる」というシステムをNode-RED上で簡単に実現できます。

## 例：Slackと連携
試しにSlackと連携して、Slackに投稿したメッセージをNode-REDに喋らせてみましょう。
Slackとの連携ノードもNode-REDにあるので、これを使えば簡単に実現できます。
### Node-REDでSlack bot
SlackのメッセージをNode-REDに送るには[node-red-contrib-slack](https://flows.nodered.org/node/node-red-contrib-slack)という拡張ノードを使用します。
ここでは詳細は書きませんが、SlackアプリとSlack botを作成し、生成されたアクセストークンをノードの設定に入れるだけでSlackのメッセージ等を取得できます。
以下の方の記事が詳しいので、そちらを参照してみてください。

[Node-REDでSlack bot 2019年8月時点 - Qiita](https://qiita.com/kolinz/items/2baf166d27c505acfd89#node-red%E3%81%A7slack-bot)

`slack-rtm-in`ノードを上記記事のように設定すればSlackのメッセージを取得できます。
### SlackメッセージをNode-REDに喋らせる
Slackに投稿されたメッセージは`msg.payload.text`から取得できます。なのでこれを`msg.message`か`msg.payload.message`に入れてやればOKです。

また、`slack-rtm-in`ノードから入ってくる情報は他にもいろいろあり、例えば`msg.payload.userObject.real_name`でユーザ名を取得できます。
これを使ってユーザ名も一緒に喋らせられるようにしたものが以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428874/d80dbdcc-a0b8-ae1f-09c0-d1bbce346e5f.png)
間に`template`ノードをはさみ、そこでメッセージを組み立てて`cast`ノードに渡しています。

# まとめ
Node-REDを活用することで、簡単にGoogle Homeにメッセージを喋らせることができました。
また、外部システム（Slack）との連携も簡単にできました。

google-home-notifierを使ってSlackと連携するには

```
Google Home
  |
google-home-notifier
  |
(ngrok)
  |
Google Apps Script
  |
(Outgoing Webhook)
  |
Slack
```

のような感じで、連携する物が多く構築や管理も大変でしたが、Node-REDを使うことで

```
Google Home
  |
Node-RED
  |
Slack
```

という感じで簡単に繋げることができました。

このように、Node-REDは「繋ぐ」ことに関してはかなりの威力を持っているので、アイデア次第でいろんなことができそうです。

[^1]: [Raspberry Piで実行する : Node-RED日本ユーザ会](https://nodered.jp/docs/getting-started/raspberrypi)