Skip to content

Commit c385099

Browse files
authored
Add support for WoTHPc (#256)
1 parent e7ad3c8 commit c385099

File tree

4 files changed

+114
-2
lines changed

4 files changed

+114
-2
lines changed

switchbot/adv_parser.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from .adv_parsers.humidifier import process_wohumidifier
2121
from .adv_parsers.light_strip import process_wostrip
2222
from .adv_parsers.lock import process_wolock, process_wolock_pro
23-
from .adv_parsers.meter import process_wosensorth
23+
from .adv_parsers.meter import process_wosensorth, process_wosensorth_c
2424
from .adv_parsers.motion import process_wopresence
2525
from .adv_parsers.plug import process_woplugmini
2626
from .const import SwitchbotModel
@@ -107,6 +107,12 @@ class SwitchbotSupportedType(TypedDict):
107107
"func": process_wosensorth,
108108
"manufacturer_id": 2409,
109109
},
110+
"5": {
111+
"modelName": SwitchbotModel.METER_PRO_C,
112+
"modelFriendlyName": "Meter",
113+
"func": process_wosensorth_c,
114+
"manufacturer_id": 2409,
115+
},
110116
"v": {
111117
"modelName": SwitchbotModel.HUB2,
112118
"modelFriendlyName": "Hub 2",

switchbot/adv_parsers/meter.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,42 @@ def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str,
4141
}
4242

4343
return _wosensorth_data
44+
45+
46+
def process_wosensorth_c(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
47+
"""Process woSensorTH/Temp sensor services data with CO2."""
48+
temp_data = None
49+
battery = None
50+
51+
if mfr_data:
52+
temp_data = mfr_data[8:11]
53+
54+
if data:
55+
if not temp_data:
56+
temp_data = data[3:6]
57+
battery = data[2] & 0b01111111
58+
59+
if not temp_data:
60+
return {}
61+
62+
_temp_sign = 1 if temp_data[1] & 0b10000000 else -1
63+
_temp_c = _temp_sign * (
64+
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
65+
)
66+
_temp_f = (_temp_c * 9 / 5) + 32
67+
_temp_f = (_temp_f * 10) / 10
68+
humidity = temp_data[2] & 0b01111111
69+
70+
if _temp_c == 0 and humidity == 0 and battery == 0:
71+
return {}
72+
73+
_wosensorth_data = {
74+
# Data should be flat, but we keep the original structure for now
75+
"temp": {"c": _temp_c, "f": _temp_f},
76+
"temperature": _temp_c,
77+
"fahrenheit": bool(temp_data[2] & 0b10000000),
78+
"humidity": humidity,
79+
"battery": battery,
80+
}
81+
82+
return _wosensorth_data

switchbot/const.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class SwitchbotModel(StrEnum):
4242
CONTACT_SENSOR = "WoContact"
4343
LIGHT_STRIP = "WoStrip"
4444
METER = "WoSensorTH"
45-
METER_PRO = "WoSensorTHP"
45+
METER_PRO = "WoTHP"
46+
METER_PRO_C = "WoTHPc"
4647
IO_METER = "WoIOSensorTH"
4748
MOTION_SENSOR = "WoPresence"
4849
COLOR_BULB = "WoBulb"

tests/test_adv_parser.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,9 @@ def test_meter_pro_passive() -> None:
15991599
rssi=-67,
16001600
)
16011601
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO)
1602+
import pprint
1603+
1604+
pprint.pprint(result)
16021605
assert result == SwitchBotAdvertisement(
16031606
address="aa:bb:cc:dd:ee:ff",
16041607
data={
@@ -1619,3 +1622,66 @@ def test_meter_pro_passive() -> None:
16191622
rssi=-67,
16201623
active=False,
16211624
)
1625+
1626+
1627+
def test_meter_pro_c_active() -> None:
1628+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
1629+
adv_data = generate_advertisement_data(
1630+
manufacturer_data={
1631+
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
1632+
},
1633+
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"5\x00d"},
1634+
rssi=-67,
1635+
)
1636+
result = parse_advertisement_data(ble_device, adv_data)
1637+
assert result == SwitchBotAdvertisement(
1638+
address="aa:bb:cc:dd:ee:ff",
1639+
data={
1640+
"data": {
1641+
"battery": 100,
1642+
"fahrenheit": True,
1643+
"humidity": 36,
1644+
"temp": {"c": 27.7, "f": 81.86},
1645+
"temperature": 27.7,
1646+
},
1647+
"isEncrypted": False,
1648+
"model": "5",
1649+
"modelFriendlyName": "Meter",
1650+
"modelName": SwitchbotModel.METER_PRO_C,
1651+
"rawAdvData": b"5\x00d",
1652+
},
1653+
device=ble_device,
1654+
rssi=-67,
1655+
active=True,
1656+
)
1657+
1658+
1659+
def test_meter_pro_c_passive() -> None:
1660+
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
1661+
adv_data = generate_advertisement_data(
1662+
manufacturer_data={
1663+
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
1664+
},
1665+
rssi=-67,
1666+
)
1667+
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO_C)
1668+
assert result == SwitchBotAdvertisement(
1669+
address="aa:bb:cc:dd:ee:ff",
1670+
data={
1671+
"data": {
1672+
"battery": None,
1673+
"fahrenheit": True,
1674+
"humidity": 36,
1675+
"temp": {"c": 27.7, "f": 81.86},
1676+
"temperature": 27.7,
1677+
},
1678+
"isEncrypted": False,
1679+
"model": "5",
1680+
"modelFriendlyName": "Meter",
1681+
"modelName": SwitchbotModel.METER_PRO_C,
1682+
"rawAdvData": None,
1683+
},
1684+
device=ble_device,
1685+
rssi=-67,
1686+
active=False,
1687+
)

0 commit comments

Comments
 (0)