From 32f75597a9e3a48348c4c26b564643c5bd1d7295 Mon Sep 17 00:00:00 2001 From: red-island <114957153+red-island@users.noreply.github.com> Date: Sat, 24 Aug 2024 17:12:32 +0200 Subject: [PATCH] Fix tilt calculation for HomeKit cover devices (#123532) --- .../components/homekit_controller/cover.py | 96 +- .../fixtures/somfy_venetian_blinds.json | 146 ++ .../fixtures/velux_active_netatmo_co2.json | 162 ++ .../fixtures/velux_window.json | 122 + .../fixtures/velux_window_cover.json | 122 + .../snapshots/test_init.ambr | 2211 +++++++++++++++++ .../homekit_controller/test_cover.py | 134 + 7 files changed, 2943 insertions(+), 50 deletions(-) create mode 100644 tests/components/homekit_controller/fixtures/somfy_venetian_blinds.json create mode 100644 tests/components/homekit_controller/fixtures/velux_active_netatmo_co2.json create mode 100644 tests/components/homekit_controller/fixtures/velux_window.json create mode 100644 tests/components/homekit_controller/fixtures/velux_window_cover.json diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index d0944db38f8..0eebb72c988 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -214,34 +214,32 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity): @property def current_cover_tilt_position(self) -> int | None: """Return current position of cover tilt.""" - tilt_position = self.service.value(CharacteristicsTypes.VERTICAL_TILT_CURRENT) - if not tilt_position: - tilt_position = self.service.value( - CharacteristicsTypes.HORIZONTAL_TILT_CURRENT - ) - if tilt_position is None: - return None - # Recalculate to convert from arcdegree scale to percentage scale. if self.is_vertical_tilt: - scale = 0.9 - if ( - self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT].minValue == -90 - and self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT].maxValue - == 0 - ): - scale = -0.9 - tilt_position = int(tilt_position / scale) + char = self.service[CharacteristicsTypes.VERTICAL_TILT_CURRENT] elif self.is_horizontal_tilt: - scale = 0.9 - if ( - self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].minValue - == -90 - and self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].maxValue - == 0 - ): - scale = -0.9 - tilt_position = int(tilt_position / scale) - return tilt_position + char = self.service[CharacteristicsTypes.HORIZONTAL_TILT_CURRENT] + else: + return None + + # Recalculate tilt_position. Convert arc to percent scale based on min/max values. + tilt_position = char.value + min_value = char.minValue + max_value = char.maxValue + total_range = int(max_value or 0) - int(min_value or 0) + + if ( + tilt_position is None + or min_value is None + or max_value is None + or total_range <= 0 + ): + return None + + # inverted scale + if min_value == -90 and max_value == 0: + return abs(int(100 / total_range * (tilt_position - max_value))) + # normal scale + return abs(int(100 / total_range * (tilt_position - min_value))) async def async_stop_cover(self, **kwargs: Any) -> None: """Send hold command.""" @@ -265,34 +263,32 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity): async def async_set_cover_tilt_position(self, **kwargs: Any) -> None: """Move the cover tilt to a specific position.""" tilt_position = kwargs[ATTR_TILT_POSITION] + if self.is_vertical_tilt: - # Recalculate to convert from percentage scale to arcdegree scale. - scale = 0.9 - if ( - self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET].minValue == -90 - and self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET].maxValue - == 0 - ): - scale = -0.9 - tilt_position = int(tilt_position * scale) - await self.async_put_characteristics( - {CharacteristicsTypes.VERTICAL_TILT_TARGET: tilt_position} - ) + char = self.service[CharacteristicsTypes.VERTICAL_TILT_TARGET] elif self.is_horizontal_tilt: - # Recalculate to convert from percentage scale to arcdegree scale. - scale = 0.9 - if ( - self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].minValue - == -90 - and self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET].maxValue - == 0 - ): - scale = -0.9 - tilt_position = int(tilt_position * scale) - await self.async_put_characteristics( - {CharacteristicsTypes.HORIZONTAL_TILT_TARGET: tilt_position} + char = self.service[CharacteristicsTypes.HORIZONTAL_TILT_TARGET] + + # Calculate tilt_position. Convert from 1-100 scale to arc degree scale respecting possible min/max Values. + min_value = char.minValue + max_value = char.maxValue + if min_value is None or max_value is None: + raise ValueError( + "Entity does not provide minValue and maxValue for the tilt" ) + # inverted scale + if min_value == -90 and max_value == 0: + tilt_position = int( + tilt_position / 100 * (min_value - max_value) + max_value + ) + else: + tilt_position = int( + tilt_position / 100 * (max_value - min_value) + min_value + ) + + await self.async_put_characteristics({char.type: tilt_position}) + @property def extra_state_attributes(self) -> dict[str, Any]: """Return the optional state attributes.""" diff --git a/tests/components/homekit_controller/fixtures/somfy_venetian_blinds.json b/tests/components/homekit_controller/fixtures/somfy_venetian_blinds.json new file mode 100644 index 00000000000..65d3126cc4b --- /dev/null +++ b/tests/components/homekit_controller/fixtures/somfy_venetian_blinds.json @@ -0,0 +1,146 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": ["pr"], + "format": "string", + "value": "VELUX Internal Cover", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": ["pr"], + "format": "string", + "value": "Netatmo", + "description": "Manufacturer", + "maxLen": 64 + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": ["pr"], + "format": "string", + "value": "VELUX Internal Cover", + "description": "Model", + "maxLen": 64 + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": ["pr"], + "format": "string", + "value": "**REDACTED**", + "description": "Serial Number", + "maxLen": 64 + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": ["pw"], + "format": "bool", + "description": "Identify" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": ["pr"], + "format": "string", + "value": "0.0.0", + "description": "Firmware Revision", + "maxLen": 64 + }, + { + "type": "00000220-0000-1000-8000-0026BB765291", + "iid": 15, + "perms": ["pr"], + "format": "data", + "value": "+nvrOv1cCQU=" + } + ] + }, + { + "iid": 8, + "type": "0000008C-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": ["pr"], + "format": "string", + "value": "Venetian Blinds", + "description": "Name", + "maxLen": 64 + }, + { + "type": "0000007C-0000-1000-8000-0026BB765291", + "iid": 11, + "perms": ["pr", "pw", "ev"], + "format": "uint8", + "value": 0, + "description": "Target Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "0000006D-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 0, + "description": "Current Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "00000072-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 2, + "description": "Position State", + "minValue": 0, + "maxValue": 2, + "minStep": 1 + }, + { + "type": "0000006C-0000-1000-8000-0026BB765291", + "iid": 13, + "perms": ["pr", "ev"], + "format": "int", + "value": 90, + "description": "Current Horizontal Tilt Angle", + "unit": "arcdegrees", + "minValue": -90, + "maxValue": 90, + "minStep": 1 + }, + { + "type": "0000007B-0000-1000-8000-0026BB765291", + "iid": 14, + "perms": ["pr", "pw", "ev"], + "format": "int", + "value": 90, + "description": "Target Horizontal Tilt Angle", + "unit": "arcdegrees", + "minValue": -90, + "maxValue": 90, + "minStep": 1 + } + ] + } + ] + } +] diff --git a/tests/components/homekit_controller/fixtures/velux_active_netatmo_co2.json b/tests/components/homekit_controller/fixtures/velux_active_netatmo_co2.json new file mode 100644 index 00000000000..80b2b34648e --- /dev/null +++ b/tests/components/homekit_controller/fixtures/velux_active_netatmo_co2.json @@ -0,0 +1,162 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": ["pr"], + "format": "string", + "value": "VELUX Sensor", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": ["pr"], + "format": "string", + "value": "Netatmo", + "description": "Manufacturer", + "maxLen": 64 + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": ["pr"], + "format": "string", + "value": "VELUX Sensor", + "description": "Model", + "maxLen": 64 + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": ["pr"], + "format": "string", + "value": "**REDACTED**", + "description": "Serial Number", + "maxLen": 64 + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": ["pw"], + "format": "bool", + "description": "Identify" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": ["pr"], + "format": "string", + "value": "16.0.0", + "description": "Firmware Revision", + "maxLen": 64 + }, + { + "type": "00000220-0000-1000-8000-0026BB765291", + "iid": 18, + "perms": ["pr"], + "format": "data", + "value": "+nvrOv1cCQU=" + } + ] + }, + { + "iid": 8, + "type": "0000008A-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": ["pr"], + "format": "string", + "value": "Temperature sensor", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000011-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": ["pr", "ev"], + "format": "float", + "value": 23.9, + "description": "Current Temperature", + "unit": "celsius", + "minValue": 0.0, + "maxValue": 50.0, + "minStep": 0.1 + } + ] + }, + { + "iid": 11, + "type": "00000082-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": ["pr"], + "format": "string", + "value": "Humidity sensor", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000010-0000-1000-8000-0026BB765291", + "iid": 13, + "perms": ["pr", "ev"], + "format": "float", + "value": 69.0, + "description": "Current Relative Humidity", + "unit": "percentage", + "minValue": 0.0, + "maxValue": 100.0, + "minStep": 1.0 + } + ] + }, + { + "iid": 14, + "type": "00000097-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 15, + "perms": ["pr"], + "format": "string", + "value": "Carbon Dioxide sensor", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000092-0000-1000-8000-0026BB765291", + "iid": 16, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 0, + "description": "Carbon Dioxide Detected", + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "type": "00000093-0000-1000-8000-0026BB765291", + "iid": 17, + "perms": ["pr", "ev"], + "format": "float", + "value": 1124.0, + "description": "Carbon Dioxide Level", + "minValue": 0.0, + "maxValue": 5000.0 + } + ] + } + ] + } +] diff --git a/tests/components/homekit_controller/fixtures/velux_window.json b/tests/components/homekit_controller/fixtures/velux_window.json new file mode 100644 index 00000000000..4d9a09344bb --- /dev/null +++ b/tests/components/homekit_controller/fixtures/velux_window.json @@ -0,0 +1,122 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": ["pr"], + "format": "string", + "value": "VELUX Window", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": ["pr"], + "format": "string", + "value": "Netatmo", + "description": "Manufacturer", + "maxLen": 64 + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": ["pr"], + "format": "string", + "value": "VELUX Window", + "description": "Model", + "maxLen": 64 + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": ["pr"], + "format": "string", + "value": "**REDACTED**", + "description": "Serial Number", + "maxLen": 64 + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": ["pw"], + "format": "bool", + "description": "Identify" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": ["pr"], + "format": "string", + "value": "0.0.0", + "description": "Firmware Revision", + "maxLen": 64 + }, + { + "type": "00000220-0000-1000-8000-0026BB765291", + "iid": 13, + "perms": ["pr"], + "format": "data", + "value": "+nvrOv1cCQU=" + } + ] + }, + { + "iid": 8, + "type": "0000008B-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": ["pr"], + "format": "string", + "value": "Roof Window", + "description": "Name", + "maxLen": 64 + }, + { + "type": "0000007C-0000-1000-8000-0026BB765291", + "iid": 11, + "perms": ["pr", "pw", "ev"], + "format": "uint8", + "value": 0, + "description": "Target Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "0000006D-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 0, + "description": "Current Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "00000072-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 2, + "description": "Position State", + "minValue": 0, + "maxValue": 2, + "minStep": 1 + } + ] + } + ] + } +] diff --git a/tests/components/homekit_controller/fixtures/velux_window_cover.json b/tests/components/homekit_controller/fixtures/velux_window_cover.json new file mode 100644 index 00000000000..d95fbbd42bf --- /dev/null +++ b/tests/components/homekit_controller/fixtures/velux_window_cover.json @@ -0,0 +1,122 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": ["pr"], + "format": "string", + "value": "VELUX External Cover", + "description": "Name", + "maxLen": 64 + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": ["pr"], + "format": "string", + "value": "Netatmo", + "description": "Manufacturer", + "maxLen": 64 + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": ["pr"], + "format": "string", + "value": "VELUX External Cover", + "description": "Model", + "maxLen": 64 + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": ["pr"], + "format": "string", + "value": "**REDACTED**", + "description": "Serial Number", + "maxLen": 64 + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": ["pw"], + "format": "bool", + "description": "Identify" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": ["pr"], + "format": "string", + "value": "15.0.0", + "description": "Firmware Revision", + "maxLen": 64 + }, + { + "type": "00000220-0000-1000-8000-0026BB765291", + "iid": 13, + "perms": ["pr"], + "format": "data", + "value": "+nvrOv1cCQU=" + } + ] + }, + { + "iid": 8, + "type": "0000008C-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": ["pr"], + "format": "string", + "value": "Awning Blinds", + "description": "Name", + "maxLen": 64 + }, + { + "type": "0000007C-0000-1000-8000-0026BB765291", + "iid": 11, + "perms": ["pr", "pw", "ev"], + "format": "uint8", + "value": 0, + "description": "Target Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "0000006D-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 0, + "description": "Current Position", + "unit": "percentage", + "minValue": 0, + "maxValue": 100, + "minStep": 1 + }, + { + "type": "00000072-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": ["pr", "ev"], + "format": "uint8", + "value": 2, + "description": "Position State", + "minValue": 0, + "maxValue": 2, + "minStep": 1 + } + ] + } + ] + } +] diff --git a/tests/components/homekit_controller/snapshots/test_init.ambr b/tests/components/homekit_controller/snapshots/test_init.ambr index 078ef792a55..6a0fead65d3 100644 --- a/tests/components/homekit_controller/snapshots/test_init.ambr +++ b/tests/components/homekit_controller/snapshots/test_init.ambr @@ -17636,6 +17636,342 @@ }), ]) # --- +# name: test_snapshots[somfy_venetian_blinds] + list([ + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:1', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Internal Cover', + 'model_id': None, + 'name': 'VELUX Internal Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_internal_cover_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Internal Cover Identify', + }), + 'entity_id': 'button.velux_internal_cover_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_internal_cover_venetian_blinds', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Venetian Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'current_tilt_position': 100, + 'friendly_name': 'VELUX Internal Cover Venetian Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_internal_cover_venetian_blinds', + 'state': 'closed', + }), + }), + ]), + }), + ]) +# --- +# name: test_snapshots[velux_active_netatmo_co2] + list([ + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:1', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Sensor', + 'model_id': None, + 'name': 'VELUX Sensor', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '16.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_sensor_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Sensor Identify', + }), + 'entity_id': 'button.velux_sensor_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Carbon Dioxide sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_14', + 'unit_of_measurement': 'ppm', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'carbon_dioxide', + 'friendly_name': 'VELUX Sensor Carbon Dioxide sensor', + 'state_class': , + 'unit_of_measurement': 'ppm', + }), + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor', + 'state': '1124.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_humidity_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Humidity sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_11', + 'unit_of_measurement': '%', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'humidity', + 'friendly_name': 'VELUX Sensor Humidity sensor', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'entity_id': 'sensor.velux_sensor_humidity_sensor', + 'state': '69.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_temperature_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Temperature sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_8', + 'unit_of_measurement': , + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'temperature', + 'friendly_name': 'VELUX Sensor Temperature sensor', + 'state_class': , + 'unit_of_measurement': , + }), + 'entity_id': 'sensor.velux_sensor_temperature_sensor', + 'state': '23.9', + }), + }), + ]), + }), + ]) +# --- # name: test_snapshots[velux_gateway] list([ dict({ @@ -18043,6 +18379,1881 @@ }), ]) # --- +# name: test_snapshots[velux_somfy_venetian_blinds] + list([ + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:5', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX External Cover', + 'model_id': None, + 'name': 'VELUX External Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '15.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_external_cover_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX External Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_5_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX External Cover Identify', + }), + 'entity_id': 'button.velux_external_cover_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_external_cover_awning_blinds', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX External Cover Awning Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_5_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'friendly_name': 'VELUX External Cover Awning Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_external_cover_awning_blinds', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:8', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX External Cover', + 'model_id': None, + 'name': 'VELUX External Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_external_cover_identify_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX External Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_8_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX External Cover Identify', + }), + 'entity_id': 'button.velux_external_cover_identify_2', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_external_cover_awning_blinds_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX External Cover Awning Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_8_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 45, + 'friendly_name': 'VELUX External Cover Awning Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_external_cover_awning_blinds_2', + 'state': 'open', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:11', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX External Cover', + 'model_id': None, + 'name': 'VELUX External Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '15.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_external_cover_identify_3', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX External Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_11_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX External Cover Identify', + }), + 'entity_id': 'button.velux_external_cover_identify_3', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_external_cover_awning_blinds_3', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX External Cover Awning Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_11_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'friendly_name': 'VELUX External Cover Awning Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_external_cover_awning_blinds_3', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:12', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX External Cover', + 'model_id': None, + 'name': 'VELUX External Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '15.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_external_cover_identify_4', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX External Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_12_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX External Cover Identify', + }), + 'entity_id': 'button.velux_external_cover_identify_4', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_external_cover_awning_blinds_4', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX External Cover Awning Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_12_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'friendly_name': 'VELUX External Cover Awning Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_external_cover_awning_blinds_4', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:1', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Gateway', + 'model_id': None, + 'name': 'VELUX Gateway', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '132.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_gateway_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Gateway Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_1_6', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Gateway Identify', + }), + 'entity_id': 'button.velux_gateway_identify', + 'state': 'unknown', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:9', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Internal Cover', + 'model_id': None, + 'name': 'VELUX Internal Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_internal_cover_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_9_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Internal Cover Identify', + }), + 'entity_id': 'button.velux_internal_cover_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_internal_cover_venetian_blinds', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Venetian Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_9_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'current_tilt_position': 100, + 'friendly_name': 'VELUX Internal Cover Venetian Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_internal_cover_venetian_blinds', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:13', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Internal Cover', + 'model_id': None, + 'name': 'VELUX Internal Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_internal_cover_identify_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_13_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Internal Cover Identify', + }), + 'entity_id': 'button.velux_internal_cover_identify_2', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_internal_cover_venetian_blinds_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Venetian Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_13_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 100, + 'current_tilt_position': 0, + 'friendly_name': 'VELUX Internal Cover Venetian Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_internal_cover_venetian_blinds_2', + 'state': 'open', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:14', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Internal Cover', + 'model_id': None, + 'name': 'VELUX Internal Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_internal_cover_identify_3', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_14_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Internal Cover Identify', + }), + 'entity_id': 'button.velux_internal_cover_identify_3', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_internal_cover_venetian_blinds_3', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Venetian Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_14_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'current_tilt_position': 100, + 'friendly_name': 'VELUX Internal Cover Venetian Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_internal_cover_venetian_blinds_3', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:15', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Internal Cover', + 'model_id': None, + 'name': 'VELUX Internal Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_internal_cover_identify_4', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Internal Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_15_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Internal Cover Identify', + }), + 'entity_id': 'button.velux_internal_cover_identify_4', + 'state': 'unknown', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:2', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Sensor', + 'model_id': None, + 'name': 'VELUX Sensor', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '16.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_sensor_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_2_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Sensor Identify', + }), + 'entity_id': 'button.velux_sensor_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Carbon Dioxide sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_2_14', + 'unit_of_measurement': 'ppm', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'carbon_dioxide', + 'friendly_name': 'VELUX Sensor Carbon Dioxide sensor', + 'state_class': , + 'unit_of_measurement': 'ppm', + }), + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor', + 'state': '1124.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_humidity_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Humidity sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_2_11', + 'unit_of_measurement': '%', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'humidity', + 'friendly_name': 'VELUX Sensor Humidity sensor', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'entity_id': 'sensor.velux_sensor_humidity_sensor', + 'state': '69.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_temperature_sensor', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Temperature sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_2_8', + 'unit_of_measurement': , + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'temperature', + 'friendly_name': 'VELUX Sensor Temperature sensor', + 'state_class': , + 'unit_of_measurement': , + }), + 'entity_id': 'sensor.velux_sensor_temperature_sensor', + 'state': '23.9', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:3', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Sensor', + 'model_id': None, + 'name': 'VELUX Sensor', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '16.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_sensor_identify_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_3_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Sensor Identify', + }), + 'entity_id': 'button.velux_sensor_identify_2', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Carbon Dioxide sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_3_14', + 'unit_of_measurement': 'ppm', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'carbon_dioxide', + 'friendly_name': 'VELUX Sensor Carbon Dioxide sensor', + 'state_class': , + 'unit_of_measurement': 'ppm', + }), + 'entity_id': 'sensor.velux_sensor_carbon_dioxide_sensor_2', + 'state': '1074.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_humidity_sensor_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Humidity sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_3_11', + 'unit_of_measurement': '%', + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'humidity', + 'friendly_name': 'VELUX Sensor Humidity sensor', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'entity_id': 'sensor.velux_sensor_humidity_sensor_2', + 'state': '64.0', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.velux_sensor_temperature_sensor_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Sensor Temperature sensor', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_3_8', + 'unit_of_measurement': , + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'temperature', + 'friendly_name': 'VELUX Sensor Temperature sensor', + 'state_class': , + 'unit_of_measurement': , + }), + 'entity_id': 'sensor.velux_sensor_temperature_sensor_2', + 'state': '24.5', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:4', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Window', + 'model_id': None, + 'name': 'VELUX Window', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_window_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_4_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Window Identify', + }), + 'entity_id': 'button.velux_window_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_window_roof_window', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Roof Window', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_4_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'device_class': 'window', + 'friendly_name': 'VELUX Window Roof Window', + 'supported_features': , + }), + 'entity_id': 'cover.velux_window_roof_window', + 'state': 'closed', + }), + }), + ]), + }), + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:7', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Window', + 'model_id': None, + 'name': 'VELUX Window', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_window_identify_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_7_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Window Identify', + }), + 'entity_id': 'button.velux_window_identify_2', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_window_roof_window_2', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Roof Window', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_7_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'device_class': 'window', + 'friendly_name': 'VELUX Window Roof Window', + 'supported_features': , + }), + 'entity_id': 'cover.velux_window_roof_window_2', + 'state': 'closed', + }), + }), + ]), + }), + ]) +# --- +# name: test_snapshots[velux_window] + list([ + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:1', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX Window', + 'model_id': None, + 'name': 'VELUX Window', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '0.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_window_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX Window Identify', + }), + 'entity_id': 'button.velux_window_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_window_roof_window', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX Window Roof Window', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'device_class': 'window', + 'friendly_name': 'VELUX Window Roof Window', + 'supported_features': , + }), + 'entity_id': 'cover.velux_window_roof_window', + 'state': 'closed', + }), + }), + ]), + }), + ]) +# --- +# name: test_snapshots[velux_window_cover] + list([ + dict({ + 'device': dict({ + 'area_id': None, + 'config_entries': list([ + 'TestData', + ]), + 'configuration_url': None, + 'connections': list([ + ]), + 'disabled_by': None, + 'entry_type': None, + 'hw_version': '', + 'identifiers': list([ + list([ + 'homekit_controller:accessory-id', + '00:00:00:00:00:00:aid:1', + ]), + ]), + 'is_new': False, + 'labels': list([ + ]), + 'manufacturer': 'Netatmo', + 'model': 'VELUX External Cover', + 'model_id': None, + 'name': 'VELUX External Cover', + 'name_by_user': None, + 'primary_config_entry': 'TestData', + 'serial_number': '**REDACTED**', + 'suggested_area': None, + 'sw_version': '15.0.0', + }), + 'entities': list([ + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'button', + 'entity_category': , + 'entity_id': 'button.velux_external_cover_identify', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'VELUX External Cover Identify', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_1_7', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'device_class': 'identify', + 'friendly_name': 'VELUX External Cover Identify', + }), + 'entity_id': 'button.velux_external_cover_identify', + 'state': 'unknown', + }), + }), + dict({ + 'entry': dict({ + 'aliases': list([ + ]), + 'area_id': None, + 'capabilities': None, + 'categories': dict({ + }), + 'config_entry_id': 'TestData', + 'device_class': None, + 'disabled_by': None, + 'domain': 'cover', + 'entity_category': None, + 'entity_id': 'cover.velux_external_cover_awning_blinds', + 'has_entity_name': False, + 'hidden_by': None, + 'icon': None, + 'labels': list([ + ]), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'VELUX External Cover Awning Blinds', + 'platform': 'homekit_controller', + 'previous_unique_id': None, + 'supported_features': , + 'translation_key': None, + 'unique_id': '00:00:00:00:00:00_1_8', + 'unit_of_measurement': None, + }), + 'state': dict({ + 'attributes': dict({ + 'current_position': 0, + 'friendly_name': 'VELUX External Cover Awning Blinds', + 'supported_features': , + }), + 'entity_id': 'cover.velux_external_cover_awning_blinds', + 'state': 'closed', + }), + }), + ]), + }), + ]) +# --- # name: test_snapshots[vocolinc_flowerbud] list([ dict({ diff --git a/tests/components/homekit_controller/test_cover.py b/tests/components/homekit_controller/test_cover.py index 7415e97a4b1..11870c801e1 100644 --- a/tests/components/homekit_controller/test_cover.py +++ b/tests/components/homekit_controller/test_cover.py @@ -116,6 +116,32 @@ def create_window_covering_service_with_none_tilt(accessory: Accessory) -> None: tilt_target.maxValue = 0 +def create_window_covering_service_with_no_minmax_tilt(accessory): + """Apply use values (-90 to 90) if min/max not provided.""" + service = create_window_covering_service(accessory) + + tilt_current = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_CURRENT) + tilt_current.value = 0 + + tilt_target = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_TARGET) + tilt_target.value = 0 + + +def create_window_covering_service_with_full_range_tilt(accessory): + """Somfi Velux Integration.""" + service = create_window_covering_service(accessory) + + tilt_current = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_CURRENT) + tilt_current.value = 0 + tilt_current.minValue = -90 + tilt_current.maxValue = 90 + + tilt_target = service.add_char(CharacteristicsTypes.HORIZONTAL_TILT_TARGET) + tilt_target.value = 0 + tilt_target.minValue = -90 + tilt_target.maxValue = 90 + + async def test_change_window_cover_state( hass: HomeAssistant, get_next_aid: Callable[[], int] ) -> None: @@ -267,6 +293,40 @@ async def test_read_window_cover_tilt_missing_tilt( assert state.state != STATE_UNAVAILABLE +async def test_read_window_cover_tilt_full_range( + hass: HomeAssistant, get_next_aid: Callable[[], int] +) -> None: + """Test that horizontal tilt is handled correctly.""" + helper = await setup_test_component( + hass, get_next_aid(), create_window_covering_service_with_full_range_tilt + ) + + await helper.async_update( + ServicesTypes.WINDOW_COVERING, + {CharacteristicsTypes.HORIZONTAL_TILT_CURRENT: 0}, + ) + state = await helper.poll_and_get_state() + # Expect converted value from arcdegree scale to percentage scale. + assert state.attributes["current_tilt_position"] == 50 + + +async def test_read_window_cover_tilt_no_minmax( + hass: HomeAssistant, get_next_aid: Callable[[], int] +) -> None: + """Test that horizontal tilt is handled correctly.""" + helper = await setup_test_component( + hass, get_next_aid(), create_window_covering_service_with_no_minmax_tilt + ) + + await helper.async_update( + ServicesTypes.WINDOW_COVERING, + {CharacteristicsTypes.HORIZONTAL_TILT_CURRENT: 90}, + ) + state = await helper.poll_and_get_state() + # Expect converted value from arcdegree scale to percentage scale. + assert state.attributes["current_tilt_position"] == 100 + + async def test_write_window_cover_tilt_horizontal( hass: HomeAssistant, get_next_aid: Callable[[], int] ) -> None: @@ -359,6 +419,29 @@ async def test_write_window_cover_tilt_vertical_2( ) +async def test_write_window_cover_tilt_no_minmax( + hass: HomeAssistant, get_next_aid: Callable[[], int] +) -> None: + """Test that horizontal tilt is written correctly.""" + helper = await setup_test_component( + hass, get_next_aid(), create_window_covering_service_with_no_minmax_tilt + ) + + await hass.services.async_call( + "cover", + "set_cover_tilt_position", + {"entity_id": helper.entity_id, "tilt_position": 90}, + blocking=True, + ) + # Expect converted value from percentage scale to arcdegree scale. + helper.async_assert_service_values( + ServicesTypes.WINDOW_COVERING, + { + CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 72, + }, + ) + + async def test_window_cover_stop( hass: HomeAssistant, get_next_aid: Callable[[], int] ) -> None: @@ -378,6 +461,57 @@ async def test_window_cover_stop( ) +async def test_write_window_cover_tilt_full_range( + hass: HomeAssistant, get_next_aid: Callable[[], int] +) -> None: + """Test that full-range tilt is working correctly.""" + helper = await setup_test_component( + hass, get_next_aid(), create_window_covering_service_with_full_range_tilt + ) + + await hass.services.async_call( + "cover", + "set_cover_tilt_position", + {"entity_id": helper.entity_id, "tilt_position": 10}, + blocking=True, + ) + # Expect converted value from percentage scale to arc on -90 to +90 scale. + helper.async_assert_service_values( + ServicesTypes.WINDOW_COVERING, + { + CharacteristicsTypes.HORIZONTAL_TILT_TARGET: -72, + }, + ) + + await hass.services.async_call( + "cover", + "set_cover_tilt_position", + {"entity_id": helper.entity_id, "tilt_position": 50}, + blocking=True, + ) + # Expect converted value from percentage scale to arc on -90 to +90 scale. + helper.async_assert_service_values( + ServicesTypes.WINDOW_COVERING, + { + CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 0, + }, + ) + + await hass.services.async_call( + "cover", + "set_cover_tilt_position", + {"entity_id": helper.entity_id, "tilt_position": 90}, + blocking=True, + ) + # Expect converted value from percentage scale to arc on -90 to +90 scale. + helper.async_assert_service_values( + ServicesTypes.WINDOW_COVERING, + { + CharacteristicsTypes.HORIZONTAL_TILT_TARGET: 72, + }, + ) + + def create_garage_door_opener_service(accessory: Accessory) -> None: """Define a garage-door-opener chars as per page 217 of HAP spec.""" service = accessory.add_service(ServicesTypes.GARAGE_DOOR_OPENER)