4
3

More than 3 years have passed since last update.

SwitchBot MeterTH の温度と湿度をPythonで読み取る(Raspberry Pi 4)

Last updated at Posted at 2021-02-19

データフォーマット

データフォーマットみて実装できる人はここを見よう
公式のWikiに詳しく書かれています。
https://github.com/OpenWonderLabs/python-host/wiki/Meter-BLE-open-API

Index Byte[0] Byte[1] Byte[2] Byte[3] Byte[4] Byte[5]
Description Enc Type Dev Type
Bit[7]予約済み
Bit[6:0]デバイスタイプ
Status
Bit[7:4]予約済み
Bit[3:0]デバイスグループ
Update UTC Flag Battery
Bit[7]予約済み
Bit[6:0]バッテリー残量
alarm flag the fraction part of temperatrue value (WoSensorTH)
Bit[7:6]温度アラートの状態
Bit[5:4]湿度アラートの状態
Bit[3:0]温度の小数点以下
temperature mode Positive/Negative temperature flag the integer part of temperature value (WoSensorTH)
Bit[7]マイナスかプラスか
Bit[6:0]温度の整数値
humidity value (WoSensorTH)
Bit[7]温度スケール
Bit[6:0]湿度の整数値

Byte[0]

Bit[6:0]のデバイスタイプ

製品名 Hex(16進数表記) Ascii 備考
SwitchBot Bot (WoHand) 0x48 H
WoButton 0x42 B
SwitchBot Hub (WoLink) 0x4C L addMode
SwitchBot Hub (WoLink) 0x6C l Normal
SwitchBot Hub Plus (WoLink Plus) 0x50 P addMode
SwitchBot Hub Plus (WoLink Plus) 0x70 p Normal
SwitchBot Fan (WoFan) 0x46 F addMode
SwitchBot Fan (WoFan) 0x66 f Normal
SwitchBot MeterTH (WoSensorTH) 0x74 t addMode
SwitchBot MeterTH (WoSensorTH) 0x54 T Normal
SwitchBot Mini (HubMini) 0x4D M addMode
SwitchBot Mini (HubMini) 0x6D m Normal

Byte[1]

Bit[3:0]のデバイスグループ

グループ分け
Bit Group
Bit[3] Group D
Bit[2] Group C
Bit[1] Group B
Bit[0] Group A
状態
0 デバイスがこのグループに含まれていない
1 デバイスがこのグループに含まれています

Byte[2]

Bit[6:0]はバッテリー残量を0~100の値で表します、単位は%です。

Byte[3]

温度アラートの状態
状態
0 アラートなし
1 低温度アラート(温度が下限以下)
2 高温度アラート (温度が上限以上)
3 温度アラート(温度は下限以上、上限以下)
湿度アラートの状態
状態
0 アラートなし
1 低湿度アラート(湿度が下限以下)
2 高湿度アラート (湿度が上限以上)
3 湿度アラート(湿度は下限以上、上限以下)

公式Wikiには higher thanとか lower thanとか書いてあったからより高い未満だと思って湿度で検証したら以上以下じゃね~かよ。
低湿度アラートを(0~39%)高湿度アラートを(39~99%)にしたら3が出力されたよ!!

Byte[4]

Bit[7]

説明
0 マイナスの温度
1 プラスの温度

Byte[5]

Bit[7]

説明
0 摂氏スケール
1 華氏スケール

スケールによってByte[3]の温度が変わるわけではなく、華氏スケールでの温度が提供される。
摂氏に変換する場合は

摂氏スケール温度=(華氏スケール温度*1.8)+32

となる。

全体像

screenshot.139.png

実装例

環境

  • Raspberry Pi 4 Model B 4GB
  • Raspbian 10
  • Python 3.7.3

コード

Meter.py

import toml
import binascii
from bluepy.btle import Scanner, DefaultDelegate

config = toml.load('config.toml')
macaddr = config['Device']['MACAddress']

mask_7Bit = 0b01111111


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 :continue
            data = binascii.unhexlify(value[4:])
            if(data[0] != 0x54):break
            battery = data[2] & mask_7Bit
            decimal_temperature =  data[3] & 0b00001111
            temperature = float(data[4] & mask_7Bit) + decimal_temperature/10
            subzero = (data[4] & 0b10000000) != 0b10000000
            humidity = data[5] &mask_7Bit
            if subzero :
                temperature = -temperature
            print(battery,end='% \n')
            print(temperature,end='C \n')
            print(humidity,end = '% \n')

scanner = Scanner().withDelegate(ScanDelegate())
scanner.scan(0)
config.toml
[Device]
MACAddress="ff:ff:ff:ff:ff:ff"

まずはSwitchBotMeterのMACアドレスでフィルタリングをかけるので、SwitchBotのスマートフォンアプリからMACアドレスを取得してきます。
例としてff:ff:ff:ff:ff:ffを書いていますので環境に合わせて書き換えてください。
Macアドレスはコード内にそのまま書いても問題ないです。
個人のポリシーでconfig.tomlに書いています。
adtypeが22の場合に温度や湿度の情報がパケットに含まれているのでadtype22でフィルタリングします。
valueの最初の4桁は使わないのでスライスで5桁目(インデックスでいうと4)以降を参照します。
その値を、binascii.unhexlify()でバイト列に変換します。
その後は上記で紹介した表に合わせてバイト列の値に対してビット演算でマスクを掛けています。
例えばバッテリー残量はByte[2]の0から6ビットまでの値で取得できるので

battery = data[2] & 0b01111111

で取得できます。

実行

pip3でbinasciiやbluepyをインストールしてからroot権限で実行します。

sudo Python3 Meter.py

参考

4
3
0

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
4
3