なんで作ったの?
照明を交換したら、リモコン付きでコントロールできるものだった。眠りかけてからでもリモコンで操作できるから便利である。しかし、リモコンを探して操作するのさえ面倒なひとがいるもので、言うだけで操作できたらなあ、という声が家族の一人からあがった。リモコンすら探したくない、ボタンを押すのさえ面倒に感じるような眠り直前の状況で、果たして元気にコマンドを発声できるのかについては疑問が残るが、ことばで照明操作、というのはよく聞く話なので、自分たちでもやってみることにした。
なにをするもの?
Google Homeに話しかけて、照明をコントロールするというものです。
“Ok, Google.”に続けて、たとえば、”RM 3 command, off“
とGoogle Homeに話しかけると、RM mini 3という名前の、いわゆるスマートリモコンから、あらかじめ学習させておいた”消灯”シグナル(赤外線)が飛んで、部屋の照明を消してくれます。ほかにも以下のコマンドが使えるようにしました。
“RM 3 command” あるいは “Command RM 3″に続けて以下のキーワードを入れて元気に言う。
キーワード | 照明はこうなる |
off | 消える |
on | 全灯 |
dimmer/down | 一段階暗くする |
brighter/up | 一段階明るくする |
warmer/right | 一段階暖かい色にする |
cooler/left | 一段階冷たい色にする |
green/whole | 全灯(もとのリモコンではボタンの色が緑) |
orange/night | 常夜灯(もとのリモコンではボタンの色がオレンジ) |
どういう仕組み?
図にしてみると、結構長い道のりですな。
IFTTTというサービスを使います。このサービスでは、トリガー(引き金)となるイベントと、それが起こった時に何をするか、を結びつけることができます。今回は、Google Homeにある定型文で話しかけたとき、というのをトリガーとして使います。何をするか、の部分は、定型文からGoogle assistantが取り出したキーワードをjsonに詰め込んで家のhttpサーバー(Raspberry pi上で動いている)に向かってPOSTしてもらう、にします。
今回設定した定型文は、”RM 3 command, XXX”です。XXXの部分に”On”とか”Off”とかを入れて話しかけます。うまくいくと数秒でXXXの部分の情報が入ったjsonが家のサーバーに届きます。
サーバーに届いた情報に応じて信号パターンをRM mini 3に送り出すようにします。信号パターンは、照明にもともとついてきたリモコンに、実際の信号を出させて記録しておきます。
使っている技(わざ)
興味のある方は、ここに出てくる文や単語をGoogle検索してさらに調べてみてください。
- blackbeancontrolによるRM mini 3の操作
- IFTTTでappletを作る: Google Assistant + Web hook
- flaskによる簡単なhttpサーバー
作り方
材料
- Google Home Mini (Nest)
Googleアカウントへの紐づけと、LANへの接続ができていること。 - Raspberry pi 3B
- RM mini 3 (Broadlink)
Lazadaから買いました。 - IFTTTアカウント
コンピューター環境
Raspberry piをheadlessにしている場合、コードを書いたりssh接続してRaspberry piを操作するためのPCが必要です。
手順
RM mini 3の準備
ihc (Intelligent Home Center)というアプリで家のLANに接続させます。(アクセスポイントとパスワードをRM mini 3に教える)このアプリから操作することもできますが、いまの目標はGoogle Homeと連携させることなので、これ以降使いません。
あとで、pythonからBlackBeanControlというスクリプトを使って命令を送る際、RM mini 3のIPアドレスが必要です。固定しておいたほうが便利なので、無線ルーターから与えるようにしました。MACアドレスもメモしておきます。
IFTTTでトリガーとアクションをつなぐ
IFTTTのページか、アプリを開き、アプレットを作りました。以下、メモ。トリガーはGoogle Assistant、アクションは、Webhooksです。この二つを連携してもらいます。
- Trigger: Google Assistant
“Say a phrase with a text ingredient” - What do you want to say? : RM3 command $
これが定型文。$のところにくることば(上の図ではキーワード)を拾ってもらいます。 - What’s another way to say it? : Command RM3 $
RM3に命令しろ!って感じです。 - What do you want the Assistant to say in response? : Alright, command $ sent to RM3.
$がどう拾われたか知るために$を文に含めておくと確認になります。 - Language: English
- Action: Make a web request (Webhooks)
- URL: https://xxxxxxxx.ngrok.io/rm3
xxx…の部分は、ngrokから与えられたもの、あるいは有料プランの人は自分で決めた文字列。/のあとのrm3は、このあとflaskでリクエストを受けるための、なんていうんでしょう、宛名です。あとでコードを見てください。 - Method: POST
- Content Type: application/json
- Body: {“command”: ” TextField “}
ここはあとでflaskで受け取って、pythonで処理しますので、dict keyにあたる部分を決めます。今は’command’としました。” TextField “は上で拾った$です。アプリではinsert ingredientsという小さなボタンがあって、そこからTextFieldを選びました。
ここまでで、図の、上半分の準備ができました。次に家の中の部分の準備です。
iniファイルの準備とリモコンシグナルの学習
さて、BlackBeanControlのページから取ってきたフォルダ、たぶん、BlackBeanControl-masterという名前だと思うのですが、この中にあるBlackBeanControl.iniに設定を書き込みます。このファイルを開くと、
[General]
IPAddress =
Port =
MACAddress =
Timeout =
[Commands]
のようになっているはずなので、RM mini 3のIPアドレスと、メモしたMACアドレスをもとに、書き込みをします。Portは80、Timeoutは10(秒)ぐらいでいいと思います。この4つの情報がそろっていないと動きません。
[General]
IPAddress = 192.168.XXX.YYY
Port = 80
MACAddress = AA:BB:CC:DD:EE:FF
Timeout = 10
[Commands]
次に進みましょう。
BlackBeanControl.pyを使ってRM mini 3に指令を飛ばします。しかし、まずは飛ばす指令(赤外線シグナル)がまだ何もありません。用意しましょう。
どうやって?
簡単です。もともとあるリモコンの、使いたいボタンを押して、赤外線シグナルをRM mini 3に読み取らせ、それを記録します。そうなんです、RM mini 3は信号だすだけではなく、読み取ることができるんです。赤外線リモコンのものなら読めるはずです。
読み取りにも、BlackBeanControl.pyを使います。やりかたは簡単で、コマンドラインから、BlackBeanControl-masterにcdして、
python BlackBeanControl.py -c
のあとにつけたいコマンド名を書いてリターン。すぐにリモコンをRM mini 3に向けて学習させたいボタンを押します。
学習した内容は、BlackBeanControl.iniの[Commands]セクションに書き込まれます。-c
オプションのあとに書いたコマンド名と、信号のパターンが記録されます。
ここまできたら、
python BlackBeanControl.py -c 今学習させたコマンド名
で、信号がRM mini 3から飛ぶはずです。
python BlackBeanControl.py -c コマンド
は、”コマンド” がすでにiniファイルにある場合はシグナル送信、ない場合には学習をします。
code
残るは、ngrok経由で飛んできたjsonを受けて、BlackBeanControl.pyを走らせる部分です。ここはpythonにやってもらいます。
flaskというモジュールでサーバーを立ち上げ、外からのPOSTを待ちます。IFTTTで指定した、宛名、/rm3が8行目に見えますね。
from flask import Flask, abort, request
import json
import subprocess
app = Flask(__name__)
@app.route('/rm3', methods=['POST'])
def foo():
print()
print("=== POST received. ===")
print("request.json:")
print(request.json)
if 'command' in request.json:
command_name = request.json['command']
cl_command = ["python2", "PATH_TO/BlackBeanControl.py", "-c", command_name]
subprocess.call(cl_command)
return json.dumps(request.json)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
使ってみて
Google Homeに話しかけてから実際の動作が得られるまで、少し時間がかかりますが、声で何かを操作するというのは、なかなか面白い体験です。ちなみに、Google Homeからではなく、Google Assistantからも同じ定型文でコマンドをだせるので、家の外からもケータイアプリを通じて同じことができます。
こらー、まだ起きてるのか、と子供部屋の照明を強制的に消すこともできます。もちろん彼らも普通のリモコンを使って逆襲できますが、朝まで10秒に一度消灯コマンドを送るプログラム書いて実行、などとしてこちらが寝てしまえば、勝てるはず(やりませんけど)。
このあとの予定
話しかけて操作する、というだけでは芸がない。指で押す、では面倒な、こんなのはどうか、と家族で話しています。
- でかけるぜ、と言うと、家じゅうのエアコン、テレビなどをoffにしてくれる。
- DVDを観たいというと、テレビ、DVDプレーヤーの電源を入れ、入力をDVDプレーヤーに切り替え、おまけにDVDを入れるトレーまで出してくれる。
- 照明は明るさ調節ができる。朝起きるときに、暗い照明から始め、起きる時間に向かって少しづつ明るくしていく、光目覚まし。うーん、これはよさそうですね。特に日の出より前に起きる人には。myToDo listに追加しましょう、これ。
うらばなし
RM mini 3のちょっとした違いに悩まされました。SDKが日本、というのと、美国(アメリカのこと)の二つがあり、今回用いたpython-broadlinkはSDKが日本のものにしか信号を送れないのです。信号学習も同じ。いろいろ調べましたが、同じような目にあっている人もいるようで、さまざまな解決策が議論されていますが、いまのところ、これでいける、という手がないようです。残念。最初に買ったものはうまく動き、ほかの部屋にも、と思って調子に乗って別のディーラーから買った二つがダメ。それでももう一部屋ほしいということで、最初と同じところから取り寄せたらうまくいった。ダメな二つもケータイアプリからはちゃんと動くので、文句は言えない。