From 564a5054865615c58a20409638bc65d4c6e5354b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 20 Jul 2021 18:55:04 -1000 Subject: [PATCH] Update homekit controller lock to support locking, unlocking, jammed (#52821) --- .../components/homekit_controller/lock.py | 56 +++++++++++++++++-- .../homekit_controller/test_lock.py | 20 +++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/homekit_controller/lock.py b/homeassistant/components/homekit_controller/lock.py index 09c02ce0ff9..3b6fb41f3a8 100644 --- a/homeassistant/components/homekit_controller/lock.py +++ b/homeassistant/components/homekit_controller/lock.py @@ -2,18 +2,28 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from homeassistant.components.lock import LockEntity -from homeassistant.const import ATTR_BATTERY_LEVEL, STATE_LOCKED, STATE_UNLOCKED +from homeassistant.components.lock import STATE_JAMMED, LockEntity +from homeassistant.const import ( + ATTR_BATTERY_LEVEL, + STATE_LOCKED, + STATE_UNKNOWN, + STATE_UNLOCKED, +) from homeassistant.core import callback from . import KNOWN_DEVICES, HomeKitEntity -STATE_JAMMED = "jammed" - -CURRENT_STATE_MAP = {0: STATE_UNLOCKED, 1: STATE_LOCKED, 2: STATE_JAMMED, 3: None} +CURRENT_STATE_MAP = { + 0: STATE_UNLOCKED, + 1: STATE_LOCKED, + 2: STATE_JAMMED, + 3: STATE_UNKNOWN, +} TARGET_STATE_MAP = {STATE_UNLOCKED: 0, STATE_LOCKED: 1} +REVERSED_TARGET_STATE_MAP = {v: k for k, v in TARGET_STATE_MAP.items()} + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Homekit lock.""" @@ -46,8 +56,44 @@ class HomeKitLock(HomeKitEntity, LockEntity): def is_locked(self): """Return true if device is locked.""" value = self.service.value(CharacteristicsTypes.LOCK_MECHANISM_CURRENT_STATE) + if CURRENT_STATE_MAP[value] == STATE_UNKNOWN: + return None return CURRENT_STATE_MAP[value] == STATE_LOCKED + @property + def is_locking(self): + """Return true if device is locking.""" + current_value = self.service.value( + CharacteristicsTypes.LOCK_MECHANISM_CURRENT_STATE + ) + target_value = self.service.value( + CharacteristicsTypes.LOCK_MECHANISM_TARGET_STATE + ) + return ( + CURRENT_STATE_MAP[current_value] == STATE_UNLOCKED + and REVERSED_TARGET_STATE_MAP.get(target_value) == STATE_LOCKED + ) + + @property + def is_unlocking(self): + """Return true if device is unlocking.""" + current_value = self.service.value( + CharacteristicsTypes.LOCK_MECHANISM_CURRENT_STATE + ) + target_value = self.service.value( + CharacteristicsTypes.LOCK_MECHANISM_TARGET_STATE + ) + return ( + CURRENT_STATE_MAP[current_value] == STATE_LOCKED + and REVERSED_TARGET_STATE_MAP.get(target_value) == STATE_UNLOCKED + ) + + @property + def is_jammed(self): + """Return true if device is jammed.""" + value = self.service.value(CharacteristicsTypes.LOCK_MECHANISM_CURRENT_STATE) + return CURRENT_STATE_MAP[value] == STATE_JAMMED + async def async_lock(self, **kwargs): """Lock the device.""" await self._set_lock_state(STATE_LOCKED) diff --git a/tests/components/homekit_controller/test_lock.py b/tests/components/homekit_controller/test_lock.py index 197b7b3c3b9..15e645bf181 100644 --- a/tests/components/homekit_controller/test_lock.py +++ b/tests/components/homekit_controller/test_lock.py @@ -57,3 +57,23 @@ async def test_switch_read_lock_state(hass, utcnow): helper.characteristics[LOCK_TARGET_STATE].value = 1 state = await helper.poll_and_get_state() assert state.state == "locked" + + helper.characteristics[LOCK_CURRENT_STATE].value = 2 + helper.characteristics[LOCK_TARGET_STATE].value = 1 + state = await helper.poll_and_get_state() + assert state.state == "jammed" + + helper.characteristics[LOCK_CURRENT_STATE].value = 3 + helper.characteristics[LOCK_TARGET_STATE].value = 1 + state = await helper.poll_and_get_state() + assert state.state == "unknown" + + helper.characteristics[LOCK_CURRENT_STATE].value = 0 + helper.characteristics[LOCK_TARGET_STATE].value = 1 + state = await helper.poll_and_get_state() + assert state.state == "locking" + + helper.characteristics[LOCK_CURRENT_STATE].value = 1 + helper.characteristics[LOCK_TARGET_STATE].value = 0 + state = await helper.poll_and_get_state() + assert state.state == "unlocking"