Procházet zdrojové kódy

Add initial support for the keypad touch (#252)

Co-authored-by: J. Nick Koston <nick@koston.org>
Nick Conway před 3 měsíci
rodič
revize
8f87eac413

+ 7 - 0
switchbot/adv_parser.py

@@ -18,6 +18,7 @@ from .adv_parsers.contact import process_wocontact
 from .adv_parsers.curtain import process_wocurtain
 from .adv_parsers.hub2 import process_wohub2
 from .adv_parsers.humidifier import process_wohumidifier
+from .adv_parsers.keypad import process_wokeypad
 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, process_wosensorth_c
@@ -177,6 +178,12 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
         "func": process_woblindtilt,
         "manufacturer_id": 2409,
     },
+    "y": {
+        "modelName": SwitchbotModel.KEYPAD,
+        "modelFriendlyName": "Keypad",
+        "func": process_wokeypad,
+        "manufacturer_id": 2409,
+    },
     "<": {
         "modelName": SwitchbotModel.RelaySwitch1PM,
         "modelFriendlyName": "Relay Switch 1PM",

+ 22 - 0
switchbot/adv_parsers/keypad.py

@@ -0,0 +1,22 @@
+"""Keypad parser."""
+
+from __future__ import annotations
+
+import logging
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def process_wokeypad(
+    data: bytes | None,
+    mfr_data: bytes | None,
+) -> dict[str, bool | int | None]:
+    """Process woKeypad services data."""
+    if data is None or mfr_data is None:
+        return {"battery": None, "attempt_state": None}
+
+    _LOGGER.debug("mfr_data: %s", mfr_data.hex())
+    if data:
+        _LOGGER.debug("data: %s", data.hex())
+
+    return {"battery": data[2] & 0b01111111, "attempt_state": mfr_data[6]}

+ 2 - 0
switchbot/const.py

@@ -1,4 +1,5 @@
 """Library to handle connection with Switchbot."""
+
 from __future__ import annotations
 
 from enum import Enum
@@ -52,6 +53,7 @@ class SwitchbotModel(StrEnum):
     LOCK_PRO = "WoLockPro"
     BLIND_TILT = "WoBlindTilt"
     HUB2 = "WoHub2"
+    KEYPAD = "WoKeypad"
     RelaySwitch1PM = "Relay Switch 1PM"
     RelaySwitch1Plus = "Relay Switch 1"
 

+ 1 - 0
switchbot/devices/keypad.py

@@ -0,0 +1 @@
+from __future__ import annotations

+ 4 - 0
switchbot/discovery.py

@@ -124,6 +124,10 @@ class GetSwitchbotDevices:
         lock_pros = await self._get_devices_by_model("$")
         return {**locks, **lock_pros}
 
+    async def get_keypads(self) -> dict[str, SwitchBotAdvertisement]:
+        """Return all WoKeypad/Keypad devices with services data."""
+        return await self._get_devices_by_model("y")
+
     async def get_device_data(
         self, address: str
     ) -> dict[str, SwitchBotAdvertisement] | None:

+ 25 - 0
tests/test_adv_parser.py

@@ -1647,3 +1647,28 @@ def test_meter_pro_c_passive() -> None:
         rssi=-67,
         active=False,
     )
+
+
+def test_parse_advertisement_data_keypad():
+    """Test parse_advertisement_data for the keypad."""
+    ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
+    adv_data = generate_advertisement_data(
+        manufacturer_data={2409: b"\xeb\x13\x02\xe6#\x0f\x8fd\x00\x00\x00\x00"},
+        service_data={"0000fd3d-0000-1000-8000-00805f9b34fb": b"y\x00d"},
+        rssi=-67,
+    )
+    result = parse_advertisement_data(ble_device, adv_data, SwitchbotModel.KEYPAD)
+    assert result == SwitchBotAdvertisement(
+        address="aa:bb:cc:dd:ee:ff",
+        data={
+            "data": {"attempt_state": 143, "battery": 100},
+            "isEncrypted": False,
+            "model": "y",
+            "modelFriendlyName": "Keypad",
+            "modelName": SwitchbotModel.KEYPAD,
+            "rawAdvData": b"y\x00d",
+        },
+        device=ble_device,
+        rssi=-67,
+        active=True,
+    )