J. Nick Koston 1 год назад
Родитель
Сommit
ea31b4feb8
3 измененных файлов с 115 добавлено и 17 удалено
  1. 7 7
      switchbot/adv_parser.py
  2. 16 6
      switchbot/adv_parsers/meter.py
  3. 92 4
      tests/test_adv_parser.py

+ 7 - 7
switchbot/adv_parser.py

@@ -78,15 +78,15 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
         },
         "manufacturer_id": 89,
     },
-    "T": {
+    "i": {
         "modelName": SwitchbotModel.METER,
-        "modelFriendlyName": "Meter",
+        "modelFriendlyName": "Meter Plus",
         "func": process_wosensorth,
         "manufacturer_id": 2409,
     },
-    "i": {
+    "T": {
         "modelName": SwitchbotModel.METER,
-        "modelFriendlyName": "Meter Plus",
+        "modelFriendlyName": "Meter",
         "func": process_wosensorth,
         "manufacturer_id": 2409,
     },
@@ -193,6 +193,9 @@ def _parse_data(
     """Parse advertisement data."""
     _model = chr(_service_data[0] & 0b01111111) if _service_data else None
 
+    if _switchbot_model and _switchbot_model in _SWITCHBOT_MODEL_TO_CHAR:
+        _model = _SWITCHBOT_MODEL_TO_CHAR[_switchbot_model]
+
     if not _model and _mfr_id and _mfr_id in MODELS_BY_MANUFACTURER_DATA:
         _service_uuids = set(_service_uuids_str.split(","))
         for model_chr, model_data in MODELS_BY_MANUFACTURER_DATA[_mfr_id]:
@@ -204,9 +207,6 @@ def _parse_data(
                 _model = model_chr
                 break
 
-    if not _model and _switchbot_model and _switchbot_model in _SWITCHBOT_MODEL_TO_CHAR:
-        _model = _SWITCHBOT_MODEL_TO_CHAR[_switchbot_model]
-
     if not _model:
         return None
 

+ 16 - 6
switchbot/adv_parsers/meter.py

@@ -6,19 +6,29 @@ from typing import Any
 
 def process_wosensorth(data: bytes | None, mfr_data: bytes | None) -> dict[str, Any]:
     """Process woSensorTH/Temp sensor services data."""
-    if data is None:
+    if mfr_data:
+        temp_data = mfr_data[8:11]
+        battery = None
+
+    if data:
+        temp_data = data[3:6]
+        battery = data[2] & 0b01111111
+
+    if not temp_data:
         return {}
 
-    _temp_sign = 1 if data[4] & 0b10000000 else -1
-    _temp_c = _temp_sign * ((data[4] & 0b01111111) + ((data[3] & 0b00001111) / 10))
+    _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
 
     _wosensorth_data = {
         "temp": {"c": _temp_c, "f": _temp_f},
-        "fahrenheit": bool(data[5] & 0b10000000),
-        "humidity": data[5] & 0b01111111,
-        "battery": data[2] & 0b01111111,
+        "fahrenheit": bool(temp_data[2] & 0b10000000),
+        "humidity": temp_data[2] & 0b01111111,
+        "battery": battery,
     }
 
     return _wosensorth_data

+ 92 - 4
tests/test_adv_parser.py

@@ -620,7 +620,7 @@ def test_bulb_active():
         tx_power=-127,
         rssi=-50,
     )
-    result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.BOT)
+    result = parse_advertisement_data(ble_device, adv_data)
     assert result == SwitchBotAdvertisement(
         address="aa:bb:cc:dd:ee:ff",
         data={
@@ -645,8 +645,6 @@ def test_bulb_active():
     )
 
 
-
-
 def test_lightstrip_passive():
     """Test parsing lightstrip as passive."""
     ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
@@ -658,7 +656,7 @@ def test_lightstrip_passive():
         tx_power=-127,
         rssi=-50,
     )
-    result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.BOT)
+    result = parse_advertisement_data(ble_device, adv_data)
     assert result == SwitchBotAdvertisement(
         address="aa:bb:cc:dd:ee:ff",
         data={
@@ -681,3 +679,93 @@ def test_lightstrip_passive():
         device=ble_device,
         rssi=-50,
     )
+
+
+def test_wosensor_passive_and_active():
+    """Test parsing wosensor as passive with active data as well."""
+    ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={2409: b"\xd7\xc1}]\xebC\xde\x03\x06\x985"},
+        service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"T\x00\xe4\x06\x985"},
+        tx_power=-127,
+        rssi=-50,
+    )
+    result = parse_advertisement_data(ble_device, adv_data)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {
+                "battery": 100,
+                "fahrenheit": False,
+                "humidity": 53,
+                "temp": {"c": 24.6, "f": 76.28},
+            },
+            "isEncrypted": False,
+            "model": "T",
+            "modelFriendlyName": "Meter",
+            "modelName": SwitchbotModel.METER,
+            "rawAdvData": b"T\x00\xe4\x06\x985",
+        },
+        device=ble_device,
+        rssi=-50,
+    )
+
+
+def test_wosensor_active():
+    """Test parsing wosensor with active data as well."""
+    ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={},
+        service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"T\x00\xe4\x06\x985"},
+        tx_power=-127,
+        rssi=-50,
+    )
+    result = parse_advertisement_data(ble_device, adv_data)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {
+                "battery": 100,
+                "fahrenheit": False,
+                "humidity": 53,
+                "temp": {"c": 24.6, "f": 76.28},
+            },
+            "isEncrypted": False,
+            "model": "T",
+            "modelFriendlyName": "Meter",
+            "modelName": SwitchbotModel.METER,
+            "rawAdvData": b"T\x00\xe4\x06\x985",
+        },
+        device=ble_device,
+        rssi=-50,
+    )
+
+
+def test_wosensor_passive_only():
+    """Test parsing wosensor with only passive data."""
+    ble_device = BLEDevice("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={2409: b"\xd7\xc1}]\xebC\xde\x03\x06\x985"},
+        service_data={},
+        tx_power=-127,
+        rssi=-50,
+    )
+    result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.METER)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {
+                "battery": None,
+                "fahrenheit": False,
+                "humidity": 53,
+                "temp": {"c": 24.6, "f": 76.28},
+            },
+            "isEncrypted": False,
+            "model": "T",
+            "modelFriendlyName": "Meter",
+            "modelName": SwitchbotModel.METER,
+            "rawAdvData": None,
+        },
+        device=ble_device,
+        rssi=-50,
+    )