From 5d85983b09f6eddcf69ab1eef6a547319590aa54 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 20 Jul 2021 18:49:05 -1000 Subject: [PATCH] Update google assistant locks to support locking, unlocking, jammed (#52820) --- .../components/google_assistant/trait.py | 7 +++- .../components/google_assistant/test_trait.py | 39 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 0c547f18741..a710010bb8d 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -24,6 +24,7 @@ from homeassistant.components import ( ) from homeassistant.components.climate import const as climate from homeassistant.components.humidifier import const as humidifier +from homeassistant.components.lock import STATE_JAMMED, STATE_UNLOCKING from homeassistant.components.media_player.const import MEDIA_TYPE_CHANNEL from homeassistant.const import ( ATTR_ASSUMED_STATE, @@ -1101,7 +1102,11 @@ class LockUnlockTrait(_Trait): def query_attributes(self): """Return LockUnlock query attributes.""" - return {"isLocked": self.state.state == STATE_LOCKED} + if self.state.state == STATE_JAMMED: + return {"isJammed": True} + + # If its unlocking its not yet unlocked so we consider is locked + return {"isLocked": self.state.state in (STATE_UNLOCKING, STATE_LOCKED)} async def execute(self, command, data, params, challenge): """Execute an LockUnlock command.""" diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index e2821d207d5..11677ed67d1 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -1042,6 +1042,45 @@ async def test_lock_unlock_lock(hass): assert calls[0].data == {ATTR_ENTITY_ID: "lock.front_door"} +async def test_lock_unlock_unlocking(hass): + """Test LockUnlock trait locking support for lock domain.""" + assert helpers.get_google_type(lock.DOMAIN, None) is not None + assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN, None, None) + assert trait.LockUnlockTrait.might_2fa(lock.DOMAIN, lock.SUPPORT_OPEN, None) + + trt = trait.LockUnlockTrait( + hass, State("lock.front_door", lock.STATE_UNLOCKING), PIN_CONFIG + ) + + assert trt.sync_attributes() == {} + + assert trt.query_attributes() == {"isLocked": True} + + +async def test_lock_unlock_lock_jammed(hass): + """Test LockUnlock trait locking support for lock domain that jams.""" + assert helpers.get_google_type(lock.DOMAIN, None) is not None + assert trait.LockUnlockTrait.supported(lock.DOMAIN, lock.SUPPORT_OPEN, None, None) + assert trait.LockUnlockTrait.might_2fa(lock.DOMAIN, lock.SUPPORT_OPEN, None) + + trt = trait.LockUnlockTrait( + hass, State("lock.front_door", lock.STATE_JAMMED), PIN_CONFIG + ) + + assert trt.sync_attributes() == {} + + assert trt.query_attributes() == {"isJammed": True} + + assert trt.can_execute(trait.COMMAND_LOCKUNLOCK, {"lock": True}) + + calls = async_mock_service(hass, lock.DOMAIN, lock.SERVICE_LOCK) + + await trt.execute(trait.COMMAND_LOCKUNLOCK, PIN_DATA, {"lock": True}, {}) + + assert len(calls) == 1 + assert calls[0].data == {ATTR_ENTITY_ID: "lock.front_door"} + + async def test_lock_unlock_unlock(hass): """Test LockUnlock trait unlocking support for lock domain.""" assert helpers.get_google_type(lock.DOMAIN, None) is not None