LoginSignup
112
123

More than 5 years have passed since last update.

Google AssistantとRaspberry Piで自宅の家電を操作する

Last updated at Posted at 2017-10-29

いきさつ

Google Homeが流行っているので、Google Assistantから自宅の家電を操作したいと思いました。IRKitを使うのが簡単そうです(IFTTTとIRKitでGoogleHomeから家電をコントロールするなど)が、IRKitは、2017/10/25現在Amazonでの販売(IRKit - iPhone,iPadを使って外出先からエアコン等の家電を操作できる学習リモコン
)が終了しています。

image.png

後継機のNature RemoはIFTTTを用いてGoogle Home等とすぐ接続できて簡単な半面、若干値段が高い。代替案を探していたところ、RaspberryPiから操作可能な赤外線リモコンモジュールを見つけたので、こちらを使って実現してみました。

システム構成

無題のプレゼンテーション.png

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が確認できます。

image.png
image.png

作成したチャネル名、リソース名、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が受け取ったデータは、以下の手順でコンソール上で確認ができます。
1. Beebotteのコンソール画面の「Account Settings」の「Credentials」からSecret Keyを取得
2. このSecret Keyを「Console」の「Secret Key」に入力し、Subscribeのパネルにチャネル名とリソース名を入れて、「Subscribe」を押下
3. 前述のcURLでメッセージを送信
4. 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と同じディレクトリに入れてください。

app.py
#!/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を買った方が良いかもしれないです。

参考サイト

以下のサイトを参考にさせていただきました。ありがとうございます。

112
123
10

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
112
123