diff --git a/homeassistant/components/matter/lock.py b/homeassistant/components/matter/lock.py index 5456554a535..1cc85fa897e 100644 --- a/homeassistant/components/matter/lock.py +++ b/homeassistant/components/matter/lock.py @@ -90,6 +90,9 @@ class MatterLock(MatterEntity, LockEntity): async def async_lock(self, **kwargs: Any) -> None: """Lock the lock with pin if needed.""" + # optimistically signal locking to state machine + self._attr_is_locking = True + self.async_write_ha_state() code: str | None = kwargs.get(ATTR_CODE) code_bytes = code.encode() if code else None await self.send_device_command( @@ -98,6 +101,9 @@ class MatterLock(MatterEntity, LockEntity): async def async_unlock(self, **kwargs: Any) -> None: """Unlock the lock with pin if needed.""" + # optimistically signal unlocking to state machine + self._attr_is_unlocking = True + self.async_write_ha_state() code: str | None = kwargs.get(ATTR_CODE) code_bytes = code.encode() if code else None if self.supports_unbolt: @@ -114,6 +120,9 @@ class MatterLock(MatterEntity, LockEntity): async def async_open(self, **kwargs: Any) -> None: """Open the door latch.""" + # optimistically signal unlocking to state machine + self._attr_is_unlocking = True + self.async_write_ha_state() code: str | None = kwargs.get(ATTR_CODE) code_bytes = code.encode() if code else None await self.send_device_command( @@ -135,26 +144,23 @@ class MatterLock(MatterEntity, LockEntity): clusters.DoorLock.Attributes.LockState ) + # always reset the optimisically (un)locking state on state update + self._attr_is_locking = False + self._attr_is_unlocking = False + LOGGER.debug("Lock state: %s for %s", lock_state, self.entity_id) if lock_state is clusters.DoorLock.Enums.DlLockState.kLocked: self._attr_is_locked = True - self._attr_is_locking = False - self._attr_is_unlocking = False - elif lock_state is clusters.DoorLock.Enums.DlLockState.kUnlocked: + elif lock_state in ( + clusters.DoorLock.Enums.DlLockState.kUnlocked, + clusters.DoorLock.Enums.DlLockState.kUnlatched, + clusters.DoorLock.Enums.DlLockState.kNotFullyLocked, + ): self._attr_is_locked = False - self._attr_is_locking = False - self._attr_is_unlocking = False - elif lock_state is clusters.DoorLock.Enums.DlLockState.kNotFullyLocked: - if self.is_locked is True: - self._attr_is_unlocking = True - elif self.is_locked is False: - self._attr_is_locking = True else: # According to the matter docs a null state can happen during device startup. self._attr_is_locked = None - self._attr_is_locking = None - self._attr_is_unlocking = None if self.supports_door_position_sensor: door_state = self.get_matter_attribute_value( diff --git a/tests/components/matter/test_door_lock.py b/tests/components/matter/test_door_lock.py index a0664612aba..84f0e58a647 100644 --- a/tests/components/matter/test_door_lock.py +++ b/tests/components/matter/test_door_lock.py @@ -8,13 +8,11 @@ import pytest from homeassistant.components.lock import ( STATE_LOCKED, - STATE_LOCKING, STATE_OPEN, STATE_UNLOCKED, - STATE_UNLOCKING, LockEntityFeature, ) -from homeassistant.const import ATTR_CODE, STATE_UNKNOWN +from homeassistant.const import ATTR_CODE, STATE_LOCKING, STATE_UNKNOWN from homeassistant.core import HomeAssistant from homeassistant.exceptions import ServiceValidationError import homeassistant.helpers.entity_registry as er @@ -68,14 +66,14 @@ async def test_lock( state = hass.states.get("lock.mock_door_lock_lock") assert state - assert state.state == STATE_LOCKED + assert state.state == STATE_LOCKING set_node_attribute(door_lock, 1, 257, 0, 0) await trigger_subscription_callback(hass, matter_client) state = hass.states.get("lock.mock_door_lock_lock") assert state - assert state.state == STATE_UNLOCKING + assert state.state == STATE_UNLOCKED set_node_attribute(door_lock, 1, 257, 0, 2) await trigger_subscription_callback(hass, matter_client) @@ -89,7 +87,7 @@ async def test_lock( state = hass.states.get("lock.mock_door_lock_lock") assert state - assert state.state == STATE_LOCKING + assert state.state == STATE_UNLOCKED set_node_attribute(door_lock, 1, 257, 0, None) await trigger_subscription_callback(hass, matter_client)