家studyをつづって

IT技術やセキュリティで勉強したことをつづっています。

AlexaでSwitchbotを操作する

概要

Switchbotは普通の(アナログの)スイッチを「押す」という動作を行ってくれるデバイスです。

 

 

スマートフォンのアプリや、専用のコントローラからBluetooth経由で操作ができるのですが、今回はすでに自宅にあるAlexaに呼びかけることで、Switchbotを操作できるような仕組みを作りました。

概要は以下の通りです。

f:id:iestudy:20200402135404p:plain

一連の流れ

MQTTとは

MQTTとはMessage Queue Telemetry Transportの略で、publish/subscribeモデルという仕組みに基づいてつくられた軽量なメッセージプロトコルです。
ネットワークが不安定な場所や、性能が低いデバイスでも動くように軽量化されているのが特徴です。

Publish/Subscribeモデルとは

  • MQTTではデータの送受信をPublisher(送信者)、Subscriber(受信者)の2つの役割にわけて行います。
  • PublisherはMQTTブローカーにデータを送信します。
  • SubscriberはMQTTブローカーにデータを受信しに行きます。

上記により非同期通信を実現しています。また、PublisherとSubScriberはMQTTブローカーを介在するので多対多の通信が可能です。

 

構築の流れ

MQTTブローカーの設定

BeebotteというMQTTブローカーを使用しました。

  1. ChannelとResourceの作成
    「Channels」-「Create New」 より、「Channel Name」と「Resource name」を入力してチャネルを作成します。
  2. トークンの取得
    1で作成されたChannelをクリックするとトークンが表示されるのでメモしておきます。
  3. 動作テスト
  • 「Account Setting」-「Access Management」より、「Secret Key」を確認します。
  • 「Console」で「Secret Key」を入力し、「Subscribe」で「Channel name」及び 「Resource name」を入力します。
  • Linux端末(用意したRaberry Pi等)から以下のコマンドを実行し、Messagesと Logsに実行内容が表示されれば試験完了です。

curl -i -H "Content-Type: application/json" -X POST -d '{"data":"Hello World"}' http://api.beebotte.com/v1/data/publish/[Channel名]/[Resource名]?token=[トークン]

 
また、Beebotteの証明書をダウンロードします。

wget https://beebotte.com/certs/mqtt.beebotte.com.pem

 

RaspberryPiの設定

RaspberryPiにPythonプログラムをデーモンとして常駐させます。

今回は自宅にあったRasberry Pi3を使用しました。

先ほどのBeebotteの証明書と以下のソースコードを、「/usr/local/lib/switchbot/」に配置します。

/usr/local/lib/switchbot/switchbotd.py
import os
import sys
import time
import json
import logging
import time
import paho.mqtt.client as mqtt
import binascii
from bluepy.btle import Peripheral
TOKEN = "Beebotteのトークン"
HOSTNAME = "mqtt.beebotte.com"
PORT = 8883
TOPIC = "Beebotteのチャンネル名/Beebotteのリソース名"
CACERT = "/usr/local/lib/switchbot/mqtt.beebotte.com.pem"
SWITCH_MAC = "スイッチボットのMACアドレス"
SWITCH_NAME = "スイッチボットの名前"
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG,format='%(asctime)s- %(name)s - %(levelname)s - %(message)s')
_LOGGER = logging.getLogger(__name__)
class SwitchBot:
def __init__(self, name, mac):
self._mac = mac
self._name = name
def action(self, act):
for connection in range(1,6):
try:
p = Peripheral(self._mac, "random")
except:
_LOGGER.error('Connection attempt failed after {connection} tries')
time.sleep(1)
continue
break
else:
_LOGGER.error('Connection to Switchbot failed')
try:
hand_service = p.getServiceByUUID("cba20d00-224d-11e6-9fb8-0002a5d5c51b")
hand = hand_service.getCharacteristics("cba20002-224d-11e6-9fb8-0002a5d5c51b")[0]
if act == "on":
hand.write(binascii.a2b_hex("570101"))
elif act == "off":
hand.write(binascii.a2b_hex("570102"))
elif act == "press":
hand.write(binascii.a2b_hex("570100"))
p.disconnect()
except:
_LOGGER.error("Cannot connect to switchbot.")
switch_bot = SwitchBot(SWITCH_NAME, SWITCH_MAC)
def on_connect(client, userdata, flags, respons_code):
print('status {0}'.format(respons_code))
client.subscribe(TOPIC)
def on_message(client, userdata, msg):
data = json.loads(msg.payload.decode("utf-8"))["data"][0]
data = {key:value.strip() for key, value in data.items()}
if "action" in data.keys():
switch_bot.action(data["action"])
def fork():
pid = os.fork()
if pid > 0:
f = open('/var/run/switchbotd.pid','w')
f.write(str(pid)+"\n")
f.close()
sys.exit()
if pid == 0:
main()
def main():
client = mqtt.Client()
client.username_pw_set("token:%s"%TOKEN)
client.on_connect = on_connect
client.on_message = on_message
client.tls_set(CACERT)
client.connect(HOSTNAME, port=PORT, keepalive=60)
client.loop_forever()
if __name__=='__main__':
fork()

サービスとして起動するために以下のファイルを作成します。

/etc/systemd/system/switchbotd.service
[Unit]
Description=SwitchBot

[Service]
ExecStart=/usr/bin/python3 /usr/local/lib/switchbot/switchbotd.py
Restart=always
Type=forking
PIDFile=/var/run/switchbotd.pid

[Install]
WantedBy=multi-user.target

また、上記を事項する際にいくつかエラーが出ました。必要なモジュールが不足していたために出たものですが、以下のコマンドを実行しました。

pip3 install paho-mqtt python-etcd
pip3 install bluepy

 

IFTTTの設定

IFTTTの「this」の設定で「Alexa」を指定します。「Say a specific phrase」を選択します。ここで設定したフレーズではAlexaに呼びかけません。

 

「that」の設定で「WebHook」を指定し、以下を設定します。

  • URL:http://api.beebotte.com/v1/data/publish/[Channel名]/[Resource名]?token=[トークン]
  • Method:POST
  • Content Type:application/json
  • Body:{"data":[{"room":"living","device":"電気","action":"on"}]}

最終的に、以下のような設定となります。

f:id:iestudy:20200404224607p:plain

IFTTTの設定

 

Alexaの設定

  • Alexaアプリから「定型アクション」をタップします。
  • 定型アクション名に任意の名前を入力し、実行条件を設定をタップします。
  • 開始フレーズを設定から定型アクションを実行するためのフレーズを設定します。
    ※ここで設定した内容でAlexaに呼びかけます。
  • アクションを追加の+をタップし、IFTTTを選択します。
  • 前工程で作成したIFTTTのアプレットを追加します。
    (アプレットの名前ではなくフレーズが表示されます。)

ここまで設定が完了すると、Alexaアプリで設定したフレーズでswitchbotが操作されます。

 

参考にさせていただいたサイト

qiita.com

qiita.com