Skip to content

Commit

Permalink
Add support for WoTHPc
Browse files Browse the repository at this point in the history
The CO2 sensor has not yet been decoded but
temp and humid work
  • Loading branch information
bdraco committed Oct 22, 2024
1 parent e7ad3c8 commit bbff6fd
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
8 changes: 7 additions & 1 deletion switchbot/adv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .adv_parsers.humidifier import process_wohumidifier
from .adv_parsers.light_strip import process_wostrip
from .adv_parsers.lock import process_wolock, process_wolock_pro
from .adv_parsers.meter import process_wosensorth
from .adv_parsers.meter import process_wosensorth, process_wosensorth_c
from .adv_parsers.motion import process_wopresence
from .adv_parsers.plug import process_woplugmini
from .const import SwitchbotModel
Expand Down Expand Up @@ -107,6 +107,12 @@ class SwitchbotSupportedType(TypedDict):
"func": process_wosensorth,
"manufacturer_id": 2409,
},
"5": {
"modelName": SwitchbotModel.METER_PRO_C,
"modelFriendlyName": "Meter",
"func": process_wosensorth_c,
"manufacturer_id": 2409,
},
"v": {
"modelName": SwitchbotModel.HUB2,
"modelFriendlyName": "Hub 2",
Expand Down
39 changes: 39 additions & 0 deletions switchbot/adv_parsers/meter.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,42 @@ def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str,
}

return _wosensorth_data


def process_wosensorth_c(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
"""Process woSensorTH/Temp sensor services data with CO2."""
temp_data = None
battery = None

if mfr_data:
temp_data = mfr_data[8:11]

if data:
if not temp_data:
temp_data = data[3:6]
battery = data[2] & 0b01111111

if not temp_data:
return {}

_temp_sign = 1 if temp_data[1] & 0b10000000 else -1
_temp_c = _temp_sign * (
(temp_data[1] & 0b01111111) + ((temp_data[0] & 0b00001111) / 10)
)
_temp_f = (_temp_c * 9 / 5) + 32
_temp_f = (_temp_f * 10) / 10
humidity = temp_data[2] & 0b01111111

if _temp_c == 0 and humidity == 0 and battery == 0:
return {}

_wosensorth_data = {
# Data should be flat, but we keep the original structure for now
"temp": {"c": _temp_c, "f": _temp_f},
"temperature": _temp_c,
"fahrenheit": bool(temp_data[2] & 0b10000000),
"humidity": humidity,
"battery": battery,
}

return _wosensorth_data
3 changes: 2 additions & 1 deletion switchbot/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class SwitchbotModel(StrEnum):
CONTACT_SENSOR = "WoContact"
LIGHT_STRIP = "WoStrip"
METER = "WoSensorTH"
METER_PRO = "WoSensorTHP"
METER_PRO = "WoTHP"
METER_PRO_C = "WoTHPc"
IO_METER = "WoIOSensorTH"
MOTION_SENSOR = "WoPresence"
COLOR_BULB = "WoBulb"
Expand Down
66 changes: 66 additions & 0 deletions tests/test_adv_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,9 @@ def test_meter_pro_passive() -> None:
rssi=-67,
)
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO)
import pprint

pprint.pprint(result)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
Expand All @@ -1619,3 +1622,66 @@ def test_meter_pro_passive() -> None:
rssi=-67,
active=False,
)


def test_meter_pro_c_active() -> None:
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
manufacturer_data={
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
},
service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"5\x00d"},
rssi=-67,
)
result = parse_advertisement_data(ble_device, adv_data)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": 100,
"fahrenheit": True,
"humidity": 36,
"temp": {"c": 27.7, "f": 81.86},
"temperature": 27.7,
},
"isEncrypted": False,
"model": "5",
"modelFriendlyName": "Meter",
"modelName": SwitchbotModel.METER_PRO_C,
"rawAdvData": b"5\x00d",
},
device=ble_device,
rssi=-67,
active=True,
)


def test_meter_pro_c_passive() -> None:
ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
adv_data = generate_advertisement_data(
manufacturer_data={
2409: b"\xb0\xe9\xfeT2\x15\xb7\xe4\x07\x9b\xa4\x007\x02\xd5\x00"
},
rssi=-67,
)
result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER_PRO_C)
assert result == SwitchBotAdvertisement(
address="aa:bb:cc:dd:ee:ff",
data={
"data": {
"battery": None,
"fahrenheit": True,
"humidity": 36,
"temp": {"c": 27.7, "f": 81.86},
"temperature": 27.7,
},
"isEncrypted": False,
"model": "5",
"modelFriendlyName": "Meter",
"modelName": SwitchbotModel.METER_PRO_C,
"rawAdvData": None,
},
device=ble_device,
rssi=-67,
active=False,
)

0 comments on commit bbff6fd

Please sign in to comment.