Google Home で家電をコントロールしてみる(RM mini + BlackBeanControl + raspberry pi)

こんにちは[Nifty Advent Calendar 2017](https://qiita.com/advent-calendar/2017/nifty) 14日目の記事です。

13日目の@ki-boさんに続き、14日目担当の@harimmasです。
わたしはWEBの企画の仕事をしています。
エンジニアではないのですが、最近開発系のことをいろいろ勉強しはじめています。
今回の記事はその勉強がてら、いろいろなWebの情報を元に試行錯誤したものなので、結構無駄なこと、危険なことが入っているような気がします。
そのあたりを念頭に、よろしくお願いします。
***
先日 Google Home Mini を買いました。
天気予報を聞いたり、ピカチューと会話をしたりしていたのですが、いまひとつ役に立っている感がありません。
ほかに何かできないものかとWEBをあさっていたら、wifiに接続する赤外線リモコンを使って家電製品もコントロールしている記事がいくつか見つかりました。
これができたらちょっと便利かもしれないということで、やってみました。

# 参考にしたWEBサイト
 [Google Homeとスマートホームの組み合わせが超便利で最高すぎる！](http://newstalker.net/review/9448/)

基本的にはこのサイトに書いてあるようにやってみました。
使っていない raspberry pi があるので、ちょうどいいと思ったのですが、それが苦労のはじまりでした。

余っているandroid端末があれば、下記サイトの方法のほうが非常に簡単なのでおすすめです。この方法では raspberry pi は使いません。

- [GoogleHomeで部屋の電気を操作してみた（RM mini3+RM Bridge）](https://sakudai-gadget.blogspot.jp/2017/11/googlehomerm-mini3rm-bridge.html)

# やることの概要
以下のような流れで、音声認識 → リモコン出力します。

- Google Home へ「OK Google、テレビの電源」と発声
- IFTT でGoogleAssistantの音声認識をトリガーにして、webwhooks で raspberry pi に制御情報を送信
- raspberry pi でhttpリクエストを受け取り、eRemoto mini へ赤外線出力コマンドを実行
- eRmote mini から赤外線信号出力

家の中の機器を制御したいだけなのに、インターネットから指令がやってくる形になります。

# 使用機材
- Google Home Mini  
    3,000円でセールをしていたので、衝動買いしてしまいました。
- eRmemoto mini  
    RM mini3 という商品を日本向けにローカライズしたものらしいです。
    RM mini は1300円くらいで売られていたようなのですが、eRemote mini は7千円くらいします。
    入手のしやすから、ちょっと高いですが eRemote mini を選択しました。
- raspberry pi model B（初代）  
    何かに使えそうと買ったものの、ずっと放置してあったもの。

# 設定
## eRemote mini の設定
とりあえずネットワークにつながるように初期設定をします。
同梱のマニュアルにしたがってアプリをダウンロードし、アプリからリモコンが動作するようにしておきます。
このアプリは Google Home に対応していないので、以下の作業でこのアプリ自体は使いません。

## raspberry pi の設定
rspberry pi から eRemote mini をコントロールするための設定を行います。

そのためにはBlackBeanControlというものを利用すればいいいとのこと。

### BlackBeanControl の設定
設定方法については参照したWebサイトに記載されていなかったので、BlackBeanControlの説明を読みながら進めていきます。
https://github.com/davorf/BlackBeanControl

Installation を読むと、いろいろなものが必要みたいなので、まずはそのインストールをすすめていきます。

その前に下準備。raspberry piを最新の情報に更新します。
`apt-get update`

インストールをする前に全体をざっと確認すると、使うのはpythonの２系みたいなので、２系で準備を進めていきます。

`sudo apt-get install python-dev`
なにか開発に必要なものなのでしょう。
`pip install configparser`
configをパースするのに便利なライブラリなのかな。
`pip install netaddr`
IPアドレスやMACアドレスを扱うのに便利なものらしい。
`pip install pycrypt`
たぶん暗号関係なのでは？

あとは、`python-broadlink package`をgithubから探して、`setup.py`でインストールしろということ。

https://github.com/mjg59/python-broadlink

ここから必要なファイルをダウンロードして、
`python setup.py install`
すると、インストールディレクトリのpermissionがないとかなんとかいってエラーがでたので、`sudo`をつけてみた。
`sudo python setup.py install`
こんどは成功。

下準備が整ったので、今度は BlackBeanControl のファイルをダウンロード。
今回は`/home/hoge/`の下にBBCというフォルダをつくって、ダウンロードしたものをすべておきました。

つぎに、`BlackBeanControl.ini`に必要な情報を記載します。
エディタで開いて、General セクションに eRemoto mini のIPアドレスとMACアドレスを記載します。

```
[General]
IPAddress = 192.168.0.7
Port = 80
MACAddress = 34:x:xx:xx:xx:xx
Timeout = 10
```
eRemote mini のIPアドレスとMACアドレスはネットワーク機器の情報を表示するフリーソフトで調べておきます。
Timeoutはリモコンを学習させるための時間なので、10秒くらいでよさそうです。

これでリモコンを動かすには、`python BlackBeanControl.py -c コマンド名`
と打てば良いらしい。

`BlackBeanControl.ini`にコマンド名が記載ない場合には、リモコンを記憶するモードになるとのこと。そこで eRemote mini にむけて覚え込ませたいリモコンボタンを押すと、iniにコマンド名とリモコンの内容が記録されるようです。
iniにコマンド名がある場合には記憶したリモコンの赤外線を発射してくれるようです。

それでは、テレビの電源ボタンを`tv_power`というコマンド名で登録してみます。

`python BlackBeanControl.py -c tv_power`
すかさず eRemote mini にテレビのリモコンを向けて電源ボタンを押します。
すると、permissionエラーがでてしまいました。書き込みの権限がないと怒られているようです。

なので、`BlackBeanControl.ini`のパーミッションを変更してみます。
`sudo chmod 777 BlackBeanControl.ini`
このパーミッションであっているのか、正直わからないのですが、とりあえずこれでやってみると今度は成功したようです。

`BlackBeanControl.ini`の中身を確認すると、以下のようにCommandsセクションにデータが追加されていました。

```
[Commands]
tv_power = 260032017337110c1029100c110c100c110c100c110c100c110c110b110c110b1129100c110c100c110c100c110c100c110c100c1128110c100c110c100c110c100c110c110c1029100c1128112811281128110c100c1128110c1029112811281128110c10291000098e7436110c1029110c100c110c100c110c100c110c100c110c100c110c1029100c110c100c110c110b110c110c100c110c1029100c110c100c110c100c110c100c110c1029100c1128112811281129100c110c1029100c1128112811281128110c10291100098d72390f0d0f2a0f0e0e0e0e0f0f0d0f0e0f0d0f0e0e0e0f0e0e0f0f0d0e2b0f0e0e0e0f0e0e0e100d0e0e100d0f0d0f0e0f2a0f0d100a120d100d0f0d100d0f0e0f0d0f2a100d1029102910291029100c110c1029110b1129102910291029100c112811000d05000000000000
```

もう一度`python BlackBeanControl.py -c tv_power`とたたくと、TVの電源がきれました。

raspberry pi でコマンドをたたくと、家電リモコンの操作ができるようになりました。

しかし、IFTTT からコントロールするためには、httpでアクセスしたらこのスクリプトが動くようにする必要があります。
どうやるんでしょう？？？

### httpでアクセスされたらコマンドを実行する
いろいろ検索をすると、下記のようなコマンドをたたくと、httpサーバーとして動作するようです。

`python -m SimpleHTTPServer 8000`

ブラウザから raspberry pi のIPへアクセスしてみると、たしかに表示ができているようです。
でも今回やりたいことに直接つながらないような気がします。

この間フレームワークをほんの少し勉強したので、bottle をいれれば解決しそうな気もするのですが、もう少し手軽にできないかさらに調べていると、こんな記事を見つけました。

- [Pythonで簡単にHTTPサーバを作る](https://qiita.com/shinido/items/b4fdc907a37424bcf15b)

`http://localhost:12345/?hoge=123`にアクセスすると`hoge=123`と出力されるコードが掲載されていました。
ばっちりです。
ポートが変えられるようになっているのも素敵です。

これをすこし改変して`http://localhost:12345/?hoge`にアクセスすると、`python BlckBeanControl.py -c hoge`が実行できるようにできそうです。

pythonから別のpythonコマンドを実行する方法がわかれば実装できそうなので探してみます。

ありました。

- [pythonからpythonを実行する方法(exec)](http://motibe.littlestar.jp/blog/2017/02/07/031837/)

``` python
import subprocess
path = “d:\test.py”
subprocess.call(“python %s” % path)
```
こんなかんじで良いみたいです。

これをもとに、コードを書いてみます。

``` python:h2b.py
# coding:utf-8

import sys
import CallbackServer
import subprocess

path = “python /home/hoge/BBC/BlackBeanControl.py -c ”

def callback_method(query):
    subprocess.call(path + query,shell=True)
    return ['Hello', 'World!', 'with', query]

if __name__ == '__main__':
    port = sys.argv[1]
    CallbackServer.start(port, callback_method)
```
`CallbackServer.py`は、[こちらのサイト](https://qiita.com/shinido/items/b4fdc907a37424bcf15b)のコードをそのままコピーして同じフォルダにおいておきます。

ためしに実行してみます。
`python h2b.py 8030`

これでraspberry pi は待ち受け状態になりました。

ブラウザから`http://localhost:8030/?tv_power`と入力すると、ブラウザには以下の文字が表示されました。

```
Hello
World!
with
tv_power
```
そして、テレビの電源も無事動きました。

## ルーターでポートマッピングの設定
外部からアクセスできるように、ルーターに穴をあけます。
ポートマッピングの設定でポート番号 8030へのアクセスが raspberry pi へ行くように設定します。

```
LAN側ホスト：192.168.0.222　　→　raspberry pi のIPアドレス
プロトコル：TCP
ポート番号：8030-8030 
```

これで外部から8030のポートにアクセスがきたら、raspberry pi のところに行くはずです。
確認君のサイトで自分の家のグローバルIPアドレスを確認して、外の環境からアクセスしてみます。
スマホ(モバイル通信)のブラウザで`http://自宅のIPアドレス:8030/?tv_power`と入力。
すると、先ほどの文字列が表示され、無事TVの電源がおちました。

## IFTTTの設定
つぎはIFTTの設定です。

新しいアプレットを作成します。
this の部分にGoogleAssistant の `Say a simple phrase` を選択します。
`What do you want to say?`のところに「テレビの電源」
`What do you want the Assistant to say in response?`に「わかりました」
`Language`に日本語を設定
でCreate triggerします。

続いてthat の部分にwebhooksを選択。
`URL`に`http://自宅のIPアドレス:8030/?tv_power`を入力
`Method`は`GET`
Create actionします。

これですべての準備が整いました。
Google Home にむかって「OK Google、テレビの電源」というと、「わかりました」の返答とともにTVの電源操作ができるようになります。

インターネットをはるばる経由してリモコンが動いているはずなのですが、それほどタイムラグは感じません。

# 今後のこと
PCから raspberry pi に ssh でアクセスして設定しているのですが、ターミナルを閉じるとリモコンの受付ができなくなってしまいます。
raspberry pi から直に実行すれば、とりあえずは良さそうですが、根本的にはサービスとして動作させるようにすると、この問題はクリアできるようです。

また、いまの仕様だとリモコンのボタン毎にIFTTTのレシピ登録が必要なので、登録するのが面倒です。
トリガーの部分を`Say a phrase with a text ingredient`にすると、Google Home への命令に変数が使えるようになるので、命令のセリフを「テレビの操作 $」などにして、まとめるとよさそうです。
それにともなって、命令を受け取るプログラムのほうに、用意された操作以外は受け付けない処理を追加しないといけないですね。

# 感想
せっかく苦労したものの、リビングだと声でリモコン操作する必要性というのがあまり感じられませんでした。
なので、寝室に移そうかと思っています。
寝室で寝転がりながら部屋の照明とエアコンが声で操作できるのは、それなりに便利そう。
ついでに IFTTT で時間をトリガーにして、朝起きる時間にエアコンと照明をつけるのも簡単にできそうです。
***
明日の記事は@nokiyu_oOさんです。よろしくお願いします。