Node.js
RaspberryPi
GoogleHome
google-home-notifier

Raspberry PiからGoogle Homeを喋らせる

はじめに

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

$ npm install google-home-notifier

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

使用機材

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

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をインストールする - しらすの備忘録

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

$ sudo apt-get autoremove nodejs

nvmのインストール

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

$ sudo mkdir ~/.nvm
$ sudo chmod 777 ~/.nvm

gitからnvmを取得

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

nvmを使えるようにする

$ source ~/.nvm/nvm.sh

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

$ nvm --version

Node.js のインストール

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

$ nvm ls-remote

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

$ nvm install v8.9.4

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

$ node --version
v8.9.4

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

$ npm --version
5.6.0

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

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

ここからは下記を参考に作業してます
Google Home開発入門 / google-home-notifier解説 - Qiita

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

$ mkdir googlehome
$ cd googlehome

npmの準備(package.jsonの作成)

$ npm init

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

$ npm install google-home-notifier

しかし、失敗。がーん。

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

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

$ sudo apt-get install libavahi-compat-libdnssd-dev

再度

$ npm install google-home-notifier

今度は成功。

サンプルプログラムの実行

ここに書いてあるサンプルプログラムをmain.jsファイルに保存

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

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

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

実行。

$ 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に記載の方法で名前解決できるようになりました。コメントで教えてくれたhorihiroさんThanx!

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

before
Browser.defaultResolverSequence = [
  rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo()
, rst.makeAddressesUnique()
];
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アドレスを指定できる。

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スピーカーに外部からプッシュして自発的に話してもらいます

未解決問題など

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