Browse Source

Add support for WoRemote (#294)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Arkadiusz Wahlig 2 months ago
parent
commit
8870e2798f
4 changed files with 84 additions and 0 deletions
  1. 7 0
      switchbot/adv_parser.py
  2. 24 0
      switchbot/adv_parsers/remote.py
  3. 1 0
      switchbot/const.py
  4. 52 0
      tests/test_adv_parser.py

+ 7 - 0
switchbot/adv_parser.py

@@ -29,6 +29,7 @@ from .adv_parsers.relay_switch import (
     process_worelay_switch_1,
     process_worelay_switch_1pm,
 )
+from .adv_parsers.remote import process_woremote
 from .const import SwitchbotModel
 from .models import SwitchBotAdvertisement
 
@@ -203,6 +204,12 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
         "func": process_worelay_switch_1,
         "manufacturer_id": 2409,
     },
+    "b": {
+        "modelName": SwitchbotModel.REMOTE,
+        "modelFriendlyName": "Remote",
+        "func": process_woremote,
+        "manufacturer_id": 89,
+    },
 }
 
 _SWITCHBOT_MODEL_TO_CHAR = {

+ 24 - 0
switchbot/adv_parsers/remote.py

@@ -0,0 +1,24 @@
+"""Remote adv parser."""
+
+from __future__ import annotations
+
+import logging
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def process_woremote(
+    data: bytes | None, mfr_data: bytes | None
+) -> dict[str, int | None]:
+    """Process WoRemote adv data."""
+
+    if data is None:
+        return {
+            "battery": None,
+        }
+
+    _LOGGER.debug("data: %s", data.hex())
+
+    return {
+        "battery": data[2] & 0b01111111,
+    }

+ 1 - 0
switchbot/const.py

@@ -57,6 +57,7 @@ class SwitchbotModel(StrEnum):
     KEYPAD = "WoKeypad"
     RELAY_SWITCH_1PM = "Relay Switch 1PM"
     RELAY_SWITCH_1 = "Relay Switch 1"
+    REMOTE = "WoRemote"
 
 
 class LockStatus(Enum):

+ 52 - 0
tests/test_adv_parser.py

@@ -1917,3 +1917,55 @@ def test_leak_real_data_from_ha():
         rssi=-73,
         active=True,
     )
+
+
+def test_remote_active() -> None:
+    ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={89: b"\xaa\xbb\xcc\xdd\xee\xff"},
+        service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"b V\x00"},
+        service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
+        rssi=-95,
+    )
+    result = parse_advertisement_data(ble_device, adv_data)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {
+                "battery": 86,
+            },
+            "isEncrypted": False,
+            "model": "b",
+            "modelFriendlyName": "Remote",
+            "modelName": SwitchbotModel.REMOTE,
+            "rawAdvData": b"b V\x00",
+        },
+        device=ble_device,
+        rssi=-95,
+        active=True,
+    )
+
+
+def test_remote_passive() -> None:
+    ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={89: b"\xaa\xbb\xcc\xdd\xee\xff"},
+        rssi=-97,
+    )
+    result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.REMOTE)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {
+                "battery": None,
+            },
+            "isEncrypted": False,
+            "model": "b",
+            "modelFriendlyName": "Remote",
+            "modelName": SwitchbotModel.REMOTE,
+            "rawAdvData": None,
+        },
+        device=ble_device,
+        rssi=-97,
+        active=False,
+    )