mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Preliminary support for Matter cover (#90262)
Preliminary support for Matter cover, curtain tilt support has not been added yet.
This commit is contained in:
parent
e962dd64cf
commit
a9e14cd8d7
153
homeassistant/components/matter/cover.py
Normal file
153
homeassistant/components/matter/cover.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
"""Matter cover."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from chip.clusters import Objects as clusters
|
||||||
|
|
||||||
|
from homeassistant.components.cover import (
|
||||||
|
ATTR_POSITION,
|
||||||
|
CoverEntity,
|
||||||
|
CoverEntityDescription,
|
||||||
|
CoverEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import LOGGER
|
||||||
|
from .entity import MatterEntity
|
||||||
|
from .helpers import get_matter
|
||||||
|
from .models import MatterDiscoverySchema
|
||||||
|
|
||||||
|
# The MASK used for extracting bits 0 to 1 of the byte.
|
||||||
|
OPERATIONAL_STATUS_MASK = 0b11
|
||||||
|
|
||||||
|
|
||||||
|
class OperationalStatus(IntEnum):
|
||||||
|
"""Currently ongoing operations enumeration for coverings, as defined in the Matter spec."""
|
||||||
|
|
||||||
|
COVERING_IS_CURRENTLY_NOT_MOVING = 0b00
|
||||||
|
COVERING_IS_CURRENTLY_OPENING = 0b01
|
||||||
|
COVERING_IS_CURRENTLY_CLOSING = 0b10
|
||||||
|
RESERVED = 0b11
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Matter Cover from Config Entry."""
|
||||||
|
matter = get_matter(hass)
|
||||||
|
matter.register_platform_handler(Platform.COVER, async_add_entities)
|
||||||
|
|
||||||
|
|
||||||
|
class MatterCover(MatterEntity, CoverEntity):
|
||||||
|
"""Representation of a Matter Cover."""
|
||||||
|
|
||||||
|
entity_description: CoverEntityDescription
|
||||||
|
_attr_supported_features = (
|
||||||
|
CoverEntityFeature.OPEN
|
||||||
|
| CoverEntityFeature.CLOSE
|
||||||
|
| CoverEntityFeature.STOP
|
||||||
|
| CoverEntityFeature.SET_POSITION
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_cover_position(self) -> int:
|
||||||
|
"""Return the current position of cover."""
|
||||||
|
if self._attr_current_cover_position:
|
||||||
|
current_position = self._attr_current_cover_position
|
||||||
|
else:
|
||||||
|
current_position = self.get_matter_attribute_value(
|
||||||
|
clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage
|
||||||
|
)
|
||||||
|
|
||||||
|
assert current_position is not None
|
||||||
|
|
||||||
|
return current_position
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_closed(self) -> bool:
|
||||||
|
"""Return true if cover is closed, else False."""
|
||||||
|
return self.current_cover_position == 0
|
||||||
|
|
||||||
|
async def async_stop_cover(self, **kwargs: Any) -> None:
|
||||||
|
"""Stop the cover movement."""
|
||||||
|
await self.send_device_command(clusters.WindowCovering.Commands.StopMotion())
|
||||||
|
|
||||||
|
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||||
|
"""Open the cover."""
|
||||||
|
await self.send_device_command(clusters.WindowCovering.Commands.UpOrOpen())
|
||||||
|
|
||||||
|
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||||
|
"""Close the cover."""
|
||||||
|
await self.send_device_command(clusters.WindowCovering.Commands.DownOrClose())
|
||||||
|
|
||||||
|
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
||||||
|
"""Set the cover to a specific position."""
|
||||||
|
position = kwargs[ATTR_POSITION]
|
||||||
|
await self.send_device_command(
|
||||||
|
clusters.WindowCovering.Commands.GoToLiftValue(position)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def send_device_command(self, command: Any) -> None:
|
||||||
|
"""Send device command."""
|
||||||
|
await self.matter_client.send_device_command(
|
||||||
|
node_id=self._endpoint.node.node_id,
|
||||||
|
endpoint_id=self._endpoint.endpoint_id,
|
||||||
|
command=command,
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _update_from_device(self) -> None:
|
||||||
|
"""Update from device."""
|
||||||
|
operational_status = self.get_matter_attribute_value(
|
||||||
|
clusters.WindowCovering.Attributes.OperationalStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
assert operational_status is not None
|
||||||
|
|
||||||
|
LOGGER.debug(
|
||||||
|
"Operational status %s for %s",
|
||||||
|
f"{operational_status:#010b}",
|
||||||
|
self.entity_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = operational_status & OPERATIONAL_STATUS_MASK
|
||||||
|
match state:
|
||||||
|
case OperationalStatus.COVERING_IS_CURRENTLY_OPENING:
|
||||||
|
self._attr_is_opening = True
|
||||||
|
self._attr_is_closing = False
|
||||||
|
case OperationalStatus.COVERING_IS_CURRENTLY_CLOSING:
|
||||||
|
self._attr_is_opening = False
|
||||||
|
self._attr_is_closing = True
|
||||||
|
case _:
|
||||||
|
self._attr_is_opening = False
|
||||||
|
self._attr_is_closing = False
|
||||||
|
|
||||||
|
self._attr_current_cover_position = self.get_matter_attribute_value(
|
||||||
|
clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage
|
||||||
|
)
|
||||||
|
LOGGER.debug(
|
||||||
|
"Current position: %s for %s",
|
||||||
|
self._attr_current_cover_position,
|
||||||
|
self.entity_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Discovery schema(s) to map Matter Attributes to HA entities
|
||||||
|
DISCOVERY_SCHEMAS = [
|
||||||
|
MatterDiscoverySchema(
|
||||||
|
platform=Platform.COVER,
|
||||||
|
entity_description=CoverEntityDescription(key="MatterCover"),
|
||||||
|
entity_class=MatterCover,
|
||||||
|
required_attributes=(
|
||||||
|
clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage,
|
||||||
|
clusters.WindowCovering.Attributes.OperationalStatus,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -10,6 +10,7 @@ from homeassistant.const import Platform
|
|||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
|
||||||
from .binary_sensor import DISCOVERY_SCHEMAS as BINARY_SENSOR_SCHEMAS
|
from .binary_sensor import DISCOVERY_SCHEMAS as BINARY_SENSOR_SCHEMAS
|
||||||
|
from .cover import DISCOVERY_SCHEMAS as COVER_SCHEMAS
|
||||||
from .light import DISCOVERY_SCHEMAS as LIGHT_SCHEMAS
|
from .light import DISCOVERY_SCHEMAS as LIGHT_SCHEMAS
|
||||||
from .lock import DISCOVERY_SCHEMAS as LOCK_SCHEMAS
|
from .lock import DISCOVERY_SCHEMAS as LOCK_SCHEMAS
|
||||||
from .models import MatterDiscoverySchema, MatterEntityInfo
|
from .models import MatterDiscoverySchema, MatterEntityInfo
|
||||||
@ -18,6 +19,7 @@ from .switch import DISCOVERY_SCHEMAS as SWITCH_SCHEMAS
|
|||||||
|
|
||||||
DISCOVERY_SCHEMAS: dict[Platform, list[MatterDiscoverySchema]] = {
|
DISCOVERY_SCHEMAS: dict[Platform, list[MatterDiscoverySchema]] = {
|
||||||
Platform.BINARY_SENSOR: BINARY_SENSOR_SCHEMAS,
|
Platform.BINARY_SENSOR: BINARY_SENSOR_SCHEMAS,
|
||||||
|
Platform.COVER: COVER_SCHEMAS,
|
||||||
Platform.LIGHT: LIGHT_SCHEMAS,
|
Platform.LIGHT: LIGHT_SCHEMAS,
|
||||||
Platform.LOCK: LOCK_SCHEMAS,
|
Platform.LOCK: LOCK_SCHEMAS,
|
||||||
Platform.SENSOR: SENSOR_SCHEMAS,
|
Platform.SENSOR: SENSOR_SCHEMAS,
|
||||||
|
721
tests/components/matter/fixtures/nodes/window-covering.json
Normal file
721
tests/components/matter/fixtures/nodes/window-covering.json
Normal file
@ -0,0 +1,721 @@
|
|||||||
|
{
|
||||||
|
"node_id": 1,
|
||||||
|
"date_commissioned": "2023-03-29T08:23:30.740085",
|
||||||
|
"last_interview": "2023-03-29T08:23:30.740087",
|
||||||
|
"interview_version": 2,
|
||||||
|
"available": true,
|
||||||
|
"attributes": {
|
||||||
|
"0/29/0": [
|
||||||
|
{
|
||||||
|
"type": 22,
|
||||||
|
"revision": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/29/1": [
|
||||||
|
29,
|
||||||
|
30,
|
||||||
|
31,
|
||||||
|
40,
|
||||||
|
42,
|
||||||
|
43,
|
||||||
|
44,
|
||||||
|
45,
|
||||||
|
48,
|
||||||
|
49,
|
||||||
|
50,
|
||||||
|
51,
|
||||||
|
54,
|
||||||
|
60,
|
||||||
|
62,
|
||||||
|
63,
|
||||||
|
64,
|
||||||
|
65
|
||||||
|
],
|
||||||
|
"0/29/2": [
|
||||||
|
41
|
||||||
|
],
|
||||||
|
"0/29/3": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"0/29/65532": 0,
|
||||||
|
"0/29/65533": 1,
|
||||||
|
"0/29/65528": [],
|
||||||
|
"0/29/65529": [],
|
||||||
|
"0/29/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/30/0": [],
|
||||||
|
"0/30/65532": 0,
|
||||||
|
"0/30/65533": 1,
|
||||||
|
"0/30/65528": [],
|
||||||
|
"0/30/65529": [],
|
||||||
|
"0/30/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/31/0": [
|
||||||
|
{
|
||||||
|
"privilege": 5,
|
||||||
|
"authMode": 2,
|
||||||
|
"subjects": [
|
||||||
|
112233
|
||||||
|
],
|
||||||
|
"targets": null,
|
||||||
|
"fabricIndex": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/31/1": [],
|
||||||
|
"0/31/2": 4,
|
||||||
|
"0/31/3": 3,
|
||||||
|
"0/31/4": 3,
|
||||||
|
"0/31/65532": 0,
|
||||||
|
"0/31/65533": 1,
|
||||||
|
"0/31/65528": [],
|
||||||
|
"0/31/65529": [],
|
||||||
|
"0/31/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/40/0": 1,
|
||||||
|
"0/40/1": "Eliteu",
|
||||||
|
"0/40/2": 4895,
|
||||||
|
"0/40/3": "Longan link WNCV DA01",
|
||||||
|
"0/40/4": 12288,
|
||||||
|
"0/40/5": "",
|
||||||
|
"0/40/6": "XX",
|
||||||
|
"0/40/7": 1,
|
||||||
|
"0/40/8": "1.0",
|
||||||
|
"0/40/9": 1,
|
||||||
|
"0/40/10": "v1.0",
|
||||||
|
"0/40/11": "20200101",
|
||||||
|
"0/40/12": "",
|
||||||
|
"0/40/13": "",
|
||||||
|
"0/40/14": "",
|
||||||
|
"0/40/15": "3c70c712bd34e54acebd1a8371f56f7d",
|
||||||
|
"0/40/16": false,
|
||||||
|
"0/40/17": true,
|
||||||
|
"0/40/18": "7630EF9998EDF03C",
|
||||||
|
"0/40/19": {
|
||||||
|
"caseSessionsPerFabric": 3,
|
||||||
|
"subscriptionsPerFabric": 3
|
||||||
|
},
|
||||||
|
"0/40/65532": 0,
|
||||||
|
"0/40/65533": 1,
|
||||||
|
"0/40/65528": [],
|
||||||
|
"0/40/65529": [],
|
||||||
|
"0/40/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
12,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
15,
|
||||||
|
16,
|
||||||
|
17,
|
||||||
|
18,
|
||||||
|
19,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/42/0": [],
|
||||||
|
"0/42/1": true,
|
||||||
|
"0/42/2": 1,
|
||||||
|
"0/42/3": null,
|
||||||
|
"0/42/65532": 0,
|
||||||
|
"0/42/65533": 1,
|
||||||
|
"0/42/65528": [],
|
||||||
|
"0/42/65529": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"0/42/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/43/0": "en-US",
|
||||||
|
"0/43/1": [
|
||||||
|
"en-US",
|
||||||
|
"de-DE",
|
||||||
|
"fr-FR",
|
||||||
|
"en-GB",
|
||||||
|
"es-ES",
|
||||||
|
"zh-CN",
|
||||||
|
"it-IT",
|
||||||
|
"ja-JP"
|
||||||
|
],
|
||||||
|
"0/43/65532": 0,
|
||||||
|
"0/43/65533": 1,
|
||||||
|
"0/43/65528": [],
|
||||||
|
"0/43/65529": [],
|
||||||
|
"0/43/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/44/0": 0,
|
||||||
|
"0/44/1": 0,
|
||||||
|
"0/44/2": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"0/44/65532": 0,
|
||||||
|
"0/44/65533": 1,
|
||||||
|
"0/44/65528": [],
|
||||||
|
"0/44/65529": [],
|
||||||
|
"0/44/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/45/0": 0,
|
||||||
|
"0/45/65532": 0,
|
||||||
|
"0/45/65533": 1,
|
||||||
|
"0/45/65528": [],
|
||||||
|
"0/45/65529": [],
|
||||||
|
"0/45/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/48/0": 0,
|
||||||
|
"0/48/1": {
|
||||||
|
"failSafeExpiryLengthSeconds": 60,
|
||||||
|
"maxCumulativeFailsafeSeconds": 900
|
||||||
|
},
|
||||||
|
"0/48/2": 0,
|
||||||
|
"0/48/3": 0,
|
||||||
|
"0/48/4": true,
|
||||||
|
"0/48/65532": 0,
|
||||||
|
"0/48/65533": 1,
|
||||||
|
"0/48/65528": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"0/48/65529": [
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"0/48/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/49/0": 1,
|
||||||
|
"0/49/1": [
|
||||||
|
{
|
||||||
|
"networkID": "TE9OR0FOLUlPVA==",
|
||||||
|
"connected": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/49/2": 10,
|
||||||
|
"0/49/3": 30,
|
||||||
|
"0/49/4": true,
|
||||||
|
"0/49/5": 0,
|
||||||
|
"0/49/6": "TE9OR0FOLUlPVA==",
|
||||||
|
"0/49/7": null,
|
||||||
|
"0/49/65532": 1,
|
||||||
|
"0/49/65533": 1,
|
||||||
|
"0/49/65528": [
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"0/49/65529": [
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"0/49/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/50/65532": 0,
|
||||||
|
"0/50/65533": 1,
|
||||||
|
"0/50/65528": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"0/50/65529": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"0/50/65531": [
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/51/0": [
|
||||||
|
{
|
||||||
|
"name": "WIFI_STA_DEF",
|
||||||
|
"isOperational": true,
|
||||||
|
"offPremiseServicesReachableIPv4": null,
|
||||||
|
"offPremiseServicesReachableIPv6": null,
|
||||||
|
"hardwareAddress": "hPcDB5/k",
|
||||||
|
"IPv4Addresses": [
|
||||||
|
"wKgIhg=="
|
||||||
|
],
|
||||||
|
"IPv6Addresses": [
|
||||||
|
"/oAAAAAAAACG9wP//gef5A==",
|
||||||
|
"JA4DsgZ+bsCG9wP//gef5A=="
|
||||||
|
],
|
||||||
|
"type": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/51/1": 35,
|
||||||
|
"0/51/2": 123,
|
||||||
|
"0/51/3": 0,
|
||||||
|
"0/51/4": 6,
|
||||||
|
"0/51/5": [],
|
||||||
|
"0/51/6": [],
|
||||||
|
"0/51/7": [],
|
||||||
|
"0/51/8": false,
|
||||||
|
"0/51/65532": 0,
|
||||||
|
"0/51/65533": 1,
|
||||||
|
"0/51/65528": [],
|
||||||
|
"0/51/65529": [
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"0/51/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/54/0": "mJfMGB1w",
|
||||||
|
"0/54/1": 0,
|
||||||
|
"0/54/2": 3,
|
||||||
|
"0/54/3": 1,
|
||||||
|
"0/54/4": -36,
|
||||||
|
"0/54/65532": 0,
|
||||||
|
"0/54/65533": 1,
|
||||||
|
"0/54/65528": [],
|
||||||
|
"0/54/65529": [],
|
||||||
|
"0/54/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/60/0": 0,
|
||||||
|
"0/60/1": null,
|
||||||
|
"0/60/2": null,
|
||||||
|
"0/60/65532": 0,
|
||||||
|
"0/60/65533": 1,
|
||||||
|
"0/60/65528": [],
|
||||||
|
"0/60/65529": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"0/60/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/62/0": [
|
||||||
|
{
|
||||||
|
"noc": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVASQRARgkBwEkCAEwCUEE5Rw88GvXEUXr+cPYgKd00rIWyiHM8eu4Bhrzf1v83yBI2Qa+pwfOsKyvzxiuHLMfzhdC3gre4najpimi8AsX+TcKNQEoARgkAgE2AwQCBAEYMAQUWh6NlHAMbG5gz+vqlF51fulr3z8wBRR+D1hE33RhFC/mJWrhhZs6SVStQBgwC0DD5IxVgOrftUA47K1bQHaCNuWqIxf/8oMfcI0nMvTtXApwbBAJI/LjjCwMZJVFBE3W/FC6dQWSEuF8ES745tLBGA==",
|
||||||
|
"icac": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEzpstYxy3lXF69g6H2vQ6uoqkdUsppJ4NcSyQcXQ8sQrF5HuzoVnDpevHfy0GAWHbXfE4VI0laTHvm/Wkj037ZjcKNQEpARgkAmAwBBR+D1hE33RhFC/mJWrhhZs6SVStQDAFFFCCK5NYv6CrD5/0S26zXBUwG0WBGDALQI5YKo3C3xvdqCrho2yZIJVJpJY2n9V/tmh7ESBBOHrY0b+K8Pf7hKhd5V0vzbCCbkhv1BNEne+lhcS2N6qhMNgY",
|
||||||
|
"fabricIndex": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/62/1": [
|
||||||
|
{
|
||||||
|
"rootPublicKey": "BFLMrM1satBpU0DN4sri/S4AVo/ugmZCndBfPO33Q+ZCKDZzNhMOB014+hZs0KL7vPssavT7Tb9nt0W+kpeAe0U=",
|
||||||
|
"vendorId": 65521,
|
||||||
|
"fabricId": 1,
|
||||||
|
"nodeId": 1,
|
||||||
|
"label": "",
|
||||||
|
"fabricIndex": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/62/2": 5,
|
||||||
|
"0/62/3": 2,
|
||||||
|
"0/62/4": [
|
||||||
|
"FTABAQAkAgE3AycUBZIG4P1iqI0kFQEYJgRBkLUrJgXBw5YtNwYnFAWSBuD9YqiNJBUBGCQHASQIATAJQQRruztKRDFfiVjMY19sSsnKqBZJlZrQ/ClUtTYatvOZxbTC53iCqhwHaIJthMWs7ICwtSX1Vr5lGkzDXQjH/oQ6Nwo1ASkBGCQCYDAEFJd2wRMLYsFFA1PRCdMviVipH3OWMAUUl3bBEwtiwUUDU9EJ0y+JWKkfc5YYMAtASJa3FJ84kws+OOWNEMgRvcZA/d0AJVmmoqoWrorxxfpVKujZuN8Kc193rwBckfxd69s3OS1y8HCZTtooCemIpBg=",
|
||||||
|
"FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEUsyszWxq0GlTQM3iyuL9LgBWj+6CZkKd0F887fdD5kIoNnM2Ew4HTXj6FmzQovu8+yxq9PtNv2e3Rb6Sl4B7RTcKNQEpARgkAmAwBBRQgiuTWL+gqw+f9Etus1wVMBtFgTAFFFCCK5NYv6CrD5/0S26zXBUwG0WBGDALQFyHXux9szIosC1gP+/1/7BX3PfGaX2GF172oHSAoMXnLJ7OawkzgWIykEj7oRIjKv3XRR27y3KhV83817SfCOkY"
|
||||||
|
],
|
||||||
|
"0/62/5": 2,
|
||||||
|
"0/62/65532": 0,
|
||||||
|
"0/62/65533": 1,
|
||||||
|
"0/62/65528": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"0/62/65529": [
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
10,
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"0/62/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/63/0": [],
|
||||||
|
"0/63/1": [],
|
||||||
|
"0/63/2": 3,
|
||||||
|
"0/63/3": 3,
|
||||||
|
"0/63/65532": 0,
|
||||||
|
"0/63/65533": 1,
|
||||||
|
"0/63/65528": [
|
||||||
|
2,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"0/63/65529": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"0/63/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/64/0": [
|
||||||
|
{
|
||||||
|
"label": "room",
|
||||||
|
"value": "bedroom 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "orientation",
|
||||||
|
"value": "North"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "floor",
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "direction",
|
||||||
|
"value": "up"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"0/64/65532": 0,
|
||||||
|
"0/64/65533": 1,
|
||||||
|
"0/64/65528": [],
|
||||||
|
"0/64/65529": [],
|
||||||
|
"0/64/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"0/65/0": [],
|
||||||
|
"0/65/65532": 0,
|
||||||
|
"0/65/65533": 1,
|
||||||
|
"0/65/65528": [],
|
||||||
|
"0/65/65529": [],
|
||||||
|
"0/65/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/3/0": 0,
|
||||||
|
"1/3/1": 2,
|
||||||
|
"1/3/65532": 0,
|
||||||
|
"1/3/65533": 4,
|
||||||
|
"1/3/65528": [],
|
||||||
|
"1/3/65529": [
|
||||||
|
0,
|
||||||
|
64
|
||||||
|
],
|
||||||
|
"1/3/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/4/0": 128,
|
||||||
|
"1/4/65532": 1,
|
||||||
|
"1/4/65533": 4,
|
||||||
|
"1/4/65528": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"1/4/65529": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"1/4/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/29/0": [
|
||||||
|
{
|
||||||
|
"type": 514,
|
||||||
|
"revision": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1/29/1": [
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
29,
|
||||||
|
30,
|
||||||
|
64,
|
||||||
|
65,
|
||||||
|
258
|
||||||
|
],
|
||||||
|
"1/29/2": [],
|
||||||
|
"1/29/3": [],
|
||||||
|
"1/29/65532": 0,
|
||||||
|
"1/29/65533": 1,
|
||||||
|
"1/29/65528": [],
|
||||||
|
"1/29/65529": [],
|
||||||
|
"1/29/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/30/0": [],
|
||||||
|
"1/30/65532": 0,
|
||||||
|
"1/30/65533": 1,
|
||||||
|
"1/30/65528": [],
|
||||||
|
"1/30/65529": [],
|
||||||
|
"1/30/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/64/0": [
|
||||||
|
{
|
||||||
|
"label": "room",
|
||||||
|
"value": "bedroom 2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "orientation",
|
||||||
|
"value": "North"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "floor",
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "direction",
|
||||||
|
"value": "up"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"1/64/65532": 0,
|
||||||
|
"1/64/65533": 1,
|
||||||
|
"1/64/65528": [],
|
||||||
|
"1/64/65529": [],
|
||||||
|
"1/64/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/65/0": [],
|
||||||
|
"1/65/65532": 0,
|
||||||
|
"1/65/65533": 1,
|
||||||
|
"1/65/65528": [],
|
||||||
|
"1/65/65529": [],
|
||||||
|
"1/65/65531": [
|
||||||
|
0,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
],
|
||||||
|
"1/258/0": 0,
|
||||||
|
"1/258/1": 0,
|
||||||
|
"1/258/3": 0,
|
||||||
|
"1/258/5": 0,
|
||||||
|
"1/258/7": 11,
|
||||||
|
"1/258/8": 100,
|
||||||
|
"1/258/10": 0,
|
||||||
|
"1/258/11": 0,
|
||||||
|
"1/258/13": 0,
|
||||||
|
"1/258/14": 4900,
|
||||||
|
"1/258/16": 0,
|
||||||
|
"1/258/17": 65535,
|
||||||
|
"1/258/23": 0,
|
||||||
|
"1/258/65532": 13,
|
||||||
|
"1/258/65533": 5,
|
||||||
|
"1/258/65528": [],
|
||||||
|
"1/258/65529": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
18,
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"1/258/65531": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
10,
|
||||||
|
11,
|
||||||
|
13,
|
||||||
|
14,
|
||||||
|
16,
|
||||||
|
17,
|
||||||
|
23,
|
||||||
|
65528,
|
||||||
|
65529,
|
||||||
|
65531,
|
||||||
|
65532,
|
||||||
|
65533
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
141
tests/components/matter/test_cover.py
Normal file
141
tests/components/matter/test_cover.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
"""Test Matter covers."""
|
||||||
|
from unittest.mock import MagicMock, call
|
||||||
|
|
||||||
|
from chip.clusters import Objects as clusters
|
||||||
|
from matter_server.client.models.node import MatterNode
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.cover import (
|
||||||
|
STATE_CLOSED,
|
||||||
|
STATE_CLOSING,
|
||||||
|
STATE_OPEN,
|
||||||
|
STATE_OPENING,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .common import (
|
||||||
|
set_node_attribute,
|
||||||
|
setup_integration_with_node_fixture,
|
||||||
|
trigger_subscription_callback,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="window_covering")
|
||||||
|
async def window_covering_fixture(
|
||||||
|
hass: HomeAssistant, matter_client: MagicMock
|
||||||
|
) -> MatterNode:
|
||||||
|
"""Fixture for a window covering node."""
|
||||||
|
return await setup_integration_with_node_fixture(
|
||||||
|
hass, "window-covering", matter_client
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# This tests needs to be adjusted to remove lingering tasks
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
async def test_cover(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
matter_client: MagicMock,
|
||||||
|
window_covering: MatterNode,
|
||||||
|
) -> None:
|
||||||
|
"""Test window covering."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"close_cover",
|
||||||
|
{
|
||||||
|
"entity_id": "cover.longan_link_wncv_da01",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert matter_client.send_device_command.call_count == 1
|
||||||
|
assert matter_client.send_device_command.call_args == call(
|
||||||
|
node_id=window_covering.node_id,
|
||||||
|
endpoint_id=1,
|
||||||
|
command=clusters.WindowCovering.Commands.DownOrClose(),
|
||||||
|
)
|
||||||
|
matter_client.send_device_command.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"stop_cover",
|
||||||
|
{
|
||||||
|
"entity_id": "cover.longan_link_wncv_da01",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert matter_client.send_device_command.call_count == 1
|
||||||
|
assert matter_client.send_device_command.call_args == call(
|
||||||
|
node_id=window_covering.node_id,
|
||||||
|
endpoint_id=1,
|
||||||
|
command=clusters.WindowCovering.Commands.StopMotion(),
|
||||||
|
)
|
||||||
|
matter_client.send_device_command.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"open_cover",
|
||||||
|
{
|
||||||
|
"entity_id": "cover.longan_link_wncv_da01",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert matter_client.send_device_command.call_count == 1
|
||||||
|
assert matter_client.send_device_command.call_args == call(
|
||||||
|
node_id=window_covering.node_id,
|
||||||
|
endpoint_id=1,
|
||||||
|
command=clusters.WindowCovering.Commands.UpOrOpen(),
|
||||||
|
)
|
||||||
|
matter_client.send_device_command.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"cover",
|
||||||
|
"set_cover_position",
|
||||||
|
{
|
||||||
|
"entity_id": "cover.longan_link_wncv_da01",
|
||||||
|
"position": 50,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert matter_client.send_device_command.call_count == 1
|
||||||
|
assert matter_client.send_device_command.call_args == call(
|
||||||
|
node_id=window_covering.node_id,
|
||||||
|
endpoint_id=1,
|
||||||
|
command=clusters.WindowCovering.Commands.GoToLiftValue(50),
|
||||||
|
)
|
||||||
|
matter_client.send_device_command.reset_mock()
|
||||||
|
|
||||||
|
set_node_attribute(window_covering, 1, 258, 8, 30)
|
||||||
|
set_node_attribute(window_covering, 1, 258, 10, 2)
|
||||||
|
await trigger_subscription_callback(hass, matter_client)
|
||||||
|
|
||||||
|
state = hass.states.get("cover.longan_link_wncv_da01")
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_CLOSING
|
||||||
|
|
||||||
|
set_node_attribute(window_covering, 1, 258, 8, 0)
|
||||||
|
set_node_attribute(window_covering, 1, 258, 10, 0)
|
||||||
|
await trigger_subscription_callback(hass, matter_client)
|
||||||
|
|
||||||
|
state = hass.states.get("cover.longan_link_wncv_da01")
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_CLOSED
|
||||||
|
|
||||||
|
set_node_attribute(window_covering, 1, 258, 8, 50)
|
||||||
|
set_node_attribute(window_covering, 1, 258, 10, 1)
|
||||||
|
await trigger_subscription_callback(hass, matter_client)
|
||||||
|
|
||||||
|
state = hass.states.get("cover.longan_link_wncv_da01")
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_OPENING
|
||||||
|
|
||||||
|
set_node_attribute(window_covering, 1, 258, 8, 100)
|
||||||
|
set_node_attribute(window_covering, 1, 258, 10, 0)
|
||||||
|
await trigger_subscription_callback(hass, matter_client)
|
||||||
|
|
||||||
|
state = hass.states.get("cover.longan_link_wncv_da01")
|
||||||
|
assert state
|
||||||
|
assert state.attributes["current_position"] == 100
|
||||||
|
assert state.state == STATE_OPEN
|
Loading…
x
Reference in New Issue
Block a user