diff --git a/homeassistant/components/matter/cover.py b/homeassistant/components/matter/cover.py index 5fe0995ff469..afc55ba71018 100644 --- a/homeassistant/components/matter/cover.py +++ b/homeassistant/components/matter/cover.py @@ -174,9 +174,10 @@ class MatterCover(MatterEntity, CoverEntity): self.current_cover_position, ) - if self._entity_info.endpoint.has_attribute( + has_tilt_position_attribute = self._entity_info.endpoint.has_attribute( None, clusters.WindowCovering.Attributes.CurrentPositionTiltPercent100ths - ): + ) + if has_tilt_position_attribute: # 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.CurrentPositionTiltPercent100ths @@ -206,9 +207,17 @@ class MatterCover(MatterEntity, CoverEntity): commands = self.get_matter_attribute_value( clusters.WindowCovering.Attributes.AcceptedCommandList ) + feature_map = self.get_matter_attribute_value( + clusters.WindowCovering.Attributes.FeatureMap + ) if clusters.WindowCovering.Commands.GoToLiftPercentage.command_id in commands: supported_features |= CoverEntityFeature.SET_POSITION - if clusters.WindowCovering.Commands.GoToTiltPercentage.command_id in commands: + # Some devices report GoToTiltPercentage in AcceptedCommandList even + # without tilt support, so also require the FeatureMap Tilt bit. + if ( + clusters.WindowCovering.Commands.GoToTiltPercentage.command_id in commands + and feature_map & clusters.WindowCovering.Bitmaps.Feature.kTilt + ): supported_features |= CoverEntityFeature.SET_TILT_POSITION self._attr_supported_features = supported_features @@ -271,6 +280,11 @@ DISCOVERY_SCHEMAS = [ clusters.WindowCovering.Attributes.OperationalStatus, clusters.WindowCovering.Attributes.Type, clusters.WindowCovering.Attributes.CurrentPositionLiftPercent100ths, + ), + # tilt is optional, not required: some devices (e.g. Shelly 2PM Gen4) + # report it as present but null instead of omitting it when tilt is + # disabled, which would otherwise fail schema matching + optional_attributes=( clusters.WindowCovering.Attributes.CurrentPositionTiltPercent100ths, ), ), diff --git a/tests/components/matter/common.py b/tests/components/matter/common.py index 6c3ffd76340f..31915c43e864 100644 --- a/tests/components/matter/common.py +++ b/tests/components/matter/common.py @@ -93,6 +93,7 @@ FIXTURES = [ "mock_window_covering_full", "mock_window_covering_lift", "mock_window_covering_pa_lift", + "mock_window_covering_pa_lift_null_tilt", "mock_window_covering_pa_tilt", "mock_window_covering_tilt", "onoff_light_with_levelcontrol_present", diff --git a/tests/components/matter/fixtures/nodes/mock_window_covering_pa_lift_null_tilt.json b/tests/components/matter/fixtures/nodes/mock_window_covering_pa_lift_null_tilt.json new file mode 100644 index 000000000000..1508a2129fef --- /dev/null +++ b/tests/components/matter/fixtures/nodes/mock_window_covering_pa_lift_null_tilt.json @@ -0,0 +1,315 @@ +{ + "node_id": 400, + "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": [ + { + "0": 22, + "1": 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": [ + { + "1": 5, + "2": 2, + "3": [112233], + "4": null, + "254": 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": "Shelly", + "0/40/2": 4895, + "0/40/3": "Shelly 2PM Gen4", + "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": "mock-shelly-2pm-gen4-null-tilt-0001", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "7630EF9998EDF03C", + "0/40/19": { + "0": 3, + "1": 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": { + "0": 60, + "1": 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": [ + { + "0": "TE9OR0FOLUlPVA==", + "1": 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": [ + { + "0": "WIFI_STA_DEF", + "1": true, + "2": null, + "3": null, + "4": "hPcDB5/k", + "5": ["wKgIhg=="], + "6": ["/oAAAAAAAACG9wP//gef5A==", "JA4DsgZ+bsCG9wP//gef5A=="], + "7": 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": [ + { + "1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVASQRARgkBwEkCAEwCUEE5Rw88GvXEUXr+cPYgKd00rIWyiHM8eu4Bhrzf1v83yBI2Qa+pwfOsKyvzxiuHLMfzhdC3gre4najpimi8AsX+TcKNQEoARgkAgE2AwQCBAEYMAQUWh6NlHAMbG5gz+vqlF51fulr3z8wBRR+D1hE33RhFC/mJWrhhZs6SVStQBgwC0DD5IxVgOrftUA47K1bQHaCNuWqIxf/8oMfcI0nMvTtXApwbBAJI/LjjCwMZJVFBE3W/FC6dQWSEuF8ES745tLBGA==", + "2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEzpstYxy3lXF69g6H2vQ6uoqkdUsppJ4NcSyQcXQ8sQrF5HuzoVnDpevHfy0GAWHbXfE4VI0laTHvm/Wkj037ZjcKNQEpARgkAmAwBBR+D1hE33RhFC/mJWrhhZs6SVStQDAFFFCCK5NYv6CrD5/0S26zXBUwG0WBGDALQI5YKo3C3xvdqCrho2yZIJVJpJY2n9V/tmh7ESBBOHrY0b+K8Pf7hKhd5V0vzbCCbkhv1BNEne+lhcS2N6qhMNgY", + "254": 2 + } + ], + "0/62/1": [ + { + "1": "BFLMrM1satBpU0DN4sri/S4AVo/ugmZCndBfPO33Q+ZCKDZzNhMOB014+hZs0KL7vPssavT7Tb9nt0W+kpeAe0U=", + "2": 65521, + "3": 1, + "4": 1, + "5": "", + "254": 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": [ + { + "0": "room", + "1": "bedroom 2" + }, + { + "0": "orientation", + "1": "North" + }, + { + "0": "floor", + "1": "2" + }, + { + "0": "direction", + "1": "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": [ + { + "0": 514, + "1": 1 + } + ], + "1/29/1": [3, 4, 29, 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/258/0": 0, + "1/258/7": 13, + "1/258/8": 0, + "1/258/10": 0, + "1/258/11": 6, + "1/258/13": 0, + "1/258/14": 6, + "1/258/23": 1, + "1/258/65532": 5, + "1/258/65533": 5, + "1/258/65528": [], + "1/258/65529": [0, 1, 2, 5, 8], + "1/258/65531": [ + 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 23, 26, 65528, 65529, 65531, 65532, + 65533 + ], + "1/258/9": null, + "1/258/12": null, + "1/258/15": null, + "1/258/26": 0 + }, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/snapshots/test_binary_sensor.ambr b/tests/components/matter/snapshots/test_binary_sensor.ambr index e8dd0b3a4279..fb99b596c5eb 100644 --- a/tests/components/matter/snapshots/test_binary_sensor.ambr +++ b/tests/components/matter/snapshots/test_binary_sensor.ambr @@ -2436,6 +2436,57 @@ 'state': 'off', }) # --- +# name: test_binary_sensors[mock_window_covering_pa_lift_null_tilt][binary_sensor.shelly_2pm_gen4_configuration_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.shelly_2pm_gen4_configuration_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Configuration status', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Configuration status', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'config_status_operational', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-1-WindowCoveringConfigStatusOperational-258-7', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[mock_window_covering_pa_lift_null_tilt][binary_sensor.shelly_2pm_gen4_configuration_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'problem', + : 'Shelly 2PM Gen4 Configuration status', + }), + 'context': , + 'entity_id': 'binary_sensor.shelly_2pm_gen4_configuration_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_binary_sensors[mock_window_covering_pa_tilt][binary_sensor.mock_pa_tilt_window_covering_configuration_status-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/matter/snapshots/test_button.ambr b/tests/components/matter/snapshots/test_button.ambr index ff798bb0bcf0..9ba2e950f999 100644 --- a/tests/components/matter/snapshots/test_button.ambr +++ b/tests/components/matter/snapshots/test_button.ambr @@ -3809,6 +3809,57 @@ 'state': 'unknown', }) # --- +# name: test_buttons[mock_window_covering_pa_lift_null_tilt][button.shelly_2pm_gen4_identify-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.shelly_2pm_gen4_identify', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Identify', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Identify', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-1-IdentifyButton-3-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_buttons[mock_window_covering_pa_lift_null_tilt][button.shelly_2pm_gen4_identify-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'identify', + : 'Shelly 2PM Gen4 Identify', + }), + 'context': , + 'entity_id': 'button.shelly_2pm_gen4_identify', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unknown', + }) +# --- # name: test_buttons[onoff_light_with_levelcontrol_present][button.d215s_identify-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/matter/snapshots/test_cover.ambr b/tests/components/matter/snapshots/test_cover.ambr index c226415fc0c3..3182a3c23300 100644 --- a/tests/components/matter/snapshots/test_cover.ambr +++ b/tests/components/matter/snapshots/test_cover.ambr @@ -269,6 +269,60 @@ 'state': 'open', }) # --- +# name: test_covers[mock_window_covering_pa_lift_null_tilt][cover.shelly_2pm_gen4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.shelly_2pm_gen4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': None, + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-1-MatterCoverPositionAwareLiftAndTilt-258-10', + 'unit_of_measurement': None, + }) +# --- +# name: test_covers[mock_window_covering_pa_lift_null_tilt][cover.shelly_2pm_gen4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 100, + : 'shade', + : 'Shelly 2PM Gen4', + : False, + : , + }), + 'context': , + 'entity_id': 'cover.shelly_2pm_gen4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- # name: test_covers[mock_window_covering_pa_tilt][cover.mock_pa_tilt_window_covering-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index 856e8f250c38..7ee43f0893a6 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -25721,6 +25721,286 @@ 'state': '-36', }) # --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_boot_reason-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : list([ + 'unspecified', + 'power_on_reboot', + 'brown_out_reset', + 'software_watchdog_reset', + 'hardware_watchdog_reset', + 'software_update_completed', + 'software_reset', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.shelly_2pm_gen4_boot_reason', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Boot reason', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Boot reason', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'boot_reason', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-0-GeneralDiagnosticsBootReason-51-4', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_boot_reason-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'enum', + : 'Shelly 2PM Gen4 Boot reason', + : list([ + 'unspecified', + 'power_on_reboot', + 'brown_out_reset', + 'software_watchdog_reset', + 'hardware_watchdog_reset', + 'software_update_completed', + 'software_reset', + ]), + }), + 'context': , + 'entity_id': 'sensor.shelly_2pm_gen4_boot_reason', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'software_reset', + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_reboot_count-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.shelly_2pm_gen4_reboot_count', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Reboot count', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Reboot count', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'reboot_count', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-0-GeneralDiagnosticsRebootCount-51-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_reboot_count-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'Shelly 2PM Gen4 Reboot count', + : , + }), + 'context': , + 'entity_id': 'sensor.shelly_2pm_gen4_reboot_count', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '35', + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_target_opening_position-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.shelly_2pm_gen4_target_opening_position', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Target opening position', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Target opening position', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'window_covering_target_position', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-1-TargetPositionLiftPercent100ths-258-11', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_target_opening_position-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'Shelly 2PM Gen4 Target opening position', + : , + }), + 'context': , + 'entity_id': 'sensor.shelly_2pm_gen4_target_opening_position', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_uptime-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.shelly_2pm_gen4_uptime', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Uptime', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Uptime', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'uptime', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-0-GeneralDiagnosticsUpTime-51-2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_uptime-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'uptime', + : 'Shelly 2PM Gen4 Uptime', + }), + 'context': , + 'entity_id': 'sensor.shelly_2pm_gen4_uptime', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2025-01-01T13:57:57+00:00', + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_wi_fi_rssi-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + : , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.shelly_2pm_gen4_wi_fi_rssi', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Wi-Fi RSSI', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Wi-Fi RSSI', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'wifi_rssi', + 'unique_id': '00000000000004D2-0000000000000190-MatterNodeDevice-0-WiFiDiagnosticsRssi-54-4', + 'unit_of_measurement': 'dBm', + }) +# --- +# name: test_sensors[mock_window_covering_pa_lift_null_tilt][sensor.shelly_2pm_gen4_wi_fi_rssi-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'signal_strength', + : 'Shelly 2PM Gen4 Wi-Fi RSSI', + : , + : 'dBm', + }), + 'context': , + 'entity_id': 'sensor.shelly_2pm_gen4_wi_fi_rssi', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '-36', + }) +# --- # name: test_sensors[mock_window_covering_pa_tilt][sensor.mock_pa_tilt_window_covering_reboot_count-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/matter/test_cover.py b/tests/components/matter/test_cover.py index b7a9b03224ed..780efca58447 100644 --- a/tests/components/matter/test_cover.py +++ b/tests/components/matter/test_cover.py @@ -51,6 +51,7 @@ async def test_covers( [ ("mock_window_covering_lift", "cover.mock_lift_window_covering"), ("mock_window_covering_pa_lift", "cover.longan_link_wncv_da01"), + ("mock_window_covering_pa_lift_null_tilt", "cover.shelly_2pm_gen4"), ("mock_window_covering_tilt", "cover.mock_tilt_window_covering"), ("mock_window_covering_pa_tilt", "cover.mock_pa_tilt_window_covering"), ("mock_window_covering_full", "cover.mock_full_window_covering"), @@ -121,6 +122,7 @@ async def test_cover( [ ("mock_window_covering_lift", "cover.mock_lift_window_covering"), ("mock_window_covering_pa_lift", "cover.longan_link_wncv_da01"), + ("mock_window_covering_pa_lift_null_tilt", "cover.shelly_2pm_gen4"), ("mock_window_covering_full", "cover.mock_full_window_covering"), ], ) @@ -248,6 +250,30 @@ async def test_cover_position_aware_lift( assert state.state == CoverState.CLOSED +@pytest.mark.parametrize( + ("node_fixture", "entity_id"), + [ + ("mock_window_covering_pa_lift_null_tilt", "cover.shelly_2pm_gen4"), + ], +) +async def test_cover_position_aware_lift_null_tilt( + hass: HomeAssistant, + matter_node: MatterNode, + entity_id: str, +) -> None: + """Test null tilt attribute while tilt is disabled (Shelly 2PM Gen4). + + See home-assistant/core#149876. + """ + state = hass.states.get(entity_id) + assert state + assert ( + state.attributes["supported_features"] & CoverEntityFeature.SET_TILT_POSITION + == 0 + ) + assert "current_tilt_position" not in state.attributes + + @pytest.mark.parametrize( ("node_fixture", "entity_id"), [