raspberry pi zero wにgoogle-home-notifierを入れてGoogle Homeをコマンドで喋らせる

google-home-notifierの導入と作動テストをやってみました。

無事、喋らせることができましたが、

初心者ならではの色々な躓きがあったので備忘録を残しておきます。

 前回の記事で、node.jsとnpmはインストール済み。

まずは下記READMEに従ってgoogle-home-notifierのインストールを試みる。

GitHub - noelportugal/google-home-notifier: Send notifications to Google Home

sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev

で必要なパッケージをインストールしたあと、node.jsの最新verを入れてね、と書いてあったので下記を実行。

curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -

ここでエラー吐かれつまりました。なんでもARMv6系CPUではこいつは使えませんよ、とか。でも、これより新しいverのnode.js導入してなかったっけ? ということでバージョン確認。

pi@raspberrypi:~ $ node -v
v9.2.1

新しいし多分大丈夫でしょ!ってことでgoogle-home-notifierのインストールへ。

git clone https://github.com/noelportugal/google-home-notifier

cd google-home-notifier

npm install

問題なくインストールできました。続いてgoogle-home-notifierの設定へ。まずはbrowser.jsの編集。

vi node_modules/mdns/lib/browser.js

で開いて、上記READMEの通り、

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

と変更しました。

続いてgoogle-home-notifier.jsを編集。

var Client = require('castv2-client').Client;
var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;
var mdns = require('mdns');
var browser = mdns.createBrowser(mdns.tcp('googlecast'));
var deviceAddress = '192.168.X.XXX'; // Google HomeIPアドレスに修正する
var language;

var device = function(name, lang = 'ja') { // "ja"に修正する
device = name;
language = lang;
return this;
};

var ip = function(ip) {
deviceAddress = ip;
return this;
}

var googletts = require('google-tts-api');
var googlettsaccent = 'ja'; // "ja"に修正する
var accent = function(accent) {
googlettsaccent = accent;
return this;
}

 に変更。後々、ここの変更ミスで痛い目見ました・・・

次にexample.jsを編集。

GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます - Qiita

こちらを参考に。

var express = require('express');
var googlehome = require('./google-home-notifier');
var ngrok = require('ngrok');
var bodyParser = require('body-parser');
var app = express();
const serverPort = 8091; // default port

var deviceName = 'リビング'; //Google Homeの設定デバイス
var ip = '192.168.X.XXX'; // default IP //ここにGoogle HomeのIPを記載


var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.post('/google-home-notifier', urlencodedParser, function (req, res) {

if (!req.body) return res.sendStatus(400)
console.log(req.body);

var text = req.body.text;

if (req.query.ip) {
ip = req.query.ip;
}

var language = 'ja'; // default language code   //ここに「ja」を記載
if (req.query.language) {
language;
}

googlehome.ip(ip, language);
googlehome.device(deviceName,language)       //ここに命令文を追加

if (text){
try {
if (text.startsWith('http')){
var mp3_url = text;
googlehome.play(mp3_url, function(notifyRes) {
console.log(notifyRes);
res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
});
} else {
googlehome.notify(text, function(notifyRes) {
console.log(notifyRes);
res.send(deviceName + ' will say: ' + text + '\n');
});
}
} catch(err) {
console.log(err);
res.sendStatus(500);
res.send(err);
}
}else{
res.send('Please GET "text=Hello Google Home"');
}
})

app.get('/google-home-notifier', function (req, res) {

console.log(req.query);

var text = req.query.text;

if (req.query.ip) {
ip = req.query.ip;
}

var language = 'ja'; // default language code     //ここに「ja」を記載
if (req.query.language) {
language;
}

googlehome.ip(ip, language);
googlehome.device(deviceName,language)        //ここに命令文を追加

if (text) {
try {
if (text.startsWith('http')){
var mp3_url = text;
googlehome.play(mp3_url, function(notifyRes) {
console.log(notifyRes);
res.send(deviceName + ' will play sound from url: ' + mp3_url + '\n');
});
} else {
googlehome.notify(text, function(notifyRes) {
console.log(notifyRes);
res.send(deviceName + ' will say: ' + text + '\n');
});
}
} catch(err) {
console.log(err);
res.sendStatus(500);
res.send(err);
}
}else{
res.send('Please GET "text=Hello+Google+Home"');
}
})

app.listen(serverPort, function () {
ngrok.connect(serverPort, function (err, url) {
console.log('Endpoints:');
console.log(' http://' + ip + ':' + serverPort + '/google-home-notifier');
console.log(' ' + url + '/google-home-notifier');
console.log('GET example:');
console.log('curl -X GET ' + url + '/google-home-notifier?text=Hello+Google+Home');
console.log('POST example:');
console.log('curl -X POST -d "text=Hello Google Home" ' + url + '/google-home-notifier');
});
})

これで準備完了!ってことで早速動作確認してみます。

node example.js

でexample.jsを起動して、例文に倣い、

curl -X POST -d "text=ほげほげ" http://192.168.X.XXX:8091/google-home-notifier

と打ち込みませんが、応答なし。むむむ?

ここで結構悩みましたが、正解は、example.jsを起動した状態で別のコンソール窓を開いて、そこからターミナルにコマンドを打ち込まなくてはならない、というものでした・・・詳しい方からすればそんなとこで詰まるの?って感じかもしれませんね。初心者感爆発。

で、きちんとターミナルから上記を実行。

curl -X POST -d "text=ほげほげ" http://192.168.XXX.X:8091/google-home-notifier

curl: (7) Failed to connect to 192.168.XXX.X port 8091: 接続を拒否されました 

エラー。ここでも悩む・・・原因は、raspberry.piのIPではなくGoogle HomeのIPを入力してcurl実行していたことでした。例文がそうなっていたとはいえ、我ながらアホでした。

curl -X POST -d "text=ほげほげ" http://192.168.YYY.Y:8091/google-home-notifier
リビング will say: ほげほげ

 きちんとraspberry.piのIPを指定してcurl実行してあげたところ、やっと通ってくれました。Google Home miniからも何やら音が!

・・・あれ、効果音はなるけど喋らないぞ???

google-tts-api周りがおかしいのかな?と思い、書き換えたexample.jsとgoogle-home-notifier.jsをチェックすると、google-home-notifier.jsの方で、languageの値がjaではなくjpになってしました・・・jaに変更して再度example.jsを起動、curlを実行すると、やっとHome miniちゃんが「ほげほげ」と喋ってくれました。

 

一人で勝手に遠回りした感はありましたが、何とかgoogle-home-notifierの導入までたどり着きました。同じようなとこで詰まる人はそうそういないとは思いますが、この記事が誰かの役に立てば幸いです、ということで自分のアホさを晒しておきます・・・

 

次は、こいつを活用して色々遊んでみたいと思います。