Browse Source

Added support for Night Latch feature of EU firmware version of smart lock (#215)

Michal Jál 8 months ago
parent
commit
7a292cbd9d
3 changed files with 15 additions and 1 deletions
  1. 1 0
      switchbot/adv_parsers/lock.py
  2. 12 1
      switchbot/devices/lock.py
  3. 2 0
      tests/test_adv_parser.py

+ 1 - 0
switchbot/adv_parsers/lock.py

@@ -27,4 +27,5 @@ def process_wolock(data: bytes | None, mfr_data: bytes | None) -> dict[str, bool
         "unclosed_alarm": bool(mfr_data[8] & 0b00100000),
         "unlocked_alarm": bool(mfr_data[8] & 0b00010000),
         "auto_lock_paused": bool(mfr_data[8] & 0b00000010),
+        "night_latch": bool(mfr_data[9] & 0b00000001),
     }

+ 12 - 1
switchbot/devices/lock.py

@@ -26,6 +26,7 @@ COMMAND_HEADER = "57"
 COMMAND_GET_CK_IV = f"{COMMAND_HEADER}0f2103"
 COMMAND_LOCK_INFO = f"{COMMAND_HEADER}0f4f8101"
 COMMAND_UNLOCK = f"{COMMAND_HEADER}0f4e01011080"
+COMMAND_UNLOCK_WITHOUT_UNLATCH = f"{COMMAND_HEADER}0f4e010110a0"
 COMMAND_LOCK = f"{COMMAND_HEADER}0f4e01011000"
 COMMAND_ENABLE_NOTIFICATIONS = f"{COMMAND_HEADER}0e01001e00008101"
 COMMAND_DISABLE_NOTIFICATIONS = f"{COMMAND_HEADER}0e00"
@@ -164,11 +165,17 @@ class SwitchbotLock(SwitchbotDevice):
         )
 
     async def unlock(self) -> bool:
-        """Send unlock command."""
+        """Send unlock command. If unlatch feature is enabled in EU firmware, also unlatches door"""
         return await self._lock_unlock(
             COMMAND_UNLOCK, {LockStatus.UNLOCKED, LockStatus.UNLOCKING}
         )
 
+    async def unlock_without_unlatch(self) -> bool:
+        """Send unlock command. This command will not unlatch the door."""
+        return await self._lock_unlock(
+            COMMAND_UNLOCK_WITHOUT_UNLATCH, {LockStatus.UNLOCKED, LockStatus.UNLOCKING, LockStatus.NOT_FULLY_LOCKED}
+        )
+
     def _parse_basic_data(self, basic_data: bytes) -> dict[str, Any]:
         """Parse basic data from lock."""
         return {
@@ -239,6 +246,10 @@ class SwitchbotLock(SwitchbotDevice):
         """Return True if auto lock is paused."""
         return self._get_adv_value("auto_lock_paused")
 
+    def is_night_latch_enabled(self) -> bool:
+        """Return True if Night Latch is enabled on EU firmware."""
+        return self._get_adv_value("night_latch")
+        
     async def _get_lock_info(self) -> bytes | None:
         """Return lock info of device."""
         _data = await self._send_command(key=COMMAND_LOCK_INFO, retry=self._retry_count)

+ 2 - 0
tests/test_adv_parser.py

@@ -1234,6 +1234,7 @@ def test_parsing_lock_active():
                 "calibration": True,
                 "door_open": False,
                 "double_lock_mode": False,
+                "night_latch": False,
                 "status": LockStatus.LOCKED,
                 "unclosed_alarm": False,
                 "unlocked_alarm": False,
@@ -1267,6 +1268,7 @@ def test_parsing_lock_passive():
                 "calibration": True,
                 "door_open": False,
                 "double_lock_mode": False,
+                "night_latch": False,
                 "status": LockStatus.LOCKED,
                 "unclosed_alarm": False,
                 "unlocked_alarm": False,