Skip to content

Commit

Permalink
Fix Matter 1.2 locks with specific unlatch/unbolt support (#103275)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelveldt authored Nov 3, 2023
1 parent ac1dc4e commit 680162d
Show file tree
Hide file tree
Showing 4 changed files with 605 additions and 22 deletions.
58 changes: 36 additions & 22 deletions homeassistant/components/matter/lock.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"""Matter lock."""
from __future__ import annotations

from enum import IntFlag
from typing import Any

from chip.clusters import Objects as clusters

from homeassistant.components.lock import LockEntity, LockEntityDescription
from homeassistant.components.lock import (
LockEntity,
LockEntityDescription,
LockEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_CODE, Platform
from homeassistant.core import HomeAssistant, callback
Expand All @@ -17,6 +20,8 @@
from .helpers import get_matter
from .models import MatterDiscoverySchema

DoorLockFeature = clusters.DoorLock.Bitmaps.Feature


async def async_setup_entry(
hass: HomeAssistant,
Expand Down Expand Up @@ -61,6 +66,14 @@ def supports_door_position_sensor(self) -> bool:

return bool(self.features & DoorLockFeature.kDoorPositionSensor)

@property
def supports_unbolt(self) -> bool:
"""Return True if the lock supports unbolt."""
if self.features is None:
return False

return bool(self.features & DoorLockFeature.kUnbolt)

async def send_device_command(
self,
command: clusters.ClusterCommand,
Expand Down Expand Up @@ -92,6 +105,25 @@ async def async_unlock(self, **kwargs: Any) -> None:
self._lock_option_default_code,
)
code_bytes = code.encode() if code else None
if self.supports_unbolt:
# if the lock reports it has separate unbolt support,
# the unlock command should unbolt only on the unlock command
# and unlatch on the HA 'open' command.
await self.send_device_command(
command=clusters.DoorLock.Commands.UnboltDoor(code_bytes)
)
else:
await self.send_device_command(
command=clusters.DoorLock.Commands.UnlockDoor(code_bytes)
)

async def async_open(self, **kwargs: Any) -> None:
"""Open the door latch."""
code: str = kwargs.get(
ATTR_CODE,
self._lock_option_default_code,
)
code_bytes = code.encode() if code else None
await self.send_device_command(
command=clusters.DoorLock.Commands.UnlockDoor(code_bytes)
)
Expand All @@ -104,6 +136,8 @@ def _update_from_device(self) -> None:
self.features = int(
self.get_matter_attribute_value(clusters.DoorLock.Attributes.FeatureMap)
)
if self.supports_unbolt:
self._attr_supported_features = LockEntityFeature.OPEN

lock_state = self.get_matter_attribute_value(
clusters.DoorLock.Attributes.LockState
Expand Down Expand Up @@ -144,26 +178,6 @@ def _update_from_device(self) -> None:
)


class DoorLockFeature(IntFlag):
"""Temp enum that represents the features of a door lock.
Should be replaced by the library provided one once that is released.
"""

kPinCredential = 0x1 # noqa: N815
kRfidCredential = 0x2 # noqa: N815
kFingerCredentials = 0x4 # noqa: N815
kLogging = 0x8 # noqa: N815
kWeekDayAccessSchedules = 0x10 # noqa: N815
kDoorPositionSensor = 0x20 # noqa: N815
kFaceCredentials = 0x40 # noqa: N815
kCredentialsOverTheAirAccess = 0x80 # noqa: N815
kUser = 0x100 # noqa: N815
kNotification = 0x200 # noqa: N815
kYearDayAccessSchedules = 0x400 # noqa: N815
kHolidaySchedules = 0x800 # noqa: N815


DISCOVERY_SCHEMAS = [
MatterDiscoverySchema(
platform=Platform.LOCK,
Expand Down
10 changes: 10 additions & 0 deletions tests/components/matter/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,16 @@ async def door_lock_fixture(
return await setup_integration_with_node_fixture(hass, "door-lock", matter_client)


@pytest.fixture(name="door_lock_with_unbolt")
async def door_lock_with_unbolt_fixture(
hass: HomeAssistant, matter_client: MagicMock
) -> MatterNode:
"""Fixture for a door lock node with unbolt feature."""
return await setup_integration_with_node_fixture(
hass, "door-lock-with-unbolt", matter_client
)


@pytest.fixture(name="eve_contact_sensor_node")
async def eve_contact_sensor_node_fixture(
hass: HomeAssistant, matter_client: MagicMock
Expand Down
Loading

0 comments on commit 680162d

Please sign in to comment.