AmazonのDashボタンとGoogle Homeを連携させた話

不慣れながら投稿します。アドベントカレンダー 14日目です。

### 何をするの？
老人介護用のヘルプボタンや、
２階部屋・離れなどにいる人の呼び出しボタンに出来ます。

### 手順的にはこの順序で命令が運ばれます。
- Dashボタンを押す。
- Raspberry Piで動いている DasherがARPを拾う。
- DasherがMACアドレスを確認後、アクションを行う。
- DasherはGoogle-Home-Notifier[G.H.N.]へポストする。
- G.H.N.はGoogle-Homeへ喋って欲しいことを投げる。

### 実行環境は以下の通り
- Google Home
- Raspberry Pi[3B]
- Amazon Dashボタン[なんでもいいです。今回はエビアンを使用]

### Raspberry Pi の準備

まずはラズパイの準備からです。

最初に`apt-get update`と`apt-get upgrade`にて、最新バージョンへ更新しておきます。

```
sudo apt-get update
sudo apt-get upgrade
```


次に、以下コマンドをすべて実行して最新のNode.jsとnpm をインストールします。

```
sudo apt-get install -y nodejs npm
sudo npm cache clean
sudo npm install npm n -g
sudo n stable
```
### Dashボタンの準備とDasherの準備
次にDashボタンを家の中のWi-Fiに接続する。

スマホにてAmazonショップアプリを開き、商品登録前まで進めてバッテンで終了。

Dasherはパケットキャプチャを使用するので以下をインスト

```
sudo apt-get install libpcap-dev
```

次にDasherです。

```
git clone https://github.com/maddox/dasher.git
cd dasher
sudo npm install
```

お次はDashボタンのMACアドレスを調べます。
このMACアドレスを指定して各ボタンのアクションを決めます。
以下のコマンドを実行

```
sudo ./script/find_button
```

すると現在LANの中を飛んでいるパケットが見えます。

パケットを監視している段階で、Dashボタンを押すと数秒後にMACアドレスが表示されます。
押した分だけ表示されるので、他のパケットと見分けがつかない場合、
複数回押すことで特定できます。

ここで私が躓いた点として、ASUSのルーターが頻繁にARPパケットを投げていました。
その為、Dashボタンパケットが埋もれてしまい、Dasherが検知できなことがありました。
対策は各々必要になってきますが、私はルーターの要らない機能をOFFにすることで回復しました。

このMACアドレスをコピーし記録しておいてください。


次にDasherの設定をして行きます。

Dasherのインストール以下 `./config/config.example.json`をコピーして`config.json`とし
テキストエディタのなんでもいいので編集を始めます。

以下が設定例を書いています。

```config.json
{"buttons":[
    {
    "name": "DASH",
    "address": "00:11:22:33:44:55",
    "interface": "eth0",
    "timeout": "60000",
    "url": "http://localhost/Lanch.py",
    "method": "GET"
    }
]}
```

構文説明
`name` は任意の名前 このボタンの名前
`address` は先程調べたMACアドレスを記入
`interface` ここはトラブりました。オリジナルはen0となっているのですが、ここはeth0に書き換えます。`ifconfig`で手に入る使用するアダプタ名にします。
`url`-`method`はGoogle-Home-Notifierに合わせています(後述)

このままセーブを行い、Dasherの直下にて`sudo npm run start`

```
[2017-12-xxxxx:00:0000.000] DASH pressed. Count: 1
```

押すたびにカウントが増えていればDasher機能は成功。

### Google Home Notifierのセットアップ

Google Homeに喋って貰います。
これだけ応用しても面白い機能です。

まずGit関連。

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

次にGitからクローンしてインストール。

```
git clone https://github.com/noelportugal/google-home-notifier
cd google-home-notifier
npm install
```

次は設定、Google-home-notiferの中に`example.js`があるので、
これを編集するが、`deviceName`と`serverPort`を変えないのであれば、このままでOK


```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 = 8080;

var deviceName = 'Google Home';
googlehome.device(deviceName);
// googlehome.accent('uk'); // uncomment for british voice

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 (text){
    try {
      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 POST "text=Hello Google Home"');
  }
})

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

次の設定は同じ場所にある、`google-home-notifier.js`を編集する。

変えるところは。

`var device = function(name, lang = 'ja')` 
lang=usこれをusからjaに。

`var googlettsaccent = 'ja';`
同じくこれをjaに。

`deviceAddress = '192.168.1.52';`
この行は追加します。
Google-Homeが割り当てられているIPアドレスに、事前に調べて固定化する必要があります。

```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;
var language;

var device = function(name, lang = 'ja') {
  device = name;
  language = lang;
  return this;
};

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

var googletts = require('google-tts-api');
var googlettsaccent = 'ja';
var accent = function(accent) {
  googlettsaccent = accent;
  return this;
}

deviceAddress = '192.168.1.52';

var notify = function(message, callback = function() {}) {
  if (!deviceAddress){
    browser.start();
    browser.on('serviceUp', function(service) {
      console.log('Device "%s" at %s:%d', service.name, service.addresses[0], s$
      if (service.name.includes(device.replace(' ', '-'))){
        deviceAddress = service.addresses[0];
        getSpeechUrl(message, deviceAddress, function(res) {
          callback(res);
        });
      }
      browser.stop();
    });
  }else {
    getSpeechUrl(message, deviceAddress, function(res) {
      callback(res);
    });
  }
};
====>続く
```

自分がポカしていたのは、`ja`に変更するところを`jp`にしていた点。
ともにjapanなのだが・・・

ここまできたら、example.jsを起動します。
```
node example.js
```

起動したら、別のコンソールから`curl`を実行

```
curl -X POST -d "text=てすとー" http://localhost:8080/google-home-notifier
```

これで「てすとー」と喋ったら、成功。
いつもの声とちょっと違います。

慣れてる人なら判りますが、`text=`以降は任意文字でここが喋る文章。
URLが今は自分自身になっていますが、もちろん変えることも可能。
外部から、帰りの電車からスマホなどでもコールできます。

私の場合、後から変えることもあり、pythonにて別ファイルに記述、
これをコールしています。

### 最後に

DasherもGoogle-home-notifierもサービス登録して自動起動を行うならサービスファイルを作って完了。

### おまけ

DasherからのレスポンスをIFTTTへ投げて組み合わせても面白いよ～。