💡

SORACOM LTE-M Button Powerd by AWSを使ってSwitchBotを動かしてみた

2021/12/11に公開

AmazonのブラックフライデーセールでSwitchBotを買いました。

このSwitchBotは、BLE APIがオープンになっているのでプログラムで制御することができます。

なのでRaspberry Piを使ってSwitchBotを触ることができます。

https://twitter.com/k_miura_io/status/1466059911104585734

で、これを試したときにせっかくRaspberry Piを使ってるならMQTTブローカーを立てて遠隔でSwitchBotを操作できそうだと思いました。

そして、遠隔操作でパッと思いついたのが以前使ってたSORACOM LTE-M Button powered by AWSです(ちなみに商品ページのリンクにある活用レシピの中の打刻の話は僕の執筆したやつです)。

というわけで今回は、このSORACOM LTE-M Buttonを使ってSwitchBotを動かしてみました。

システム構成

ボタンを押されたら、Lambda関数を呼び出してSORACOM BeamにPublishします。

Publishしたデータは、SORACOM BeamのMQTTアドレスでRaspberry Piに転送されることでSwitchBotを操作できるようにしていきます。

用意するもの

  • SwitchBot
  • Raspberry Pi(今回はRaspberry Pi3 model B+を使っています)
  • SORACOM LTE-M Button powered by AWS
  • USBドングル(SORACOM Airを使用する場合、SORACOM Arcを使っている場合は不要です)

AWS IoT Coreの設定

まずは、AWS IoT CoreでSORACOM Beamに接続するための設定を行います。

モノの作成

  1. モノを作成 からAWS IoTで使用するデバイスを登録します。

  2. 1つのモノを作成 を選択して 次へ をクリックします。

  3. モノの名前を任意のものに設定して 次へ をクリックします。

  4. 今回はポリシーを新規で作成するので、スキップして、モノの作成 をクリックします。

  5. 新しい証明書を自動生成 を選択して 次へをクリックします。

  6. デバイス証明書とプライベートキーファイルは必要なのでここで忘れないようにダウンロードします。(パブリックキーファイルは必要ではありませんがダウンロードしないと終わらないので一緒にダウンロードします。)
    また、ルートCA1ファイルも必要になるので合わせてダウンロードします。

ポリシーの作成

  1. 左のメニューから ポリシー を選択して 作成 をクリックします。

  2. 設定内容を記入して、作成 をクリックします。

  • 名前 : PubSubToAnyTopic
  • アクション : iot:*
  • リソース ARN :  *
  • 効果 : 許可をチェック
  1. 左のメニューから 証明書 をクリックして作成した証明書を選択して ポリシーのアタッチ をクリックします。

  2. 作成したポリシーを選択して アタッチ をクリックします。

  3. 左のメニューから 設定 をクリックしてデバイスデータエンドポイントメモします。

SORACOM Beamとの連携

  1. 設定するSIMに紐付いたSIMグループを選択して SORACOM Beam設定を開く

  2. MQTTエントリポイント を選択

  3. 転送先を設定します。

  • プロトコル:MQTTS
  • ホスト名:AWS IoT Coreの設定からコピーしたエンドポイント
  • ポート番号:8883
  1. 証明書を有効にして証明書を設定できるようにする

証明書の認証情報入力

  • 認証情報:任意のものでOK
  • 秘密鍵のテキストボックス:{ランダム文字列}-private.pem.key の内容
  • 証明書のテキストボックス:{ランダム文字列}-certificate.pem.crt の内容
  • CA 証明局のテキストボックス:Amazon ルート CA の内容

入力したら 保存をクリックしてBeamの設定が完了します。

IMSIの確認

MQTTのトピックで必要になるので、SORACOMのユーザーコンソールで今回使用するSIMの詳細を開いてIMSIを確認し、メモしておきます。

Raspberry Piの設定

SIMの設定

Raspberry PiからSORACOMのプラットフォームに接続するための設定を行います。

ドングルを使ってセルラー通信をやるならsetup_air.shSORACOMのユーザーサイトからダウンロードして実行します。

Wifiのみで通信をやるなら、SORACOM Arcのセットアップを行います。セットアップはこちらのブログを参考にしてもらうとすぐに試せると思います(僕の書いた記事ですがw)。

