Node.js
AmazonDashButton
Dasher
GoogleHome
google-home-notifier

ラズパイを使わずにAmazon DashとGoogle Homeを連携させてみた

Amazon Dash Buttonを押すと、Google Home Miniが喋る
というテストです。

WiFiの圏内であれば、声の届く範囲でなくてもGoogle-Homeを応答させれるんじゃないか、という構想でしたが、
喋るだけで今の所応答までは繋がりません。

WiFi環境、Node環境のみで問題ないはずです。

ちなみに今回の実行環境は
HighSierra
node v9.3.0
npm v5.6.0
でした。

MacからGoogle Homeを喋らせてみる

作業用のディレクトリghomeを作った後google-home-notifierを入れます。

$ mkdir ghome
$ cd ghome
$ npm init
$ npm install google-home-notifier

IPアドレスを調べる

あとで使うのでまずGoogle HomeのIPアドレスを取得します。
ghomeにtest.jsを作ります。

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

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

googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});
$ node test.js
Device "Google-Home-XXX" at 192.168.1.11:8009
Device notified

at以下に書いてあるものがGoogle HomeのIPアドレスです。
:以下の数字、この場合8009がport番号になります。

喋らせる

同様にghomeにexample.jsを作ります。

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

var deviceName = 'ribihome';
var ip = '192.168.1.11'; // default IP      //ここに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
  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
  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
Endpoints:
    http://192.168.1.11:8009/google-home-notifier
    https://e8bfa9cf.ngrok.io/google-home-notifier
GET example:
curl -X GET https://e8bfa9cf.ngrok.io/google-home-notifier?text=Hello+Google+Home
POST example:
curl -X POST -d "text=Hello Google Home" https://e8bfa9cf.ngrok.io/google-home-notifier

となりサーバが立つので、別のターミナルウィンドウを開き
GET exampleかPOST exampleのどちらかをすれば問題ないです。

$ curl -X GET https://e8bfa9cf.ngrok.io/google-home-notifier?text=Hello+Google+Home
ribihome will say: Hello Google Home

これで喋ります。
一回つまったんですが、音量が小さかっただけでした。

Amazon Dash Buttonの押下をMacで拾う

Amazon Dash Buttonのセットアップは、公式通りにやってください。
ただし、商品選択の欄にきたら×をタップして終了します。

Dasherを使います。まず作業用ディレクトリadashを作成してからDasherをクローンしました。

$ mkdir adash
$ cd adash
$ git clone https://github.com/maddox/dasher.git
$ cd daser
$ npm install

DashボタンのMACアドレスを調べる

ボタンの識別のためにMACアドレスを取得します。

$ ./script/find_button
Password:
Watching for arp & udp requests on your local network, please try to press your dash now
Dash buttons should appear as manufactured by 'Amazon Technologies Inc.' 

という状態になるので、ここでボタンを押すと

$ ./script/find_button
Password:
Watching for arp & udp requests on your local network, please try to press your dash now
Dash buttons should appear as manufactured by 'Amazon Technologies Inc.' 
Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: unknown Protocol: udp
Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: unknown Protocol: arp

下の2行が追加されました。
Amazon Technologies Inc.と表示されるはずなのに、unknownになっていますが、これで問題なかったです。
XX:XX:XX:XX:XX:XXの部分がMACアドレスです。

押下を拾う

dasher/configの下にjsonを作ります。

config/config.json
{"buttons":[
  {
    "name" : "Amazon Dash Button [伊右衛門]",
    "address": "XX:XX:XX:XX:XX:XX",
    "url": "https://e8bfa9cf.ngrok.io/google-home-notifier?text=Hello+Google+Home",
    "method": "GET",
    "json": true,
    "body": {"text":"Hello"}
  }
]}

adressの部分には先ほどのMACアドレスが入ります。
その後実行します。

$ sudo npm run start
Password:

> dasher@1.4.1 start /Users/hogehoge/Documents/adash/dasher
> node app.js

[2018-01-03T16:37:45.134Z] Amazon Dash Button [伊右衛門] added.

となるので、ここでAmazon Dash Buttonを押すと

[2018-01-03T16:39:35.966Z] Amazon Dash Button [伊右衛門] pressed. Count: 1
[2018-01-03T16:39:36.763Z] Unsuccessful status code

というメッセージが追加されます。これでMacでダッシュボタンの押下が拾えました。

連携させる

さっきダッシュボタンを押した時のメッセージで、Unsuccessful status codeとなっているのが気になったかもしれません。
実はこのconfig.jsonではurlが適当ではないからです。

ghomeで

$ node example.js
を実行し、そのGETのurlをコピーしましょう。
そのurlをconfig.jsonのurlに置き換えることでGETを飛ばすことができます。

その後dasherで

$ sudo npm run start

を実行します。
一つ前に実行したexample.jsは中断しないようにしましょう。

二つのプログラムを走らせたままAmazon Dash Buttonを押すと、Google Homeが喋ってくれます。

実用性

サーバー用のPCを用意してる人なら使えると思います。
テストとしてなら、Google HomeとAmazon Dashのいい基本になるんじゃないでしょうか。

参考

test.jsは
https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066
のmain.js

example.jsは
https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066
から取ってきました。

Amazon Dashの部分は
https://qiita.com/tokio-takeda/items/a061df1f254117659b0c
をほぼ使わせてもらいました。