ラズパイ+3GPi+イプシムを使って外から家のGoogle Homeを喋らせる

[GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます](https://qiita.com/azipinsyan/items/db4606aaa51426ac8dac)を参考に、ラズパイ＋[3GPi](https://mechatrax.com/products/3gpi/)と[イプシム](https://ipsim.net/)だけで、外出先から自宅のGoogle Homeを喋らせてみます。IFTTT、Firebase、Twitter、Slackなどの外部サービスやngrokなどのトンネルサービスは使いません。

#何ができるの？

- どこでも『OK, Google』（固定回線不要・無線LAN不要）
- 外から家のGoogle Homeを喋らせる！

##準備するもの

- Raspberry Pi 3 Model B（またはRPi2とUSB無線LANドングルの組み合わせ＋追加設定）
- [3GPi](https://mechatrax.com/products/3gpi/)＋同梱Raspbian([3gpi2-jessie-20170904](https://github.com/mechatrax/3gpi/tree/master/release))（またはUSBモデム＋追加設定）
- 固定IPアドレスMVNO「[イプシム](https://ipsim.net/)」標準SIM
- Google Home または Google Home Mini
- **自由にHTTP POSTできる環境**

##ネットワーク構成
`Internet --(3G回線)-- <ppp0>[3GPi+イプシム]+[RPi]<wlan0> --(無線LAN)-- [Google Home]`


#はじめに：Google Homeの利用方法3パターン
|   | Input || 中間処理 || Output | 例 |
|:-------------:|:-:|:-:|:-:|:-:|:-:|:-:|
| (1)OK, Google | Google Home |→|Google|→| Google Home | 「今日の天気は？」⇒『晴れです』 |
| (2)内から外 | Google Home |→| IFTTT |→| Twitter, Slack等 | 「～と呟いて」⇒"～"をtweet |
| (3)外から内 | **何かのトリガと手段** |→| google-home-notifier |→| Google Home | "帰ります"をPOST⇒『カエリマス』 |

(1)は普通の使い方ですね。
(2)はIFTTTを使う例が多いようです。
(3)が今回やりたいことですが、[google-home-notifier](https://github.com/noelportugal/google-home-notifier)をラズパイなどで動作させることで、簡単に実現できるようです。なんと「Google Homeに喋らせたいメッセージ」を、google-home-notifierにPOSTで投げるだけで、Google Homeが喋ります。残る問題は、LAN以外からどうやってgoogle-home-notifierに投げるか、だけです。

##(3)の使い方で参照したサイトと接続手段

- [GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます](https://qiita.com/azipinsyan/items/db4606aaa51426ac8dac) (LAN)
- [Google Homeで時報を知らせる](https://qiita.com/udon11/items/fef44cec7b243f93151b) (LAN)
- [帰宅したらGoogleHomeから好きな音声で「おかえり」って言ってもらいます](https://qiita.com/taaaaaaak22/items/abfb9f2a672689c20505) (LAN)
- [Twitterの通知をGoogle Homeに教えてもらう](https://kotodama.today/?p=744) (ngrok)
- [Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる（ついでにNode.jsやngrokやらも使ってLINEやGoogle Homeに通知する）](https://qiita.com/miso_develop/items/be562d8a823ad2639d94) (ngrok)
- [新着メールを知らせてくれるGoogle Home](https://qiita.com/tetotetote/items/4d6ac866b716695fa4c9) (Firebase)

##どうやってgoogle-home-notifierに投げるか？
LANから投げるのであれば、
`http://ラズパイのIPアドレス:8080/google-home-notifier`
にPOSTすれば良いだけです。悩むことはありません。

また親切なことに(?)、google-home-notifierはデフォルトで[ngrok](https://ngrok.com/)が使えるようになっていて、WAN(Internet側)から投げる場合も、起動時に表示されるURL
`https://********.nrgok.io/google-home-notifier`
にPOSTすれば、後はngrokのトンネル経由で到達できるようになっています。しかし、ngrokはgoogle-home-notifierを起動する度にURLが変わってしまいます。このためIFTTTのwebhookなどに設定するのには向きません。[^1]

[^1]: NAPTタイマ切れによる切断やグローバルIP変更時の再接続など、確実に接続できる保証もありません。そもそも外界にトンネル張りっぱなしというのも少し不安です。

そうすると、[FirebaseのリアルタイムDB更新とFirebase Listenerを組み合わせ](https://qiita.com/tetotetote/items/4d6ac866b716695fa4c9)が、NAT＋クラウド時代のまっとうな解決方法かもしれません。

…が、固定IPアドレスがあれば、そこに投げれば良いのでは？ ということで

`http://イプシムの固定IPアドレス:8080/google-home-notifier`

に投げる、という安易な解が導き出されました。[^2]

[^2]: Google Homeを自宅LANに接続したくない、という別の理由もありますが…。

#セットアップ
1. ラズパイ＋3GPi＋イプシム
    [anyPi(ラズパイ+3GPi)で固定IPアドレスSIMイプシムを使う](https://qiita.com/ipsim_net/items/9305190478d4f2361389)と、[ラズパイ+3GPiをufw/hostapd/dnsmasqでモバイルWi-Fiルータにして格安SIMで使う](https://qiita.com/ipsim_net/private/bc3a9d14e2b4404d63e6)に従って設定します。

1. Google Home
    Google HomeのMACアドレスを調べて、ラズパイのDHCPサーバでGoogle Homeに恒久的にIPアドレスを割り当てます。

    ```text:/etc/dnsmasq.conf
dhcp-host=XX:XX:XX:XX:XX:XX, GoogleHome, 192.168.168.2, infinite
```

    スマートフォンでGoogle Home側の設定を終わらせます。この時点ですでに『OK, Google』は利用可能です。

1. google-home-notifier
    [Raspberry PiにNode.jsとnpmの最新版をインストールする](https://qiita.com/mascii/items/77c685df65c4cbca9315)を参考に進めます。

    ```
sudo apt-get install nodejs npm
sudo npm cache clean
sudo npm install npm n -g
sudo n lts
```

    最後を`sudo n stable`とすると、v9.0.0がインストールされてしまい、google-home-notifierが動作しませんでした。完了後、バージョンを確認します。

    ```text:node
$ node -v
v8.9.0
```

    ```text:npm
$ npm -v
5.5.1
```

    [google-home-notifier](https://github.com/noelportugal/google-home-notifier)のREADMEにある、Raspberry Piの記載を先に実行します。


    ```
curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
sudo apt-get install nodejs
sudo apt-get install git-core libnss-mdns libavahi-compat-libdnssd-dev
```

    あとはgoogle-home-notifier本体です。

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

    npm install後、READMEに従ってファイルを修正します。

    ```
vi node_modules/mdns/lib/browser.js
```

	```text:node_modules/mdns/lib/browser.js（修正前）
	Browser.defaultResolverSequence = [
	  rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo()
	, rst.makeAddressesUnique()
	];
	```

	```text:node_modules/mdns/lib/browser.js（修正後）
	Browser.defaultResolverSequence = [
	  rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo({families:[4]})
	, rst.makeAddressesUnique()
	];
	```

    設定ファイルを編集します。

    ```
vi example.js
```

    ```js:example.js
//var deviceName = 'Google Home';
var deviceName = '（Google Homeセットアップ時の名前）';
```

    ```
vi google-home-notifier.js
```

    ```js:google-home-notifier.js
//var deviceAddress;
var deviceAddress='192.168.168.2';
//var device = function(name, lang = 'en') {
var device = function(name, lang = 'ja') {
//var googlettsaccent = 'us';
var googlettsaccent = 'ja';
```

#動作確認
1. 起動

    ```
node example.js
```

1. localhost上と同一LAN上から投げてみる

    ```bash:RPi
$ curl -X POST -d "text=ローカルホストからのメッセージ" http://localhost:8080/google-home-notifier
Google Home will say: ローカルホストからのメッセージ
```

    ```bash:無線LAN上の別PC
$ curl -X POST -d "text=同一ネットワークからのメッセージ、漢字や句読点もOK" http://192.168.168.1:8080/google-home-notifier
Google Home will say: 同一ネットワークからのメッセージ、漢字や句読点もOK
```

1. 外から投げてみる
    事前に、ufwで「接続元のIPアドレスから、イプシムの固定IPアドレス：ポート8080への接続」を許可してください。

    ```
sudo ufw allow from [会社のIPアドレス] to [イプシムのIPアドレス] port 8080 proto tcp
```

    ```bash:会社のPC（任意ポートへのPOSTが許可されている方に限ります）
$ curl -X POST -d "text=仕事が終わったので帰ります" http://イプシムの固定IPアドレス:8080/google-home-notifier
Google Home will say: 仕事が終わったので帰ります
```

    簡単！
    iPhoneの[iCurlHTTP](https://itunes.apple.com/jp/app/icurlhttp/id611943891)[^3]でもOKです。
    <img width="375" alt="iCurlHTTP1.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/211762/04dc4db2-a2ae-c25e-3982-c09c2c6edeee.jpeg">

    <img width="375" alt="iCurlHTTP2.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/211762/912b071c-7813-c9fd-7b71-7ad27c2dad8f.jpeg">


[^3]: 設定画面で「Use HTTP2」のチェックを外してください。

#今後の展開

- ちゃんとしたWeb UI/APIを作る。
- Web UI/API経由でgoogle-home-notifierを直接呼び出す。（フロントがあればリスナーは不要）
- 認証を設ける。
- ボイスメッセージを投げて、そのままGoogle Homeに再生させる。