環境構築

Raspberry Piに必要なソフトウェアをインストールします。

$ sudo apt-get update
$ sudo apt-get install python3-pip
$ sudo apt-get install python3-dev
$ sudo apt-get install python3-setuptools
$ sudo apt-get install libboost-python-dev
$ sudo apt-get install libboost-thread-dev

次にPythonのライブラリをインストールします。
AWS IoTでSubscribeするには専用のSDKを使いますが、今回はSORACOM BeamのMQTTでSubscribeするのでSDKを使わず、paho-mqttをインストールします。
そして、SwitchBotは公式のレポジトリではpybluezを使った方法が紹介されていますが、調べてみたらサードパーティーで公開されている専用のライブラリがあったのでそっちを使います。

$ sudo pip3 install paho-mqtt
$ sudo pip3 install switchbotpy

コードの用意

環境構築したところで、Subscriberのコードを用意します。

ファイル名はsubscriber.pyとします。

<DEVICE_MAC_ADDR>はお使いのSwitchBotのMACアドレスに書き換えます。

{{imsi}}はプレースホルダーになっているので、接続しているSIMのものに書き換えなくても大丈夫です。

#!/usr/bin/env python3                                       
import json                                                  
import subprocess                                            
import paho.mqtt.client as mqtt                              
from switchbotpy import Bot                                  
from switchbotpy.switchbot_util import SwitchbotError        
                                                             
device_addr = '<DEVICE_MAC_ADDR>'                            
bot = Bot(bot_id=0, mac=device_addr, name='bot0')            
                                                             
def on_connect(clinet, user_data, flag, rc):                 
    print("Connect with result code {}".format(rc))      
    clinet.subscribe("switchbot/{{imsi}}")               
                                                             
def on_disconnect(client, userdata, flag, rc):               
    if rc != 0:                                          
        print("Unexpected disconnection.")           
                                                             
def on_message(client, userdata, msg):                       
    data = json.loads(msg.payload.decode('utf-8'))       
    print("Reseaved: {}".format(data))                   
    cmd = data['command']                                
                                                            
    switch_cmd = None                                    
    if cmd == 'on':                                      
        switch_cmd = True                            
    elif cmd == 'off':                                   
        switch_cmd = False                           
    elif cmd == 'reboot':                                
        subprocess.run(['sudo', 'reboot'])           
                                                            
    if switch_cmd is not None:                           
        print('Send Command')                        
        try:                                         
            bot.switch(switch_cmd)               
        except SwitchbotError:                       
            print('Command Falied')              
                                                             
client = mqtt.Client()                                       
client.on_connect = on_connect                               
client.on_disconnect = on_disconnect                         
client.on_message = on_message                               
                                                             
if __name__ == "__main__":                                   
    try:                                                 
        client.connect("beam.soracom.io", 1883, 60)  
        client.loop_forever()                        
    except KeyboardInterrupt:                            
        pass                                         

上記のコードを保存して以下のコマンドを実行します。

$ python3 subscriber.py

コンソールに以下のように表示されていればSORACOM Beamに接続できています。

もし接続エラーが出た場合は、SIMの設定ができていない可能性があるので、ping pong.soracom.ioを実行してSORACOMのプラットフォームに接続できているか確認してください。

Connect with result code 0

このあとLambdaからのPublishできるか確認するため、接続状態にしておきます。

Lambda関数の用意

今度はボタンを押したときに実行するLambda関数を用意します。

IAMロールを作成

関数を作成する前にAWSでLambdaのアクセス権限を設定するIAMロールを作成します。

AWSのIAMコンソールを開いて、IAMロールを作成します。

ユースケースから Lambda を選択して、次へすすむ。

アクセス権は AWSIoTWirelessFullPublishAccessAWSLambdaBasicExecutionRole を設定します。

タグはスキップでOKです。

ロール名は lambdaIoTPublish にして後は設定内容に問題なければ ロールの作成 をクリックします。

Lambda関数を作成

作成したIAMロールを使ってLambda関数を作成します。以下の内容で設定します。

  • 関数名: buttonTrigger
  • ランタイム:Python3.9
  • アクセス権限:既存のロールから lambdaIoTPublish を選択
import os
import json
import boto3

