スイッチボット防水温湿度計の遊び方

スイッチボット防水温湿度計 PC/デジモノ

スイッチボットから防水型の温湿度計が発売されました。お外の気温湿度を測定するのに都合が良さそうです。

前回同様、LinuxマシンでBLEを使ってデータを取れないか解析してみました。Bluetooth搭載のLinuxマシンであれば特に制限はないはずなので、RaspberryPiを使って読みだすこともできますよ!

バッテリー残量まで対応して書き直しました。
bookwormになってからpython3に必要なライブラリbluepyのインストール時にエラーが出るようになってしまいました。現状ではとりあえずひとつ前のBullseyeで使用することをお勧めします。

液晶付き従来型の遊び方

液晶表示のある、スイッチボット温湿度計のデータ取得方法は過去記事を参照してください。ただ、新しく発売された防水型のものは下記のものでは動作しませんでした

防水タイプの新型の遊び方

液晶付タイプのスイッチボット温湿度計のデータを読み出すプログラムでは動作しなかったため、色々と試してみた結果

  • 液晶付きタイプは、温湿度のデータがBLEのServiceDataに格納されている
  • 防水タイプは、温湿度のデータがBLEのManufactuarerに格納されている
  • ただし、バッテリー残量は従来と同じくServiceDataに格納されている

ということがわかりました。

前準備

プログラムの実行に必要なソフトウェアを準備してください。手順は以下の通りです。

$sudo apt -y install python3-dev
$sudo apt -y install python3-pip
$sudo apt -y install libglib2.0-dev
$sudo pip3 install bluepy
bookwormになってからpython3に必要なライブラリbluepyのインストール時にエラーが出るようになってしまいました。現状ではとりあえずひとつ前のBullseyeで使用することをお勧めします。
もしくは無理やり入れるのであれば以下のようにしてください。
$sudo pip3 install –break-system-packages bluepy
※breakの前は(-)を二つです
上記で動かない場合はbluezもインストールしてください。ラズパイなら初期インストール済みです。
$sudo apt install bluez

プログラム例(Python)

$emacs sbm_b.py
import binascii
from bluepy.btle import Scanner, DefaultDelegate
import time
import sys

args = sys.argv
macaddr = args[1]
battery = 0
humid = 0
temp = 0

class ScanDelegate(DefaultDelegate):
  def __init__(self):
    DefaultDelegate.__init__(self)

  def handleDiscovery(self, dev, isNewDev, isNewData):
    if dev.addr != macaddr: return
    for (adtype, desc, value) in dev.getScanData():
      if(adtype == 22):
        servicedata = binascii.unhexlify(value[4:])
        battery = servicedata[2] & 0b01111111
        print(str(battery) + "," + str(temp) + "," + str(humid))
        exit()
      elif(adtype == 255):
        madata = binascii.unhexlify(value[16:])
        humid = madata[4] & 0b01111111
        temp = (madata[2] & 0b00001111) / 10 + (madata[3] & 0b01111111)
        isOverZero=(madata[3]&0b10000000)
        if not isOverZero:
          temp=-temp
        continue
      else : continue

scanner = Scanner().withDelegate( ScanDelegate() )
scanner.scan(10)

実行

防水タイプ温湿度計のMACアドレスは適宜

$sudo python3 sbm_b.py aa:bb:cc:dd:ee:ff

これで

{バッテリー残量},{気温},{湿度}

の形式で結果が出力されます。

97,23.6,74

解説

バッテリー情報の読み出し

elif(adtype == 22):

→BLEアドバタイズのなかのServiceData(adtype:22)を抜き出し。

battery = servicedata[2] & 0b01111111

->ServiceDataの3ビット目以降にバッテリーデータが格納されています。

ちなみに、BLEのadtypeのデータは1->255->22の順で吐き出されているので、’22’以外だったらもう一周、’22’だったら結果を吐き出して終了、というアルゴリズムにしています。

温湿度の読み出し

elif(adtype == 255):

→BLEアドバタイズのなかのManufactuarer(adtype:255)を抜き出し。

madata = binascii.unhexlify(value[16:])

→16番目以降にデータが入っている模様。ちなみに液晶表示タイプだと[15]までしかデータが入ってません。

humid = madata[4] & 0b01111111
temp = (madata[2] & 0b00001111) / 10 + (madata[3] & 0b01111111)

→上記で抜き出したもののうち、[4]が湿度、[2]が小数点気温、[3]が気温、[3]の最上位ビットが零度以上かどうかのフラグ(1が入っていれば零度以上)となっています。冷凍庫に突っ込んで確認済みです。

注意など

とりあえず現段階でわかった内容を記事にしました。バッテリー残量などすべての情報をとりだせているわけではありません。詳しい内容をご存知の方はぜひコメント欄へ。

本製品は防水がうたわれていますが、温度変化による膨張/伸縮で内部に水が入るとかいうのもよく聞く話です。直射日光に当てない/最低限の雨よけぐらいは用意するなどしたほうがよさそうです。そもそも、日光があたっていたら気温測定になりませんしね。

コメント

  1. 検証と、記事の投稿ありがとうございます。
    買ったはいいものの途方に暮れていたのですが、無事に温度と湿度の取得ができました。

    バッテリーの残量についてですが、従来通り ServiceData の 3byte 目にある値なのではないかなと思っています。

    以下従来の温湿度計の公開されている仕様です。
    https://github.com/OpenWonderLabs/SwitchBotAPI-BLE
    https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/meter.md

    このあたりを見ると、ServiceData の 1byte 目は、device-type として、どんな機器でもある気がします。
    また、屋外対応の温湿度計の ServiceData は Service UUID に続く先頭 3byte になにかはいっていて、3byte目の bit 6-0 が 0x64(100)だったので、これがバッテリ残量なのではないかなーと思いました。
    検証などしてないので間違っていたらごめんなさい。

    • コメントありがとうございます。
      データの取得ができたとのこと、少しでもお役に立てたようでよかったです。

      バッテリー残量についての情報提供ありがとうございます。気力があるときに試してみます。

    • >バッテリーの残量についてですが、従来通り ServiceData の 3byte 目にある値なのではないかなと思っています。

      確認しました。ビンゴです。ありがとうございます。