いきさつ
Google Homeが流行っているので、Google Assistantから自宅の家電を操作したいと思いました。IRKitを使うのが簡単そうです(IFTTTとIRKitでGoogleHomeから家電をコントロールするなど)が、IRKitは、2017/10/25現在Amazonでの販売(IRKit - iPhone,iPadを使って外出先からエアコン等の家電を操作できる学習リモコン
)が終了しています。
後継機のNature RemoはIFTTTを用いてGoogle Home等とすぐ接続できて簡単な半面、若干値段が高い。代替案を探していたところ、RaspberryPiから操作可能な赤外線リモコンモジュールを見つけたので、こちらを使って実現してみました。
システム構成
Google Asistantがユーザからの特定の発話を受け取ると、IFTTTをトリガーします。
IFTTTからRapberry Piまでの経路(②,③)ですが、IFTTTのMaker Channelでは、アクションとして外部のウェブサーバに対してウェブリクエストを送信するwebhookがあります。そのため、Raspberry Piをwebサーバにし、ドメイン取得&ポート解放するなどして、グローバルにアクセスできるようにするなどの方法が考えられますが、サーバを公開できないような環境(特に自宅LANなど)も多いと思います。そこで今回は、IFTTTがMQTTブローカーBeebotteにREST APIでメッセージを保存し(②)、Raspberry Piがこのブローカーにメッセージを取得しに行く(③)、という形式をとる事にしました。
各要素の概要と選定理由
- MQTTブローカ: Beebotte
- 1日あたりのメッセージ数が50,000個まで無料(その他条件あり)
- RESTとMQTTの両方から利用可能
- 赤外線リモコンモジュール: ADIR01P
- Raspberry Piで動作している例がある
- 出力が強そう
1. Beebotte設定
Beebotteのサイトでアカウントが作成が完了したら、コンソールパネル上でチャンネルとリソースを作成します(②でメッセージをポストする際のURLの構成要素になります)。作成完了後、コンソールのホームから作成したチャンネルにアクセスするためのChannel Tokenが確認できます。
作成したチャネル名、リソース名、Channel Tokenを用いて、以下のようにcURLで動作確認できます。
curl -i -H "Content-Type: application/json" \
-X POST -d '{"data":"Hello World"}' \
http://api.beebotte.com/v1/data/publish/<channel名>/<リソース名>?token=<Channel Token>
Beebotteが受け取ったデータは、以下の手順でコンソール上で確認ができます。
- Beebotteのコンソール画面の「Account Settings」の「Credentials」からSecret Keyを取得
- このSecret Keyを「Console」の「Secret Key」に入力し、Subscribeのパネルにチャネル名とリソース名を入れて、「Subscribe」を押下
- 前述のcURLでメッセージを送信
- Messagesに送信したメッセージが表示される
2. IFTTTの設定
あらかじめ、IFTTTのMaker Channelのサイトにアクセスして、有効にしたうえで、以下のようなレシピで新しいAppletを作成します。
- トリガー: Google Assistant/Say a simple phrase with a text ingredient
項目 | 設定値 |
---|---|
What do you want to say? | リビングの $ つけて |
What do you want the Assistant to say in Respponse | リビングの $ をつけます |
Language | Japanese |
Google Assistantのフレーズが$
から始められないため、「リビング」と入れています。
- アクション: Webhooks/Make a web request
項目 | 設定値 |
---|---|
URL | http://api.beebotte.com/v1/data/publish/<channel名>/<リソース名>?token=<Channel Token> |
Method | POST |
Content Type | application/json |
Body | { "data": [{"room": "living","device": "{{TextField}}","action":"on"}]} |
トリガーで受け取った$
が{{TextField}}に入ります。
上記の設定完了後、Google HomeやGoogle Assistantに「リビングのテレビつけて」と言った際に、前述のBeebotteのコンソールで以下のメッセージが確認できれば、動作確認終了です。
{ "channel": <チャンネル名>, "resource": <リソース名>", "eid": xxxx, "data": [ { "room": "living", "device": " テレビ", "action": "on" } ] }
3. ADIR01Pの接続とリモコン信号の学習
ADIR01PとRaspberry PiをUSBで接続し(mini USBなので注意)、動作確認・リモコン信号の学習を行います。今回はRaspberry Pi3 Model Bを利用しました。
ADIR01PはUNIX系環境用コマンドラインツールが公開されていますので、それをダウンロードし、コンパイルして利用します。Raspberry Pi上からダウンロードできなかったので、他のマシンでダウンロードしてからSCPでコピーしました。libusbも必要なので、インストールしてください。
$ unzip bto_advanced_USBIR_cmd.zip
$ cd bto_advanced_USBIR_cmd
$ sudo apt-get update
$ sudo apt-get install libusb-1.0.0
$ make
$ sudo make install
コマンドラインツールbto_advanced_USBIR_cmd
が作成されるはずです。
次に、以下の手順で受信を開始し、ADIR01Pに赤外線リモコンから信号を発射することで、信号を受信・保存することができます。
$ bto_advanced_USBIR_cmd -r # 受信開始
# 次に記録したい機器の赤外線を、受信部に向けて、発射します。
$ bto_advanced_USBIR_cmd -s # 受信停止
$ bto_advanced_USBIR_cmd -g | tee living_light_on.txt # ファイル保存
living_light_on.txtに信号が保存されます。今回は証明用のリモコンを記録させました。
4. Raspberry PiでのMQTT受信と赤外線信号送信
Pythonを使って、MQTT受信と赤外線信号送信用のスクリプトを作ります。今回用いたpythonと依存パッケージのバージョンは以下の通りです。
- Python 3.4.2
- paho-mqtt==1.3.1
以下のファイルを先ほど作成したliving_light_on.txt
と同じディレクトリに入れてください。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt
import json
import subprocess
import os
_TOKEN = 'XXXXXXXXXX' #IFTTTに設定したものと同じChannel Tokenを設定
HOSTNAME = 'api.beebotte.com'
PORT = 1883 #SSLの場合は8883
TOPIC = 'YYYYYYY/ZZZZZZZZZZZ' #トピック名/リソース名 の形で設定
# 名詞の変換表
noun_conv = {
"照明": "light",
"ライト": "light",
"らいと": "light",
"しょうめい": "light",
"ショウメイ": "light",
"証明": "light"
}
# 接続中の処理を記載→subscribeする
def on_connect(client, userdata, flags, respons_code):
print('status {0}'.format(respons_code))
client.subscribe(TOPIC)
# メッセージ受信時の処理を記載
def on_message(client, userdata, msg):
print(msg.topic + ' ' + str(msg.payload))
data = json.loads(msg.payload.decode("utf-8"))["data"][0]
# Google Assistantの側でTextFiledの前後に半角スペースが入ることがあるのでstripして削除
data = {key:value.strip() for key, value in data.items()}
if "room" in data.keys():
# 「証明を」と言ってしまった際に「を」が入ってTextFieldに入ってくることがあるので削除
if data["device"].endswith("を"):
data["device"] = data["device"][:-1]
# 日本語の表記ゆれに併せて、IFTTTのTextFieldをlightに修正
if not data["device"] in set(noun_conv.values()):
try:
data["device"] = noun_conv[data["device"]]
except:
print("unkown device")
return
fname = "%s_%s_%s.txt"%(data["room"],
data["device"],
data["action"])
if os.path.exists(fname):
signal = open(fname).read()
subprocess.call(['bto_advanced_USBIR_cmd', '-d', signal])
if __name__ == '__main__':
client = mqtt.Client()
#トークンを使って認証
client.username_pw_set("token:%s"%_TOKEN)
client.on_connect = on_connect
client.on_message = on_message
client.connect(HOSTNAME, port=PORT, keepalive=60)
# 待ち受け状態にする
client.loop_forever()
app.py
の入ったディレクトリで以下を実行すると、MQTTの待ち受けが開始されます。
$ python3 app.py
5.動かしてみる
Google HomeやGoogle Assistantに「リビングのライトつけて」と言うと、リビングのライトが無事つきました。
Google AssistantにIFTTT, Beebotteなどのサービスを組み合わせると、簡単に音声でのリモコン操作が実現できました。
ただ、RaspberryPiとirMagicianの料金を合わせると、Nature Remoとほぼ変わらないような値段になってしまいました。すでにある機材を組み合わせたい場合などを除いた方が、Nature Remoを買った方が良いかもしれないです。
参考サイト
以下のサイトを参考にさせていただきました。ありがとうございます。