Fix locking/unlocking transition state in Matter lock platform (#121099)

This commit is contained in:
Marcel van der Veldt 2024-07-04 09:20:55 +02:00 committed by GitHub
parent ac9c08f52c
commit 24f6e6e885
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 18 deletions

View file

@ -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(

View file

@ -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)