Raspberry PiからGoogle Homeを喋らせる

# はじめに
昨年末にGoogle Home Miniを買ったので何か使えないか調べていたところ、Node.jsにgoogle-home-notifierというAPIがあり、任意の言葉を喋らせることができるという記事があったのでやってみた。
macだと

```bash:
$ npm install google-home-notifier
```

すればサンプルプログラムが実行できたが、RaspberryPiで同じことをやろうとしたら何かとつまづいたので、記事にすることにした。

## 使用機材
- Google Home Mini
- Raspberry Pi 3 Model B (Raspbian Stretch 2017-11-29 インストール済み)

## 2019/04/06 追記

Raspbian Stretch 2018-11-13 だと Node.js の v8.11.1 が標準でインストールされていた。
そのため下記 「Node.jsのアップデート」の作業は不要、npmが入っていなかったため、npmのインストールが必要と思って `$ sudo apt-get install npm` とやってもうまく入りませんでした。
やはり下記手段をやる必要がありそうです。

# Node.js のアップデート
Rasbpian Stretchに標準でインストールされているNode.jsはバージョンが古い(v4.8.2)。
そのため、npmでgoogle-home-notifierをインストールしようとすると怒られるので、Node.jsをアップデートする必要があった。
せっかくなので、「nvm（Node Version Manager）」(プロジェクトごとに、Node.jsのバージョンを切り替えて使えるようにする仕組み)を入れて、今後バージョン違いで困らないようにした。
手順は下記を参考にした。
[Raspberry Pi 3 Model BにnvmでNode.jsをインストールする - しらすの備忘録](http://sirasu55.hatenablog.com/entry/2017/10/11/235223)

## 古いNode.jsをアンインストール

```bash:
$ sudo apt-get autoremove nodejs
```

## nvmのインストール

nvmをインストールするためのディレクトリ作成

```bash:
$ sudo mkdir ~/.nvm
$ sudo chmod 777 ~/.nvm
```

gitからnvmを取得

```bash:
$ git clone https://github.com/creationix/nvm.git ~/.nvm
```

nvmを使えるようにする

```bash:
$ source ~/.nvm/nvm.sh
```

nvmバージョンを取得して、nvmがインストールできたことを確認する。

```bash:
$ nvm --version
```

## Node.js のインストール

nvmでインストールできるNode.jsのバージョンのリストを確認

```bash:
$ nvm ls-remote
```

この中で、「LTS（Long Team Support）」（要するに安定版）とついているバージョンをインストール
2018-01-05時点でv8.9.4

```bash:
$ nvm install v8.9.4
```

Node.jsがインストールされたかどうかバージョンを確認

```bash:
$ node --version
ｖ８．９．４
```

npm(Node Package Manager)もインストールされているかどうかバージョンを確認

```bash:
$ npm --version
5.6.0
```

やっとgoogle-home-notifierをインストールする準備ができました。

# google-home-notifierのインストール

ここからは下記を参考に作業してます
[Google Home開発入門 / google-home-notifier解説 - Qiita][link-1]
[link-1]:https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066

作業用ディレクトリを作成して移動

```bash:
$ mkdir googlehome
$ cd googlehome
```

npmの準備（package.jsonの作成）

```bash:
$ npm init
```

満を持してgoogle-home-notifierのインストール
この１行がやりたかったために上記の準備が必要だったのだ！

```bash:
$ npm install google-home-notifier
```

しかし、失敗。がーん。

```bash:
fatal error: dns_sd.h: そのようなファイルやディレクトリはありません
```

エラーメッセージで検索すると、下記のサイトに出会った。
[Raspberry Pi 3 にhomebridgeを導入してsiriから家電操作できるようにした際の覚書 - Qiita](https://qiita.com/udon11/items/25e09769196cbbe397e3)
ここを参考に、下記を実行してみる

```bash:
$ sudo apt-get install libavahi-compat-libdnssd-dev
```

再度

```bash:
$ npm install google-home-notifier
```

今度は成功。

# サンプルプログラムの実行
[ここ][link-1]に書いてあるサンプルプログラムをmain.jsファイルに保存

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

googlehome.device('Google-Home', language); 

googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});
```

実行。

```bash:
$ node main.js
```

失敗。

```
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: getaddrinfo -3008
    at errnoException (/home/pi/work/googlehome/node_modules/mdns/lib/resolver_sequence_tasks.js:199:11)
    at getaddrinfo_complete (/home/pi/work/googlehome/node_modules/mdns/lib/resolver_sequence_tasks.js:112:10)
    at GetAddrInfoReqWrap.oncomplete (/home/pi/work/googlehome/node_modules/mdns/lib/resolver_sequence_tasks.js:120:9)
```

getaddrinfoでエラー？
~~よくわからないが、GoogleHomeのIPアドレスを指定する方法があったので、参考にプログラムを修正。~~
**(2018/05/19修正)　**[公式のREADME](https://github.com/noelportugal/google-home-notifier#after-npm-install)に記載の方法で名前解決できるようになりました。コメントで教えてくれたhorihiroさんThanx!

node_modules/mdns/lib/browser.js コードの一部を修正。

```javascript:before
Browser.defaultResolverSequence = [
  rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo()
, rst.makeAddressesUnique()
];
```

```javascript:after
Browser.defaultResolverSequence = [
  rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo({families:[4]})
, rst.makeAddressesUnique()
];
```

要するに`rst.getaddrinfo()`を`rst.getaddrinfo({families:[4]})`にする。
この修正を加えてから再度実行すると、Google Homeが喋ってくれる。

*もしうまくいかなかったり、IPアドレスを直接指定したい場合は以下のコードでIPアドレスを指定できる。*

```javascript:main2.js
const googlehome = require('google-home-notifier');
const language = 'ja';
googlehome.device("Google-Home", language);
googlehome.ip("192.168.xxx.xxx");
googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});
```

いろいろなものと連携して、GoogleHomeが喋るようにできますね。
こんな記事も見つけました。
[GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます](https://qiita.com/azipinsyan/items/db4606aaa51426ac8dac)

# 未解決問題など
1. Node.jsを一回アンインストールした影響か、Raspberry Piに元から入っていたNode-RED（ブロックを繋げてプログラミングするやつ）が消えてしまった。使いたいときはあらためてインストールする必要がある。
2. ~~macではIPアドレスを直打ちしなくてもできたので、直打ちしなくてもよい方法を知りたい。~~ **(2018/05/19解決)**