diff --git a/homeassistant/components/matter/cover.py b/homeassistant/components/matter/cover.py index 4e227d83b44..9e72b69f335 100644 --- a/homeassistant/components/matter/cover.py +++ b/homeassistant/components/matter/cover.py @@ -8,6 +8,7 @@ from chip.clusters import Objects as clusters from homeassistant.components.cover import ( ATTR_POSITION, + ATTR_TILT_POSITION, CoverDeviceClass, CoverEntity, CoverEntityDescription, @@ -56,12 +57,6 @@ 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 is_closed(self) -> bool: @@ -88,6 +83,14 @@ class MatterCover(MatterEntity, CoverEntity): clusters.WindowCovering.Commands.GoToLiftPercentage((100 - position) * 100) ) + async def async_set_cover_tilt_position(self, **kwargs: Any) -> None: + """Set the cover tilt to a specific position.""" + position = kwargs[ATTR_TILT_POSITION] + await self.send_device_command( + # value needs to be inverted and is sent in 100ths + clusters.WindowCovering.Commands.GoToTiltPercentage((100 - position) * 100) + ) + async def send_device_command(self, command: Any) -> None: """Send device command.""" await self.matter_client.send_device_command( @@ -127,7 +130,9 @@ class MatterCover(MatterEntity, CoverEntity): current_cover_position = self.get_matter_attribute_value( clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage ) - self._attr_current_cover_position = 100 - current_cover_position + self._attr_current_cover_position = ( + 100 - current_cover_position if current_cover_position is not None else None + ) LOGGER.debug( "Current position for %s - raw: %s - corrected: %s", @@ -136,12 +141,41 @@ class MatterCover(MatterEntity, CoverEntity): self.current_cover_position, ) + # current tilt position is inverted in matter (100 is closed, 0 is open) + current_cover_tilt_position = self.get_matter_attribute_value( + clusters.WindowCovering.Attributes.CurrentPositionTiltPercentage + ) + self._attr_current_cover_tilt_position = ( + 100 - current_cover_tilt_position + if current_cover_tilt_position is not None + else None + ) + + LOGGER.debug( + "Current tilt position for %s - raw: %s - corrected: %s", + self.entity_id, + current_cover_tilt_position, + self.current_cover_tilt_position, + ) + # map matter type to HA deviceclass device_type: clusters.WindowCovering.Enums.Type = ( self.get_matter_attribute_value(clusters.WindowCovering.Attributes.Type) ) self._attr_device_class = TYPE_MAP.get(device_type, CoverDeviceClass.AWNING) + supported_features = ( + CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE | CoverEntityFeature.STOP + ) + commands = self.get_matter_attribute_value( + clusters.WindowCovering.Attributes.AcceptedCommandList + ) + if clusters.WindowCovering.Commands.GoToLiftPercentage.command_id in commands: + supported_features |= CoverEntityFeature.SET_POSITION + if clusters.WindowCovering.Commands.GoToTiltPercentage.command_id in commands: + supported_features |= CoverEntityFeature.SET_TILT_POSITION + self._attr_supported_features = supported_features + # Discovery schema(s) to map Matter Attributes to HA entities DISCOVERY_SCHEMAS = [ @@ -150,8 +184,51 @@ DISCOVERY_SCHEMAS = [ entity_description=CoverEntityDescription(key="MatterCover"), entity_class=MatterCover, required_attributes=( - clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage, clusters.WindowCovering.Attributes.OperationalStatus, + clusters.WindowCovering.Attributes.Type, ), - ) + absent_attributes=( + clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage, + clusters.WindowCovering.Attributes.CurrentPositionTiltPercentage, + ), + ), + MatterDiscoverySchema( + platform=Platform.COVER, + entity_description=CoverEntityDescription(key="MatterCoverPositionAwareLift"), + entity_class=MatterCover, + required_attributes=( + clusters.WindowCovering.Attributes.OperationalStatus, + clusters.WindowCovering.Attributes.Type, + clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage, + ), + absent_attributes=( + clusters.WindowCovering.Attributes.CurrentPositionTiltPercentage, + ), + ), + MatterDiscoverySchema( + platform=Platform.COVER, + entity_description=CoverEntityDescription(key="MatterCoverPositionAwareTilt"), + entity_class=MatterCover, + required_attributes=( + clusters.WindowCovering.Attributes.OperationalStatus, + clusters.WindowCovering.Attributes.Type, + clusters.WindowCovering.Attributes.CurrentPositionTiltPercentage, + ), + absent_attributes=( + clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage, + ), + ), + MatterDiscoverySchema( + platform=Platform.COVER, + entity_description=CoverEntityDescription( + key="MatterCoverPositionAwareLiftAndTilt" + ), + entity_class=MatterCover, + required_attributes=( + clusters.WindowCovering.Attributes.OperationalStatus, + clusters.WindowCovering.Attributes.Type, + clusters.WindowCovering.Attributes.CurrentPositionLiftPercentage, + clusters.WindowCovering.Attributes.CurrentPositionTiltPercentage, + ), + ), ] diff --git a/tests/components/matter/fixtures/nodes/window-covering_full.json b/tests/components/matter/fixtures/nodes/window-covering_full.json new file mode 100644 index 00000000000..3ffd68bd319 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/window-covering_full.json @@ -0,0 +1,268 @@ +{ + "node_id": 50, + "date_commissioned": "2023-04-27T18:47:08.437119", + "last_interview": "2023-04-27T18:47:08.437131", + "interview_version": 3, + "available": true, + "attributes": { + "0/29/65533": 1, + "0/29/0": [ + { + "deviceType": 22, + "revision": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 49, 51, 60, 62, 63, 54], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "0/31/65533": 1, + "0/31/0": [ + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 1 + }, + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 2 + }, + { + "privilege": 5, + "authMode": 2, + "subjects": [112233], + "targets": null, + "fabricIndex": 3 + } + ], + "0/31/2": 4, + "0/31/4": 4, + "0/31/3": 3, + "0/31/65532": 0, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [65528, 65529, 65531, 65533, 0, 2, 4, 3, 65532], + "0/40/65532": 0, + "0/40/0": 1, + "0/40/1": "Nabu Casa", + "0/40/2": 65521, + "0/40/3": "Mock Covering", + "0/40/4": 32768, + "0/40/5": "Mock Full Window Covering", + "0/40/6": "XX", + "0/40/7": 0, + "0/40/8": "v1.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": "12345678", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "mock-full-window-covering", + "0/40/19": { + "caseSessionsPerFabric": 3, + "subscriptionsPerFabric": 3 + }, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 65528, 65529, 65531, 65532, 0, 6, 1, 2, 3, 4, 7, 8, 9, 10, 19, 65533, 5 + ], + "0/48/65532": 0, + "0/48/2": 0, + "0/48/3": 0, + "0/48/1": { + "failSafeExpiryLengthSeconds": 60, + "maxCumulativeFailsafeSeconds": 900 + }, + "0/48/4": true, + "0/48/65533": 1, + "0/48/0": 0, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [65528, 65529, 65531, 65532, 2, 3, 1, 4, 65533, 0], + "0/49/0": 1, + "0/49/1": [ + { + "networkID": "MTI2MDk5", + "connected": true + } + ], + "0/49/2": 10, + "0/49/3": 30, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "MTI2MDk5", + "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/51/0": [ + { + "name": "WIFI_STA_DEF", + "isOperational": true, + "offPremiseServicesReachableIPv4": null, + "offPremiseServicesReachableIPv6": null, + "hardwareAddress": "JG8olrDo", + "IPv4Addresses": ["wKgBFw=="], + "IPv6Addresses": ["/oAAAAAAAAAmbyj//paw6A=="], + "type": 1 + } + ], + "0/51/1": 1, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 1, + "0/51/65528": [], + "0/51/65529": [0], + "0/51/65531": [0, 1, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/65532": 0, + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 65533], + "0/62/65532": 0, + "0/62/0": [ + { + "noc": "", + "icac": null, + "fabricIndex": 1 + }, + { + "noc": "", + "icac": null, + "fabricIndex": 2 + }, + { + "noc": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRMhgkBwEkCAEwCUEE+5TLtucQZ8l7Y5r8nKhYB0mia0RMn+RJa5AtRIPb2R9ixMcQXfQBANdHPCwsfTGWyjBYzPXG1yDUTUz+Z1J9aTcKNQEoARgkAgE2AwQCBAEYMAQUh/lTccn18xJ1JqA9VRHdr2+IhscwBRTPeGj+EyBBTsdlJC4zNSP/tIcpFhgwC0AoRjZKvJRkg+Cz77N6+IIQBt0i1Oco92N/XzoDWtgUVIOW5qvPcUUI/tiYAEDdefy2/6XpjU1Y7ecN3vgoTdNUGA==", + "icac": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEL6dfjjyZxKHsFjZvYUOhWsOCI/2ucOxcCZGFaJwG0vXhL5/aDhR/AF907lF93LR1Huvp3NJsB0oxqsNnbEz8jjcKNQEpARgkAmAwBBTPeGj+EyBBTsdlJC4zNSP/tIcpFjAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQIHEwwdIaYHnFzpYngW9g+7Cn3gl0qKnetK5gWUVVTdVtpx6dYBblvPnOU+5K3Ow85llzcRxU1yXgPAM77s7t8gY", + "fabricIndex": 3 + } + ], + "0/62/2": 5, + "0/62/3": 3, + "0/62/1": [ + { + "rootPublicKey": "BFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U=", + "vendorId": 24582, + "fabricId": 7331465149450221740, + "nodeId": 3429688654, + "label": "", + "fabricIndex": 1 + }, + { + "rootPublicKey": "BJyJ1DODbJ+HellxuG3J/EstNpyw/i5h1x5qjNLQjwnPZoEaLLMZ8KKN7/rxQy3JUIkfuQydJz7JXeF80mES8q8=", + "vendorId": 4362, + "fabricId": 8516517930550670493, + "nodeId": 1443093566726981311, + "label": "", + "fabricIndex": 2 + }, + { + "rootPublicKey": "BFOpRqEk+HJ6n/NtUtaWTQVVwstz9QRDK2xvRP6qKZKX3Rk05Zie5Ux9PdjgE1K5zE9NIP2jHHcVJjRBVZxNFz0=", + "vendorId": 4939, + "fabricId": 2, + "nodeId": 50, + "label": "", + "fabricIndex": 3 + } + ], + "0/62/4": [ + "FTABAQEkAgE3AyyEAlVTLAcGR29vZ2xlLAELTWF0dGVyIFJvb3QnFAEAAAD+////GCYEf9JDKSYFf5Rb5TcGLIQCVVMsBwZHb29nbGUsAQtNYXR0ZXIgUm9vdCcUAQAAAP7///8YJAcBJAgBMAlBBFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U3CjUBKQEkAgEYJAJgMAQUcsIB91cZE7NIygDKe0X0d0ZoyX4wBRRywgH3VxkTs0jKAMp7RfR3RmjJfhgwC0BlFksWat/xjBVhCozpG9cD6cH2d7cRzhM1BRUt8NoVERZ1rFWRzueGhRzdnv2tKWZ0vryyo6Mgm83nswnbVSxvGA==", + "FTABEQDNbArxrUcyIYFkHqJLbo/WJAIBNwMnFHQ/DS4Kfg0eGCYEt4c/KyYFx+imNDcGJxR0Pw0uCn4NHhgkBwEkCAEwCUEEnInUM4Nsn4d6WXG4bcn8Sy02nLD+LmHXHmqM0tCPCc9mgRossxnwoo3v+vFDLclQiR+5DJ0nPsld4XzSYRLyrzcKNQEpARgwBBRmfAEklIwuWsdBmLyvfEmBToSQbyQCYTAFFGZ8ASSUjC5ax0GYvK98SYFOhJBvGDALQG4YnkZOq0UG+s4+HLs3eTnu91x/TgO5aeFb7sRom4xWTHn+rS7KISVXeWs6W3FRJsJdyZSYNgdwv5/cRFPC5q8Y", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEU6lGoST4cnqf821S1pZNBVXCy3P1BEMrbG9E/qopkpfdGTTlmJ7lTH092OATUrnMT00g/aMcdxUmNEFVnE0XPTcKNQEpARgkAmAwBBQvAa/SApcgS93u6aNxvkFzRrAaGDAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQJjFHQ5JVpar4vSHdn0lTZreXN7Ye9N3BfZWW+BJXbTs9yOH/oON1B1OLipahkwhWRj7A26vEfRHQ9g3Bh2Zt/kY" + ], + "0/62/5": 3, + "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": [65528, 65529, 65531, 65532, 0, 2, 3, 1, 4, 5, 65533], + "0/63/65532": 0, + "0/63/65533": 1, + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3], + "0/54/65532": 0, + "0/54/0": "YI0m7T6v", + "0/54/1": 4, + "0/54/2": 3, + "0/54/3": 6, + "0/54/4": -88, + "0/54/65533": 1, + "0/54/65528": [], + "0/54/65529": [], + "0/54/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 3, 4, 65533], + "1/29/65533": 1, + "1/29/0": [ + { + "deviceType": 514, + "revision": 2 + } + ], + "1/29/1": [29, 3, 258], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/0": 0, + "1/3/1": 0, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [65528, 65529, 65531, 65532, 65533, 0, 1], + "1/258/65532": 31, + "1/258/65533": 5, + "1/258/0": 6, + "1/258/1": 90, + "1/258/2": 90, + "1/258/3": 0, + "1/258/4": 0, + "1/258/5": 0, + "1/258/7": 1, + "1/258/8": 0, + "1/258/9": 0, + "1/258/10": 0, + "1/258/11": 0, + "1/258/12": 0, + "1/258/13": 255, + "1/258/14": 0, + "1/258/15": 0, + "1/258/16": 0, + "1/258/17": 0, + "1/258/18": 0, + "1/258/19": 0, + "1/258/23": 0, + "1/258/26": 0, + "1/258/6": 0, + "1/258/65528": [], + "1/258/65529": [0, 1, 2, 4, 5, 7, 8], + "1/258/65531": [ + 65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 23, 26, 6 + ] + } +} diff --git a/tests/components/matter/fixtures/nodes/window-covering_lift.json b/tests/components/matter/fixtures/nodes/window-covering_lift.json new file mode 100644 index 00000000000..cd200eb15f0 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/window-covering_lift.json @@ -0,0 +1,249 @@ +{ + "node_id": 50, + "date_commissioned": "2023-04-27T18:47:08.437119", + "last_interview": "2023-04-27T18:47:08.437131", + "interview_version": 3, + "available": true, + "attributes": { + "0/29/65533": 1, + "0/29/0": [ + { + "deviceType": 22, + "revision": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 49, 51, 60, 62, 63, 54], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "0/31/65533": 1, + "0/31/0": [ + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 1 + }, + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 2 + }, + { + "privilege": 5, + "authMode": 2, + "subjects": [112233], + "targets": null, + "fabricIndex": 3 + } + ], + "0/31/2": 4, + "0/31/4": 4, + "0/31/3": 3, + "0/31/65532": 0, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [65528, 65529, 65531, 65533, 0, 2, 4, 3, 65532], + "0/40/65532": 0, + "0/40/0": 1, + "0/40/1": "Nabu Casa", + "0/40/2": 65521, + "0/40/3": "Mock Covering", + "0/40/4": 32768, + "0/40/5": "Mock Lift Window Covering", + "0/40/6": "XX", + "0/40/7": 0, + "0/40/8": "v1.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": "12345678", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "mock-lift-window-covering", + "0/40/19": { + "caseSessionsPerFabric": 3, + "subscriptionsPerFabric": 3 + }, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 65528, 65529, 65531, 65532, 0, 6, 1, 2, 3, 4, 7, 8, 9, 10, 19, 65533, 5 + ], + "0/48/65532": 0, + "0/48/2": 0, + "0/48/3": 0, + "0/48/1": { + "failSafeExpiryLengthSeconds": 60, + "maxCumulativeFailsafeSeconds": 900 + }, + "0/48/4": true, + "0/48/65533": 1, + "0/48/0": 0, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [65528, 65529, 65531, 65532, 2, 3, 1, 4, 65533, 0], + "0/49/0": 1, + "0/49/1": [ + { + "networkID": "MTI2MDk5", + "connected": true + } + ], + "0/49/2": 10, + "0/49/3": 30, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "MTI2MDk5", + "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/51/0": [ + { + "name": "WIFI_STA_DEF", + "isOperational": true, + "offPremiseServicesReachableIPv4": null, + "offPremiseServicesReachableIPv6": null, + "hardwareAddress": "JG8olrDo", + "IPv4Addresses": ["wKgBFw=="], + "IPv6Addresses": ["/oAAAAAAAAAmbyj//paw6A=="], + "type": 1 + } + ], + "0/51/1": 1, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 1, + "0/51/65528": [], + "0/51/65529": [0], + "0/51/65531": [0, 1, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/65532": 0, + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 65533], + "0/62/65532": 0, + "0/62/0": [ + { + "noc": "", + "icac": null, + "fabricIndex": 1 + }, + { + "noc": "", + "icac": null, + "fabricIndex": 2 + }, + { + "noc": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRMhgkBwEkCAEwCUEE+5TLtucQZ8l7Y5r8nKhYB0mia0RMn+RJa5AtRIPb2R9ixMcQXfQBANdHPCwsfTGWyjBYzPXG1yDUTUz+Z1J9aTcKNQEoARgkAgE2AwQCBAEYMAQUh/lTccn18xJ1JqA9VRHdr2+IhscwBRTPeGj+EyBBTsdlJC4zNSP/tIcpFhgwC0AoRjZKvJRkg+Cz77N6+IIQBt0i1Oco92N/XzoDWtgUVIOW5qvPcUUI/tiYAEDdefy2/6XpjU1Y7ecN3vgoTdNUGA==", + "icac": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEL6dfjjyZxKHsFjZvYUOhWsOCI/2ucOxcCZGFaJwG0vXhL5/aDhR/AF907lF93LR1Huvp3NJsB0oxqsNnbEz8jjcKNQEpARgkAmAwBBTPeGj+EyBBTsdlJC4zNSP/tIcpFjAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQIHEwwdIaYHnFzpYngW9g+7Cn3gl0qKnetK5gWUVVTdVtpx6dYBblvPnOU+5K3Ow85llzcRxU1yXgPAM77s7t8gY", + "fabricIndex": 3 + } + ], + "0/62/2": 5, + "0/62/3": 3, + "0/62/1": [ + { + "rootPublicKey": "BFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U=", + "vendorId": 24582, + "fabricId": 7331465149450221740, + "nodeId": 3429688654, + "label": "", + "fabricIndex": 1 + }, + { + "rootPublicKey": "BJyJ1DODbJ+HellxuG3J/EstNpyw/i5h1x5qjNLQjwnPZoEaLLMZ8KKN7/rxQy3JUIkfuQydJz7JXeF80mES8q8=", + "vendorId": 4362, + "fabricId": 8516517930550670493, + "nodeId": 1443093566726981311, + "label": "", + "fabricIndex": 2 + }, + { + "rootPublicKey": "BFOpRqEk+HJ6n/NtUtaWTQVVwstz9QRDK2xvRP6qKZKX3Rk05Zie5Ux9PdjgE1K5zE9NIP2jHHcVJjRBVZxNFz0=", + "vendorId": 4939, + "fabricId": 2, + "nodeId": 50, + "label": "", + "fabricIndex": 3 + } + ], + "0/62/4": [ + "FTABAQEkAgE3AyyEAlVTLAcGR29vZ2xlLAELTWF0dGVyIFJvb3QnFAEAAAD+////GCYEf9JDKSYFf5Rb5TcGLIQCVVMsBwZHb29nbGUsAQtNYXR0ZXIgUm9vdCcUAQAAAP7///8YJAcBJAgBMAlBBFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U3CjUBKQEkAgEYJAJgMAQUcsIB91cZE7NIygDKe0X0d0ZoyX4wBRRywgH3VxkTs0jKAMp7RfR3RmjJfhgwC0BlFksWat/xjBVhCozpG9cD6cH2d7cRzhM1BRUt8NoVERZ1rFWRzueGhRzdnv2tKWZ0vryyo6Mgm83nswnbVSxvGA==", + "FTABEQDNbArxrUcyIYFkHqJLbo/WJAIBNwMnFHQ/DS4Kfg0eGCYEt4c/KyYFx+imNDcGJxR0Pw0uCn4NHhgkBwEkCAEwCUEEnInUM4Nsn4d6WXG4bcn8Sy02nLD+LmHXHmqM0tCPCc9mgRossxnwoo3v+vFDLclQiR+5DJ0nPsld4XzSYRLyrzcKNQEpARgwBBRmfAEklIwuWsdBmLyvfEmBToSQbyQCYTAFFGZ8ASSUjC5ax0GYvK98SYFOhJBvGDALQG4YnkZOq0UG+s4+HLs3eTnu91x/TgO5aeFb7sRom4xWTHn+rS7KISVXeWs6W3FRJsJdyZSYNgdwv5/cRFPC5q8Y", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEU6lGoST4cnqf821S1pZNBVXCy3P1BEMrbG9E/qopkpfdGTTlmJ7lTH092OATUrnMT00g/aMcdxUmNEFVnE0XPTcKNQEpARgkAmAwBBQvAa/SApcgS93u6aNxvkFzRrAaGDAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQJjFHQ5JVpar4vSHdn0lTZreXN7Ye9N3BfZWW+BJXbTs9yOH/oON1B1OLipahkwhWRj7A26vEfRHQ9g3Bh2Zt/kY" + ], + "0/62/5": 3, + "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": [65528, 65529, 65531, 65532, 0, 2, 3, 1, 4, 5, 65533], + "0/63/65532": 0, + "0/63/65533": 1, + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3], + "0/54/65532": 0, + "0/54/0": "YI0m7T6v", + "0/54/1": 4, + "0/54/2": 3, + "0/54/3": 6, + "0/54/4": -88, + "0/54/65533": 1, + "0/54/65528": [], + "0/54/65529": [], + "0/54/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 3, 4, 65533], + "1/29/65533": 1, + "1/29/0": [ + { + "deviceType": 514, + "revision": 2 + } + ], + "1/29/1": [29, 3, 258], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/0": 0, + "1/3/1": 0, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [65528, 65529, 65531, 65532, 65533, 0, 1], + "1/258/65532": 1, + "1/258/65533": 5, + "1/258/0": 5, + "1/258/5": 0, + "1/258/7": 1, + "1/258/10": 0, + "1/258/13": 255, + "1/258/23": 0, + "1/258/65528": [], + "1/258/65529": [0, 1, 2, 5], + "1/258/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 5, 7, 10, 13, 23] + } +} diff --git a/tests/components/matter/fixtures/nodes/window-covering.json b/tests/components/matter/fixtures/nodes/window-covering_pa-lift.json similarity index 100% rename from tests/components/matter/fixtures/nodes/window-covering.json rename to tests/components/matter/fixtures/nodes/window-covering_pa-lift.json diff --git a/tests/components/matter/fixtures/nodes/window-covering_pa-tilt.json b/tests/components/matter/fixtures/nodes/window-covering_pa-tilt.json new file mode 100644 index 00000000000..d432d7cf50a --- /dev/null +++ b/tests/components/matter/fixtures/nodes/window-covering_pa-tilt.json @@ -0,0 +1,254 @@ +{ + "node_id": 50, + "date_commissioned": "2023-04-27T18:47:08.437119", + "last_interview": "2023-04-27T18:47:08.437131", + "interview_version": 3, + "available": true, + "attributes": { + "0/29/65533": 1, + "0/29/0": [ + { + "deviceType": 22, + "revision": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 49, 51, 60, 62, 63, 54], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "0/31/65533": 1, + "0/31/0": [ + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 1 + }, + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 2 + }, + { + "privilege": 5, + "authMode": 2, + "subjects": [112233], + "targets": null, + "fabricIndex": 3 + } + ], + "0/31/2": 4, + "0/31/4": 4, + "0/31/3": 3, + "0/31/65532": 0, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [65528, 65529, 65531, 65533, 0, 2, 4, 3, 65532], + "0/40/65532": 0, + "0/40/0": 1, + "0/40/1": "Nabu Casa", + "0/40/2": 65521, + "0/40/3": "Mock Covering", + "0/40/4": 32768, + "0/40/5": "Mock PA Tilt Window Covering", + "0/40/6": "XX", + "0/40/7": 0, + "0/40/8": "v1.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": "12345678", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "mock_pa_tilt_window_covering", + "0/40/19": { + "caseSessionsPerFabric": 3, + "subscriptionsPerFabric": 3 + }, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 65528, 65529, 65531, 65532, 0, 6, 1, 2, 3, 4, 7, 8, 9, 10, 19, 65533, 5 + ], + "0/48/65532": 0, + "0/48/2": 0, + "0/48/3": 0, + "0/48/1": { + "failSafeExpiryLengthSeconds": 60, + "maxCumulativeFailsafeSeconds": 900 + }, + "0/48/4": true, + "0/48/65533": 1, + "0/48/0": 0, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [65528, 65529, 65531, 65532, 2, 3, 1, 4, 65533, 0], + "0/49/0": 1, + "0/49/1": [ + { + "networkID": "MTI2MDk5", + "connected": true + } + ], + "0/49/2": 10, + "0/49/3": 30, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "MTI2MDk5", + "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/51/0": [ + { + "name": "WIFI_STA_DEF", + "isOperational": true, + "offPremiseServicesReachableIPv4": null, + "offPremiseServicesReachableIPv6": null, + "hardwareAddress": "JG8olrDo", + "IPv4Addresses": ["wKgBFw=="], + "IPv6Addresses": ["/oAAAAAAAAAmbyj//paw6A=="], + "type": 1 + } + ], + "0/51/1": 1, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 1, + "0/51/65528": [], + "0/51/65529": [0], + "0/51/65531": [0, 1, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/65532": 0, + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 65533], + "0/62/65532": 0, + "0/62/0": [ + { + "noc": "", + "icac": null, + "fabricIndex": 1 + }, + { + "noc": "", + "icac": null, + "fabricIndex": 2 + }, + { + "noc": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRMhgkBwEkCAEwCUEE+5TLtucQZ8l7Y5r8nKhYB0mia0RMn+RJa5AtRIPb2R9ixMcQXfQBANdHPCwsfTGWyjBYzPXG1yDUTUz+Z1J9aTcKNQEoARgkAgE2AwQCBAEYMAQUh/lTccn18xJ1JqA9VRHdr2+IhscwBRTPeGj+EyBBTsdlJC4zNSP/tIcpFhgwC0AoRjZKvJRkg+Cz77N6+IIQBt0i1Oco92N/XzoDWtgUVIOW5qvPcUUI/tiYAEDdefy2/6XpjU1Y7ecN3vgoTdNUGA==", + "icac": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEL6dfjjyZxKHsFjZvYUOhWsOCI/2ucOxcCZGFaJwG0vXhL5/aDhR/AF907lF93LR1Huvp3NJsB0oxqsNnbEz8jjcKNQEpARgkAmAwBBTPeGj+EyBBTsdlJC4zNSP/tIcpFjAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQIHEwwdIaYHnFzpYngW9g+7Cn3gl0qKnetK5gWUVVTdVtpx6dYBblvPnOU+5K3Ow85llzcRxU1yXgPAM77s7t8gY", + "fabricIndex": 3 + } + ], + "0/62/2": 5, + "0/62/3": 3, + "0/62/1": [ + { + "rootPublicKey": "BFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U=", + "vendorId": 24582, + "fabricId": 7331465149450221740, + "nodeId": 3429688654, + "label": "", + "fabricIndex": 1 + }, + { + "rootPublicKey": "BJyJ1DODbJ+HellxuG3J/EstNpyw/i5h1x5qjNLQjwnPZoEaLLMZ8KKN7/rxQy3JUIkfuQydJz7JXeF80mES8q8=", + "vendorId": 4362, + "fabricId": 8516517930550670493, + "nodeId": 1443093566726981311, + "label": "", + "fabricIndex": 2 + }, + { + "rootPublicKey": "BFOpRqEk+HJ6n/NtUtaWTQVVwstz9QRDK2xvRP6qKZKX3Rk05Zie5Ux9PdjgE1K5zE9NIP2jHHcVJjRBVZxNFz0=", + "vendorId": 4939, + "fabricId": 2, + "nodeId": 50, + "label": "", + "fabricIndex": 3 + } + ], + "0/62/4": [ + "FTABAQEkAgE3AyyEAlVTLAcGR29vZ2xlLAELTWF0dGVyIFJvb3QnFAEAAAD+////GCYEf9JDKSYFf5Rb5TcGLIQCVVMsBwZHb29nbGUsAQtNYXR0ZXIgUm9vdCcUAQAAAP7///8YJAcBJAgBMAlBBFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U3CjUBKQEkAgEYJAJgMAQUcsIB91cZE7NIygDKe0X0d0ZoyX4wBRRywgH3VxkTs0jKAMp7RfR3RmjJfhgwC0BlFksWat/xjBVhCozpG9cD6cH2d7cRzhM1BRUt8NoVERZ1rFWRzueGhRzdnv2tKWZ0vryyo6Mgm83nswnbVSxvGA==", + "FTABEQDNbArxrUcyIYFkHqJLbo/WJAIBNwMnFHQ/DS4Kfg0eGCYEt4c/KyYFx+imNDcGJxR0Pw0uCn4NHhgkBwEkCAEwCUEEnInUM4Nsn4d6WXG4bcn8Sy02nLD+LmHXHmqM0tCPCc9mgRossxnwoo3v+vFDLclQiR+5DJ0nPsld4XzSYRLyrzcKNQEpARgwBBRmfAEklIwuWsdBmLyvfEmBToSQbyQCYTAFFGZ8ASSUjC5ax0GYvK98SYFOhJBvGDALQG4YnkZOq0UG+s4+HLs3eTnu91x/TgO5aeFb7sRom4xWTHn+rS7KISVXeWs6W3FRJsJdyZSYNgdwv5/cRFPC5q8Y", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEU6lGoST4cnqf821S1pZNBVXCy3P1BEMrbG9E/qopkpfdGTTlmJ7lTH092OATUrnMT00g/aMcdxUmNEFVnE0XPTcKNQEpARgkAmAwBBQvAa/SApcgS93u6aNxvkFzRrAaGDAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQJjFHQ5JVpar4vSHdn0lTZreXN7Ye9N3BfZWW+BJXbTs9yOH/oON1B1OLipahkwhWRj7A26vEfRHQ9g3Bh2Zt/kY" + ], + "0/62/5": 3, + "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": [65528, 65529, 65531, 65532, 0, 2, 3, 1, 4, 5, 65533], + "0/63/65532": 0, + "0/63/65533": 1, + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3], + "0/54/65532": 0, + "0/54/0": "YI0m7T6v", + "0/54/1": 4, + "0/54/2": 3, + "0/54/3": 6, + "0/54/4": -88, + "0/54/65533": 1, + "0/54/65528": [], + "0/54/65529": [], + "0/54/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 3, 4, 65533], + "1/29/65533": 1, + "1/29/0": [ + { + "deviceType": 514, + "revision": 2 + } + ], + "1/29/1": [29, 3, 258], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/0": 0, + "1/3/1": 0, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [65528, 65529, 65531, 65532, 65533, 0, 1], + "1/258/65532": 18, + "1/258/65533": 5, + "1/258/0": 7, + "1/258/7": 1, + "1/258/9": 0, + "1/258/10": 0, + "1/258/12": 0, + "1/258/13": 255, + "1/258/15": 0, + "1/258/23": 0, + "1/258/6": 0, + "1/258/65528": [], + "1/258/65529": [0, 1, 2, 8], + "1/258/65531": [ + 65528, 65529, 65531, 65532, 65533, 0, 7, 9, 10, 12, 13, 15, 23, 6 + ] + } +} diff --git a/tests/components/matter/fixtures/nodes/window-covering_tilt.json b/tests/components/matter/fixtures/nodes/window-covering_tilt.json new file mode 100644 index 00000000000..1fe0d99ac38 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/window-covering_tilt.json @@ -0,0 +1,249 @@ +{ + "node_id": 50, + "date_commissioned": "2023-04-27T18:47:08.437119", + "last_interview": "2023-04-27T18:47:08.437131", + "interview_version": 3, + "available": true, + "attributes": { + "0/29/65533": 1, + "0/29/0": [ + { + "deviceType": 22, + "revision": 1 + } + ], + "0/29/1": [29, 31, 40, 48, 49, 51, 60, 62, 63, 54], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "0/31/65533": 1, + "0/31/0": [ + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 1 + }, + { + "privilege": 0, + "authMode": 0, + "subjects": null, + "targets": null, + "fabricIndex": 2 + }, + { + "privilege": 5, + "authMode": 2, + "subjects": [112233], + "targets": null, + "fabricIndex": 3 + } + ], + "0/31/2": 4, + "0/31/4": 4, + "0/31/3": 3, + "0/31/65532": 0, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [65528, 65529, 65531, 65533, 0, 2, 4, 3, 65532], + "0/40/65532": 0, + "0/40/0": 1, + "0/40/1": "Nabu Casa", + "0/40/2": 65521, + "0/40/3": "Mock Covering", + "0/40/4": 32768, + "0/40/5": "Mock Tilt Window Covering", + "0/40/6": "XX", + "0/40/7": 0, + "0/40/8": "v1.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": "12345678", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "mock-tilt-window-covering", + "0/40/19": { + "caseSessionsPerFabric": 3, + "subscriptionsPerFabric": 3 + }, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 65528, 65529, 65531, 65532, 0, 6, 1, 2, 3, 4, 7, 8, 9, 10, 19, 65533, 5 + ], + "0/48/65532": 0, + "0/48/2": 0, + "0/48/3": 0, + "0/48/1": { + "failSafeExpiryLengthSeconds": 60, + "maxCumulativeFailsafeSeconds": 900 + }, + "0/48/4": true, + "0/48/65533": 1, + "0/48/0": 0, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [65528, 65529, 65531, 65532, 2, 3, 1, 4, 65533, 0], + "0/49/0": 1, + "0/49/1": [ + { + "networkID": "MTI2MDk5", + "connected": true + } + ], + "0/49/2": 10, + "0/49/3": 30, + "0/49/4": true, + "0/49/5": 0, + "0/49/6": "MTI2MDk5", + "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/51/0": [ + { + "name": "WIFI_STA_DEF", + "isOperational": true, + "offPremiseServicesReachableIPv4": null, + "offPremiseServicesReachableIPv6": null, + "hardwareAddress": "JG8olrDo", + "IPv4Addresses": ["wKgBFw=="], + "IPv6Addresses": ["/oAAAAAAAAAmbyj//paw6A=="], + "type": 1 + } + ], + "0/51/1": 1, + "0/51/8": false, + "0/51/65532": 0, + "0/51/65533": 1, + "0/51/65528": [], + "0/51/65529": [0], + "0/51/65531": [0, 1, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/65532": 0, + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 1, 2], + "0/60/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 65533], + "0/62/65532": 0, + "0/62/0": [ + { + "noc": "", + "icac": null, + "fabricIndex": 1 + }, + { + "noc": "", + "icac": null, + "fabricIndex": 2 + }, + { + "noc": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVAiQRMhgkBwEkCAEwCUEE+5TLtucQZ8l7Y5r8nKhYB0mia0RMn+RJa5AtRIPb2R9ixMcQXfQBANdHPCwsfTGWyjBYzPXG1yDUTUz+Z1J9aTcKNQEoARgkAgE2AwQCBAEYMAQUh/lTccn18xJ1JqA9VRHdr2+IhscwBRTPeGj+EyBBTsdlJC4zNSP/tIcpFhgwC0AoRjZKvJRkg+Cz77N6+IIQBt0i1Oco92N/XzoDWtgUVIOW5qvPcUUI/tiYAEDdefy2/6XpjU1Y7ecN3vgoTdNUGA==", + "icac": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEL6dfjjyZxKHsFjZvYUOhWsOCI/2ucOxcCZGFaJwG0vXhL5/aDhR/AF907lF93LR1Huvp3NJsB0oxqsNnbEz8jjcKNQEpARgkAmAwBBTPeGj+EyBBTsdlJC4zNSP/tIcpFjAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQIHEwwdIaYHnFzpYngW9g+7Cn3gl0qKnetK5gWUVVTdVtpx6dYBblvPnOU+5K3Ow85llzcRxU1yXgPAM77s7t8gY", + "fabricIndex": 3 + } + ], + "0/62/2": 5, + "0/62/3": 3, + "0/62/1": [ + { + "rootPublicKey": "BFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U=", + "vendorId": 24582, + "fabricId": 7331465149450221740, + "nodeId": 3429688654, + "label": "", + "fabricIndex": 1 + }, + { + "rootPublicKey": "BJyJ1DODbJ+HellxuG3J/EstNpyw/i5h1x5qjNLQjwnPZoEaLLMZ8KKN7/rxQy3JUIkfuQydJz7JXeF80mES8q8=", + "vendorId": 4362, + "fabricId": 8516517930550670493, + "nodeId": 1443093566726981311, + "label": "", + "fabricIndex": 2 + }, + { + "rootPublicKey": "BFOpRqEk+HJ6n/NtUtaWTQVVwstz9QRDK2xvRP6qKZKX3Rk05Zie5Ux9PdjgE1K5zE9NIP2jHHcVJjRBVZxNFz0=", + "vendorId": 4939, + "fabricId": 2, + "nodeId": 50, + "label": "", + "fabricIndex": 3 + } + ], + "0/62/4": [ + "FTABAQEkAgE3AyyEAlVTLAcGR29vZ2xlLAELTWF0dGVyIFJvb3QnFAEAAAD+////GCYEf9JDKSYFf5Rb5TcGLIQCVVMsBwZHb29nbGUsAQtNYXR0ZXIgUm9vdCcUAQAAAP7///8YJAcBJAgBMAlBBFs332VJwg3I1yKmuKy2YKinZM57r2xsIk9+6ENJaErX2An/ZQAz0VJ9zx+6rGqcOti0HtrJCfe1x2D9VCyJI3U3CjUBKQEkAgEYJAJgMAQUcsIB91cZE7NIygDKe0X0d0ZoyX4wBRRywgH3VxkTs0jKAMp7RfR3RmjJfhgwC0BlFksWat/xjBVhCozpG9cD6cH2d7cRzhM1BRUt8NoVERZ1rFWRzueGhRzdnv2tKWZ0vryyo6Mgm83nswnbVSxvGA==", + "FTABEQDNbArxrUcyIYFkHqJLbo/WJAIBNwMnFHQ/DS4Kfg0eGCYEt4c/KyYFx+imNDcGJxR0Pw0uCn4NHhgkBwEkCAEwCUEEnInUM4Nsn4d6WXG4bcn8Sy02nLD+LmHXHmqM0tCPCc9mgRossxnwoo3v+vFDLclQiR+5DJ0nPsld4XzSYRLyrzcKNQEpARgwBBRmfAEklIwuWsdBmLyvfEmBToSQbyQCYTAFFGZ8ASSUjC5ax0GYvK98SYFOhJBvGDALQG4YnkZOq0UG+s4+HLs3eTnu91x/TgO5aeFb7sRom4xWTHn+rS7KISVXeWs6W3FRJsJdyZSYNgdwv5/cRFPC5q8Y", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEU6lGoST4cnqf821S1pZNBVXCy3P1BEMrbG9E/qopkpfdGTTlmJ7lTH092OATUrnMT00g/aMcdxUmNEFVnE0XPTcKNQEpARgkAmAwBBQvAa/SApcgS93u6aNxvkFzRrAaGDAFFC8Br9IClyBL3e7po3G+QXNGsBoYGDALQJjFHQ5JVpar4vSHdn0lTZreXN7Ye9N3BfZWW+BJXbTs9yOH/oON1B1OLipahkwhWRj7A26vEfRHQ9g3Bh2Zt/kY" + ], + "0/62/5": 3, + "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": [65528, 65529, 65531, 65532, 0, 2, 3, 1, 4, 5, 65533], + "0/63/65532": 0, + "0/63/65533": 1, + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [65528, 65529, 65531, 65532, 65533, 0, 1, 2, 3], + "0/54/65532": 0, + "0/54/0": "YI0m7T6v", + "0/54/1": 4, + "0/54/2": 3, + "0/54/3": 6, + "0/54/4": -88, + "0/54/65533": 1, + "0/54/65528": [], + "0/54/65529": [], + "0/54/65531": [65528, 65529, 65531, 65532, 0, 1, 2, 3, 4, 65533], + "1/29/65533": 1, + "1/29/0": [ + { + "deviceType": 514, + "revision": 2 + } + ], + "1/29/1": [29, 3, 258], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [65528, 65529, 65531, 65533, 0, 1, 2, 3, 65532], + "1/3/65532": 0, + "1/3/65533": 4, + "1/3/0": 0, + "1/3/1": 0, + "1/3/65528": [], + "1/3/65529": [0], + "1/3/65531": [65528, 65529, 65531, 65532, 65533, 0, 1], + "1/258/65532": 2, + "1/258/65533": 5, + "1/258/0": 7, + "1/258/6": 0, + "1/258/7": 1, + "1/258/10": 0, + "1/258/13": 255, + "1/258/23": 0, + "1/258/65528": [], + "1/258/65529": [0, 1, 2, 8], + "1/258/65531": [65528, 65529, 65531, 65532, 65533, 0, 7, 10, 13, 23, 6] + } +} diff --git a/tests/components/matter/test_cover.py b/tests/components/matter/test_cover.py index 15ce8ceea8b..bbbd0751e4a 100644 --- a/tests/components/matter/test_cover.py +++ b/tests/components/matter/test_cover.py @@ -2,7 +2,6 @@ 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 ( @@ -10,6 +9,7 @@ from homeassistant.components.cover import ( STATE_CLOSING, STATE_OPEN, STATE_OPENING, + CoverEntityFeature, ) from homeassistant.core import HomeAssistant @@ -20,29 +20,37 @@ from .common import ( ) -@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]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_lift", "cover.mock_lift_window_covering"), + ("window-covering_pa-lift", "cover.longan_link_wncv_da01"), + ("window-covering_tilt", "cover.mock_tilt_window_covering"), + ("window-covering_pa-tilt", "cover.mock_pa_tilt_window_covering"), + ("window-covering_full", "cover.mock_full_window_covering"), + ], +) async def test_cover( hass: HomeAssistant, matter_client: MagicMock, - window_covering: MatterNode, + fixture: str, + entity_id: str, ) -> None: - """Test window covering.""" + """Test window covering commands that always are implemented.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + await hass.services.async_call( "cover", "close_cover", { - "entity_id": "cover.longan_link_wncv_da01", + "entity_id": entity_id, }, blocking=True, ) @@ -59,7 +67,7 @@ async def test_cover( "cover", "stop_cover", { - "entity_id": "cover.longan_link_wncv_da01", + "entity_id": entity_id, }, blocking=True, ) @@ -76,7 +84,7 @@ async def test_cover( "cover", "open_cover", { - "entity_id": "cover.longan_link_wncv_da01", + "entity_id": entity_id, }, blocking=True, ) @@ -89,11 +97,36 @@ async def test_cover( ) matter_client.send_device_command.reset_mock() + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_lift", "cover.mock_lift_window_covering"), + ("window-covering_pa-lift", "cover.longan_link_wncv_da01"), + ("window-covering_full", "cover.mock_full_window_covering"), + ], +) +async def test_cover_lift( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with lift and position aware lift features.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + await hass.services.async_call( "cover", "set_cover_position", { - "entity_id": "cover.longan_link_wncv_da01", + "entity_id": entity_id, "position": 50, }, blocking=True, @@ -107,35 +140,300 @@ async def test_cover( ) 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) + set_node_attribute(window_covering, 1, 258, 10, 0b001010) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("cover.longan_link_wncv_da01") + state = hass.states.get(entity_id) 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) + set_node_attribute(window_covering, 1, 258, 10, 0b000101) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("cover.longan_link_wncv_da01") - assert state - assert state.state == STATE_OPEN - - 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") + state = hass.states.get(entity_id) 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) + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_lift", "cover.mock_lift_window_covering"), + ], +) +async def test_cover_lift_only( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with lift feature and without position aware lift feature.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + + set_node_attribute(window_covering, 1, 258, 65529, [0, 1, 2]) await trigger_subscription_callback(hass, matter_client) - state = hass.states.get("cover.longan_link_wncv_da01") + state = hass.states.get(entity_id) + assert state + assert state.attributes["supported_features"] & CoverEntityFeature.SET_POSITION == 0 + + set_node_attribute(window_covering, 1, 258, 65529, [0, 1, 2, 5]) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.attributes["supported_features"] & CoverEntityFeature.SET_POSITION != 0 + + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_pa-lift", "cover.longan_link_wncv_da01"), + ], +) +async def test_cover_position_aware_lift( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with position aware lift features.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + + state = hass.states.get(entity_id) + assert state + mask = ( + CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.STOP + | CoverEntityFeature.SET_POSITION + ) + assert state.attributes["supported_features"] & mask == mask + + for position in (0, 99): + set_node_attribute(window_covering, 1, 258, 8, position) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.attributes["current_position"] == 100 - position + assert state.state == STATE_OPEN + + set_node_attribute(window_covering, 1, 258, 8, 100) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) assert state assert state.attributes["current_position"] == 0 assert state.state == STATE_CLOSED + + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_tilt", "cover.mock_tilt_window_covering"), + ("window-covering_pa-tilt", "cover.mock_pa_tilt_window_covering"), + ("window-covering_full", "cover.mock_full_window_covering"), + ], +) +async def test_cover_tilt( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with tilt and position aware tilt features.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + + await hass.services.async_call( + "cover", + "set_cover_tilt_position", + { + "entity_id": entity_id, + "tilt_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.GoToTiltPercentage(5000), + ) + matter_client.send_device_command.reset_mock() + + await trigger_subscription_callback(hass, matter_client) + + set_node_attribute(window_covering, 1, 258, 10, 0b100010) + await trigger_subscription_callback(hass, matter_client) + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_CLOSING + + set_node_attribute(window_covering, 1, 258, 10, 0b010001) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OPENING + + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_tilt", "cover.mock_tilt_window_covering"), + ], +) +async def test_cover_tilt_only( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with tilt feature and without position aware tilt feature.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + + set_node_attribute(window_covering, 1, 258, 65529, [0, 1, 2]) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert ( + state.attributes["supported_features"] & CoverEntityFeature.SET_TILT_POSITION + == 0 + ) + + set_node_attribute(window_covering, 1, 258, 65529, [0, 1, 2, 8]) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert ( + state.attributes["supported_features"] & CoverEntityFeature.SET_TILT_POSITION + != 0 + ) + + +# This tests needs to be adjusted to remove lingering tasks +@pytest.mark.parametrize("expected_lingering_tasks", [True]) +@pytest.mark.parametrize( + ("fixture", "entity_id"), + [ + ("window-covering_pa-tilt", "cover.mock_pa_tilt_window_covering"), + ], +) +async def test_cover_position_aware_tilt( + hass: HomeAssistant, + matter_client: MagicMock, + fixture: str, + entity_id: str, +) -> None: + """Test window covering devices with position aware tilt feature.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + fixture, + matter_client, + ) + + state = hass.states.get(entity_id) + assert state + mask = ( + CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.STOP + | CoverEntityFeature.SET_TILT_POSITION + ) + assert state.attributes["supported_features"] & mask == mask + + for tilt_position in (0, 99, 100): + set_node_attribute(window_covering, 1, 258, 9, tilt_position) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.attributes["current_tilt_position"] == 100 - tilt_position + + +async def test_cover_full_features( + hass: HomeAssistant, + matter_client: MagicMock, +) -> None: + """Test window covering devices with all the features.""" + + window_covering = await setup_integration_with_node_fixture( + hass, + "window-covering_full", + matter_client, + ) + entity_id = "cover.mock_full_window_covering" + + state = hass.states.get(entity_id) + assert state + mask = ( + CoverEntityFeature.OPEN + | CoverEntityFeature.CLOSE + | CoverEntityFeature.STOP + | CoverEntityFeature.SET_POSITION + | CoverEntityFeature.SET_TILT_POSITION + ) + assert state.attributes["supported_features"] & mask == mask + + set_node_attribute(window_covering, 1, 258, 8, 100) + set_node_attribute(window_covering, 1, 258, 9, 100) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_CLOSED + + set_node_attribute(window_covering, 1, 258, 8, 50) + set_node_attribute(window_covering, 1, 258, 9, 100) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OPEN + + set_node_attribute(window_covering, 1, 258, 8, 100) + set_node_attribute(window_covering, 1, 258, 9, 50) + set_node_attribute(window_covering, 1, 258, 10, 0b000000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_CLOSED