RaspberryPi
3GPI
GoogleHome
ipsim

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

GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいますを参考に、ラズパイ+3GPiイプシムだけで、外出先から自宅のGoogle Homeを喋らせてみます。IFTTT、Firebase、Twitter、Slackなどの外部サービスやngrokなどのトンネルサービスは使いません。

何ができるの?

  • どこでも『OK, Google』(固定回線不要・無線LAN不要)
  • 外から家のGoogle Homeを喋らせる!

準備するもの

  • Raspberry Pi 3 Model B(またはRPi2とUSB無線LANドングルの組み合わせ+追加設定)
  • 3GPi+同梱Raspbian(3gpi2-jessie-20170904)(またはUSBモデム+追加設定)
  • 固定IPアドレスMVNO「イプシム」標準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をラズパイなどで動作させることで、簡単に実現できるようです。なんと「Google Homeに喋らせたいメッセージ」を、google-home-notifierにPOSTで投げるだけで、Google Homeが喋ります。残る問題は、LAN以外からどうやってgoogle-home-notifierに投げるか、だけです。

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

どうやってgoogle-home-notifierに投げるか?

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

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

そうすると、FirebaseのリアルタイムDB更新とFirebase Listenerを組み合わせが、NAT+クラウド時代のまっとうな解決方法かもしれません。

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

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

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

セットアップ

  1. ラズパイ+3GPi+イプシム
    anyPi(ラズパイ+3GPi)で固定IPアドレスSIMイプシムを使うと、ラズパイ+3GPiをufw/hostapd/dnsmasqでモバイルWi-Fiルータにして格安SIMで使うに従って設定します。

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

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

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

  3. google-home-notifier
    Raspberry PiにNode.jsとnpmの最新版をインストールするを参考に進めます。

    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が動作しませんでした。完了後、バージョンを確認します。

    node
    $ node -v
    v8.9.0
    
    npm
    $ npm -v
    5.5.1
    

    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
    
    node_modules/mdns/lib/browser.js(修正前)
    Browser.defaultResolverSequence = [
      rst.DNSServiceResolve(), 'DNSServiceGetAddrInfo' in dns_sd ? rst.DNSServiceGetAddrInfo() : rst.getaddrinfo()
    , rst.makeAddressesUnique()
    ];
    
    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
    
    example.js
    //var deviceName = 'Google Home';
    var deviceName = '(Google Homeセットアップ時の名前)';
    
    vi google-home-notifier.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
    
  2. localhost上と同一LAN上から投げてみる

    RPi
    $ curl -X POST -d "text=ローカルホストからのメッセージ" http://localhost:8080/google-home-notifier
    Google Home will say: ローカルホストからのメッセージ
    
    無線LAN上の別PC
    $ curl -X POST -d "text=同一ネットワークからのメッセージ、漢字や句読点もOK" http://192.168.168.1:8080/google-home-notifier
    Google Home will say: 同一ネットワークからのメッセージ、漢字や句読点もOK
    
  3. 外から投げてみる
    事前に、ufwで「接続元のIPアドレスから、イプシムの固定IPアドレス:ポート8080への接続」を許可してください。

    sudo ufw allow from [会社のIPアドレス] to [イプシムのIPアドレス] port 8080 proto tcp
    
    会社のPC(任意ポートへのPOSTが許可されている方に限ります)
    $ curl -X POST -d "text=仕事が終わったので帰ります" http://イプシムの固定IPアドレス:8080/google-home-notifier
    Google Home will say: 仕事が終わったので帰ります
    

    簡単!
    iPhoneのiCurlHTTP3でもOKです。
    iCurlHTTP1.JPG

    iCurlHTTP2.JPG

今後の展開

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

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

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

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