iot = boto3.client('iot-data', region_name='ap-northeast-1')

def lambda_handler(event, context):
    # 押されたときのアクションを取得
    click_type = event['deviceEvent']['buttonClicked'].get('clickType')
    print("clickType: {}".format(click_type))
    
    # プレイスメントの値を取得
    cmd = event['placementInfo']['attributes'].get(click_type)
    imsi = event['placementInfo']['attributes'].get('DEVICE_IMSI')
    
    try:
        # 受け取ったメッセージをデバイスへPublish
        pub_msg =  {
            'command': cmd
        }
        iot.publish(
            topic = "switchbot/{}".format(imsi),
            qos = 0,
            payload = json.dumps(pub_msg)
        )
    except Exception as e:
        print(e)
        raise e
    
    return {
        'statusCode': 200,
        'body': 'Success Call'
    }

関数のテスト

それでは、メッセージがPublishされるかテストをしてみます。

テストのイベントデータとして、以下のJSONを使います。

DEVICE_IMSIはSORACOMでお使いのSIMのIMSI番号に書き換えます。

{
  "deviceEvent": {
    "buttonClicked": {
      "clickType": "SINGLE",
      "reportedTime": "2018-05-04T23:26:33.747Z"
    }
  },
  "deviceInfo": {
    "attributes": {},
    "type": "button",
    "deviceId": " G030PMXXXXXXXXXX ",
    "remainingLife": 5
  },
  "placementInfo": {
    "projectName": "TestProject",
    "placementName": "button1",
    "attributes": {
      "DEVICE_IMSI": "123456789012345",
      "SINGLE": "on",
      "DOUBLE": "off",
      "LONG": "reboot"
    },
    "devices": {
      "myButton": " G030PMXXXXXXXXXX "
    }
  }
}

テストイベントを用意したらLambdaのテストを実行します。

実行後、Raspberry PiのコンソールにPublishされたメッセージが表示されたら正常に通信できています。そして受け取ったメッセージで手元のSwitchBotも動作していれば問題ありません(たまにSwitchBotとの接続を失敗することがありますが、何度も失敗するときは一度Raspberry Piを再起動して試してもらうといいと思います)。

Reseaved: {'command': 'on'}

AWS IoT 1-Clickの設定

デバイスの追加

今回使用するボタンをAWS IoT 1-Clickに追加します。

AWS IoT 1-Clickのコンソールを開いたら、デバイスの追加をクリックします。

もしくは、スマホにAWS IoT 1-Clickのアプリをインストールして、そこからデバイスを追加することもできます。

追加するときは、LambdaやAWS IoT Coreを設定したリージョンと同じものを選択していることに注意が必要です。

デバイスプレイスメントの設定

左のメニューから 管理→プロジェクト をクリックしてプロジェクトを新規で作成します。

作成後、デバイステンプレートを作成します。

デバイステンプレートではボタンが押されたときにLambda関数を呼び出すように設定します。

関数名は先ほど作成したLambda関数名 buttonTrigger と同じです。

プレイスメントの属性では以下の値を設定します。

IMSIはLambda側で環境変数を設定しなくてもプレイスメントの属性で設定した値を使うことで、値の設定箇所がひとまとめになるので設定が整理しやすくなります。

属性
DEVICE_IMSI SORACOMに接続しているIMSI
SINGLE on
DOUBLE off
LONG reboot

動作確認

それでは動作確認です。

動画のようにボタンを押してSwitchBotが動いたら、成功です。

https://www.youtube.com/watch?v=n0Gpwt8pOlY

ちなみにsystemctlで動かしたときにRaspberry Piを再起動できるようにボタンを長押しするとRaspberry Piが再起動できるようにしています。

まとめ

今回はSORACOM LTE-MボタンでAWSのサービスを駆使してSwitchBotを動かしてみました。

SORACOM Beamを使えばデバイス側にAWSの接続情報を入れなくてもSORACOMのプラットフォームでクラウド側に接続情報を設定することで、デバイス側のコードがシンプルでセキュアな通信を実現できます。

しかも、AWSをよく使う人なのでAWS IoT 1-Clickで簡単にLambdaを動かせるのは便利です。

SORACOM × AWSの相性バツグンですね!

Discussion