7 Commits e9482cc659 ... 2ca7e6d938

Author SHA1 Message Date
  J. Nick Koston 2ca7e6d938 0.22.0 1 year ago
  J. Nick Koston 33f097efdd Fix black and isort from plug merge (#147) 1 year ago
  Masahiro Konishi bd614c3573 Add plug mini power field (#142) 1 year ago
  Masahiro Konishi 07fb14e869 Support plug mini JP model (#141) 1 year ago
  J. Nick Koston e2430c80fd 0.21.0 1 year ago
  J. Nick Koston e612077e19 Sort deps from lock merge (#146) 1 year ago
  Damian Sypniewski 001841bd38 Add read-only support for lock (#145) 1 year ago

+ 1 - 1
setup.py

@@ -4,7 +4,7 @@ setup(
     name="PySwitchbot",
     packages=["switchbot", "switchbot.devices", "switchbot.adv_parsers"],
     install_requires=["async_timeout>=4.0.1", "bleak>=0.17.0", "bleak-retry-connector>=2.9.0"],
-    version="0.20.8",
+    version="0.22.0",
     description="A library to communicate with Switchbot",
     author="Daniel Hjelseth Hoyer",
     url="https://github.com/Danielhiversen/pySwitchbot/",

+ 11 - 0
switchbot/adv_parser.py

@@ -16,6 +16,7 @@ from .adv_parsers.contact import process_wocontact
 from .adv_parsers.curtain import process_wocurtain
 from .adv_parsers.humidifier import process_wohumidifier
 from .adv_parsers.light_strip import process_wostrip
+from .adv_parsers.lock import process_wolock
 from .adv_parsers.meter import process_wosensorth
 from .adv_parsers.motion import process_wopresence
 from .adv_parsers.plug import process_woplugmini
@@ -79,6 +80,11 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
         "modelFriendlyName": "Plug Mini",
         "func": process_woplugmini,
     },
+    "j": {
+        "modelName": SwitchbotModel.PLUG_MINI,
+        "modelFriendlyName": "Plug Mini (JP)",
+        "func": process_woplugmini,
+    },
     "u": {
         "modelName": SwitchbotModel.COLOR_BULB,
         "modelFriendlyName": "Color Bulb",
@@ -94,6 +100,11 @@ SUPPORTED_TYPES: dict[str, SwitchbotSupportedType] = {
         "modelFriendlyName": "Humidifier",
         "func": process_wohumidifier,
     },
+    "o": {
+        "modelName": SwitchbotModel.LOCK,
+        "modelFriendlyName": "Lock",
+        "func": process_wolock,
+    },
 }
 
 

+ 29 - 0
switchbot/adv_parsers/lock.py

@@ -0,0 +1,29 @@
+"""Lock parser."""
+from __future__ import annotations
+
+import logging
+
+from ..const import LockStatus
+
+_LOGGER = logging.getLogger(__name__)
+
+
+def process_wolock(data: bytes, mfr_data: bytes | None) -> dict[str, bool | int]:
+    """Process woLock services data."""
+    if mfr_data is None:
+        return {}
+
+    _LOGGER.debug("mfr_data: %s", mfr_data.hex())
+    _LOGGER.debug("data: %s", data.hex())
+
+    return {
+        "battery": data[2] & 0b01111111,
+        "calibration": bool(mfr_data[7] & 0b10000000),
+        "status": LockStatus(mfr_data[7] & 0b01110000),
+        "update_from_secondary_lock": bool(mfr_data[7] & 0b00001000),
+        "door_open": bool(mfr_data[7] & 0b00000100),
+        "double_lock_mode": bool(mfr_data[8] & 0b10000000),
+        "unclosed_alarm": bool(mfr_data[8] & 0b00100000),
+        "unlocked_alarm": bool(mfr_data[8] & 0b00010000),
+        "auto_lock_paused": bool(mfr_data[8] & 0b00000010),
+    }

+ 1 - 0
switchbot/adv_parsers/plug.py

@@ -10,4 +10,5 @@ def process_woplugmini(data: bytes, mfr_data: bytes | None) -> dict[str, bool |
         "switchMode": True,
         "isOn": mfr_data[7] == 0x80,
         "wifi_rssi": -mfr_data[9],
+        "power": (((mfr_data[10] << 8) + mfr_data[11]) & 0x7FFF) / 10,  # W
     }

+ 13 - 0
switchbot/const.py

@@ -1,6 +1,8 @@
 """Library to handle connection with Switchbot."""
 from __future__ import annotations
 
+from enum import Enum
+
 DEFAULT_RETRY_COUNT = 3
 DEFAULT_RETRY_TIMEOUT = 1
 DEFAULT_SCAN_TIMEOUT = 5
@@ -20,3 +22,14 @@ class SwitchbotModel(StrEnum):
     MOTION_SENSOR = "WoPresence"
     COLOR_BULB = "WoBulb"
     CEILING_LIGHT = "WoCeiling"
+    LOCK = "WoLock"
+
+
+class LockStatus(Enum):
+    LOCKED = 0b0000000
+    UNLOCKED = 0b0010000
+    LOCKING = 0b0100000
+    UNLOCKING = 0b0110000
+    LOCKING_STOP = 0b1000000
+    UNLOCKING_STOP = 0b1010000
+    NOT_FULLY_LOCKED = 0b1100000  # Only EU lock type

+ 1 - 0
switchbot/devices/lock.py

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

+ 4 - 0
switchbot/discovery.py

@@ -101,6 +101,10 @@ class GetSwitchbotDevices:
         """Return all WoContact/Contact sensor devices with services data."""
         return await self._get_devices_by_model("d")
 
+    async def get_locks(self) -> dict[str, SwitchBotAdvertisement]:
+        """Return all WoLock/Locks devices with services data."""
+        return await self._get_devices_by_model("o")
+
     async def get_device_data(
         self, address: str
     ) -> dict[str, SwitchBotAdvertisement] | None: