🌡️

Raspberry Pi Pico W で Switchbot 温湿度計からBLEで値を取得する

2024/09/04に公開

Switchbot温湿度計(小さい方)を購入したので、その値をRaspberry Pi Pico Wから取得できるようにしました。
先駆者はたくさんいるようでしたが、Pico WのBLEで、MicroPythonを使った上でライブラリとしてaiobleを使った作例は見当たらなかったので、主に自分向けに簡単にやり方を書いておきます。

要約

MicroPythonから扱えるaiobleだとSwitchbot 温湿度計から出力されるService Dataを示すデータタイプ値 0x16 を判別できずUUIDを取り出せない。
aiobleのソースを参考にしてresp_dataをデコードするプログラムを用意して上げる必要がある。

前提条件

Pimoroni から 発売されている Pico Display Pack を使いたかったので、Pimoroni の MicroPythonファームウェア を使用しています。
おそらくMicroPython公式ファームウェア でも動くとは思いますが、未確認です。
ファームウェアをPico Wへ書き込む方法はよその記事を参照してください。

aioble ライブラリ とは

aioble はMicroPythonで使用できるBLEを用いた通信のためのライブラリです。
その名前のとおり、asyncioベースとなっており、非同期パターンを用いたプログラムの記述ができます。
しかし、今回はその部分に関してはあまり活用しておらず、ほぼ参考としているExampleのまま使用しています。

コード

以下に aioble を参考にしたデコード関数を示します。

def decode_servicedata(result, *adv_type):

        if result.resp_data is None:
            return None
        i = 0
        while i + 1 < len(result.resp_data):
            if result.resp_data[i + 1] in adv_type:
                yield result.resp_data[i + 2 : i + result.resp_data[i] + 1]
            i += 1 + result.resp_data[i]

aioble と組み合わせてScan結果をデコードするにはこのように書きます。


_ADV_TYPE_UUID16_SERVICEDATA = const(0x16)

async def find_temp_sensor():
    results = []
    async with aioble.scan(5000, interval_us=30000, window_us=30000, active=True) as scanner:
        async for result in scanner:
            result.serviceUUID = None
            result.servicePayload = None
            if result.adv_data is not None and result.resp_data is not None:
                for i in decode_servicedata(result, _ADV_TYPE_UUID16_SERVICEDATA):
                    result.serviceUUID = bluetooth.UUID(i[0:2])
                    result.servicePayload = i[2:len(i)]
            # See if it matches UUID and has Service Data payload.
            if _ENV_SENSE_UUID == result.serviceUUID and result.servicePayload is not None:
                if result not in results:
                    results.append(result)
    return results

gist にコード全体を置いておきます。

以上。

Discussion