Handle removal of accessories/services/chars in homekit_controller (#102179)

This commit is contained in:
J. Nick Koston 2023-10-17 20:49:35 -10:00 committed by GitHub
parent e2e9c84c88
commit c3d1db5db6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1907 additions and 65 deletions

View file

@ -26,6 +26,7 @@ from homeassistant.components.homekit_controller.const import (
DOMAIN,
HOMEKIT_ACCESSORY_DISPATCH,
IDENTIFIER_ACCESSORY_ID,
SUBSCRIBE_COOLDOWN,
)
from homeassistant.components.homekit_controller.utils import async_get_controller
from homeassistant.config_entries import ConfigEntry
@ -238,6 +239,7 @@ async def setup_test_accessories_with_controller(
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await time_changed(hass, SUBSCRIBE_COOLDOWN)
await hass.async_block_till_done()
return config_entry, pairing

View file

@ -0,0 +1,561 @@
[
{
"aid": 1,
"services": [
{
"type": "3E",
"characteristics": [
{
"value": "HomeW",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 2
},
{
"value": "ecobee Inc.",
"perms": ["pr"],
"type": "20",
"format": "string",
"iid": 3
},
{
"value": "123456789012",
"perms": ["pr"],
"type": "30",
"format": "string",
"iid": 4
},
{
"value": "ecobee3",
"perms": ["pr"],
"type": "21",
"format": "string",
"iid": 5
},
{
"perms": ["pw"],
"type": "14",
"format": "bool",
"iid": 6
},
{
"value": "4.2.394",
"perms": ["pr"],
"type": "52",
"format": "string",
"iid": 8
},
{
"value": 0,
"perms": ["pr", "ev"],
"type": "A6",
"format": "uint32",
"iid": 9
}
],
"iid": 1
},
{
"type": "A2",
"characteristics": [
{
"value": "1.1.0",
"perms": ["pr"],
"maxLen": 64,
"type": "37",
"format": "string",
"iid": 31
}
],
"iid": 30
},
{
"primary": true,
"type": "4A",
"characteristics": [
{
"value": 1,
"maxValue": 2,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "F",
"minValue": 0,
"format": "uint8",
"iid": 17
},
{
"value": 1,
"maxValue": 3,
"minStep": 1,
"perms": ["pr", "pw", "ev"],
"type": "33",
"minValue": 0,
"format": "uint8",
"iid": 18
},
{
"value": 21.8,
"maxValue": 100,
"minStep": 0.1,
"perms": ["pr", "ev"],
"unit": "celsius",
"type": "11",
"minValue": 0,
"format": "float",
"iid": 19
},
{
"value": 22.2,
"maxValue": 33.3,
"minStep": 0.1,
"perms": ["pr", "pw", "ev"],
"unit": "celsius",
"type": "35",
"minValue": 7.2,
"format": "float",
"iid": 20
},
{
"value": 1,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "pw", "ev"],
"type": "36",
"minValue": 0,
"format": "uint8",
"iid": 21
},
{
"value": 24.4,
"maxValue": 33.3,
"minStep": 0.1,
"perms": ["pr", "pw", "ev"],
"unit": "celsius",
"type": "D",
"minValue": 18.3,
"format": "float",
"iid": 22
},
{
"value": 22.2,
"maxValue": 26.1,
"minStep": 0.1,
"perms": ["pr", "pw", "ev"],
"unit": "celsius",
"type": "12",
"minValue": 7.2,
"format": "float",
"iid": 23
},
{
"value": 34,
"maxValue": 100,
"minStep": 1,
"perms": ["pr", "ev"],
"unit": "percentage",
"type": "10",
"minValue": 0,
"format": "float",
"iid": 24
},
{
"value": 36,
"maxValue": 50,
"minStep": 1,
"perms": ["pr", "pw", "ev"],
"unit": "percentage",
"type": "34",
"minValue": 20,
"format": "float",
"iid": 25
},
{
"value": "HomeW",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 27
}
],
"iid": 16
}
]
},
{
"aid": 2,
"services": [
{
"type": "3E",
"characteristics": [
{
"value": "Kitchen",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 2049
},
{
"value": "ecobee Inc.",
"perms": ["pr"],
"type": "20",
"format": "string",
"iid": 2050
},
{
"value": "AB1C",
"perms": ["pr"],
"type": "30",
"format": "string",
"iid": 2051
},
{
"value": "REMOTE SENSOR",
"perms": ["pr"],
"type": "21",
"format": "string",
"iid": 2052
},
{
"value": "1.0.0",
"perms": ["pr"],
"type": "52",
"format": "string",
"iid": 8
},
{
"perms": ["pw"],
"type": "14",
"format": "bool",
"iid": 2053
}
],
"iid": 1
},
{
"type": "8A",
"characteristics": [
{
"value": 21.5,
"maxValue": 100,
"minStep": 0.1,
"perms": ["pr", "ev"],
"unit": "celsius",
"type": "11",
"minValue": 0,
"format": "float",
"iid": 2064
},
{
"value": "Kitchen",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 2067
},
{
"value": true,
"perms": ["pr", "ev"],
"type": "75",
"format": "bool",
"iid": 2066
},
{
"value": 0,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "79",
"minValue": 0,
"format": "uint8",
"iid": 2065
}
],
"iid": 55
},
{
"type": "85",
"characteristics": [
{
"value": false,
"perms": ["pr", "ev"],
"type": "22",
"format": "bool",
"iid": 2060
},
{
"value": "Kitchen",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 2063
},
{
"value": true,
"perms": ["pr", "ev"],
"type": "75",
"format": "bool",
"iid": 2062
},
{
"minValue": 0,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "79",
"value": 0,
"format": "uint8",
"iid": 2061
},
{
"minValue": -1,
"maxValue": 86400,
"perms": ["pr", "ev"],
"type": "BFE61C70-4A40-11E6-BDF4-0800200C9A66",
"value": 3620,
"format": "int",
"iid": 2059
}
],
"iid": 56
}
]
},
{
"aid": 3,
"services": [
{
"type": "3E",
"characteristics": [
{
"value": "Porch",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 3073
},
{
"value": "ecobee Inc.",
"perms": ["pr"],
"type": "20",
"format": "string",
"iid": 3074
},
{
"value": "AB2C",
"perms": ["pr"],
"type": "30",
"format": "string",
"iid": 3075
},
{
"value": "REMOTE SENSOR",
"perms": ["pr"],
"type": "21",
"format": "string",
"iid": 3076
},
{
"value": "1.0.0",
"perms": ["pr"],
"type": "52",
"format": "string",
"iid": 8
},
{
"perms": ["pw"],
"type": "14",
"format": "bool",
"iid": 3077
}
],
"iid": 1
},
{
"type": "8A",
"characteristics": [
{
"value": 21,
"maxValue": 100,
"minStep": 0.1,
"perms": ["pr", "ev"],
"unit": "celsius",
"type": "11",
"minValue": 0,
"format": "float",
"iid": 3088
},
{
"value": "Porch",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 3091
},
{
"value": true,
"perms": ["pr", "ev"],
"type": "75",
"format": "bool",
"iid": 3090
},
{
"value": 0,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "79",
"minValue": 0,
"format": "uint8",
"iid": 3089
}
],
"iid": 55
},
{
"type": "85",
"characteristics": [
{
"value": false,
"perms": ["pr", "ev"],
"type": "22",
"format": "bool",
"iid": 3084
},
{
"value": "Porch",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 3087
},
{
"value": true,
"perms": ["pr", "ev"],
"type": "75",
"format": "bool",
"iid": 3086
},
{
"minValue": 0,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "79",
"value": 0,
"format": "uint8",
"iid": 3085
},
{
"minValue": -1,
"maxValue": 86400,
"perms": ["pr", "ev"],
"type": "BFE61C70-4A40-11E6-BDF4-0800200C9A66",
"value": 5766,
"format": "int",
"iid": 3083
}
],
"iid": 56
}
]
},
{
"aid": 4,
"services": [
{
"type": "3E",
"characteristics": [
{
"value": "Basement",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 4097
},
{
"value": "ecobee Inc.",
"perms": ["pr"],
"type": "20",
"format": "string",
"iid": 4098
},
{
"value": "AB3C",
"perms": ["pr"],
"type": "30",
"format": "string",
"iid": 4099
},
{
"value": "REMOTE SENSOR",
"perms": ["pr"],
"type": "21",
"format": "string",
"iid": 4100
},
{
"value": "1.0.0",
"perms": ["pr"],
"type": "52",
"format": "string",
"iid": 8
},
{
"perms": ["pw"],
"type": "14",
"format": "bool",
"iid": 4101
}
],
"iid": 1
},
{
"type": "85",
"characteristics": [
{
"value": false,
"perms": ["pr", "ev"],
"type": "22",
"format": "bool",
"iid": 4108
},
{
"value": "Basement",
"perms": ["pr"],
"type": "23",
"format": "string",
"iid": 4111
},
{
"value": true,
"perms": ["pr", "ev"],
"type": "75",
"format": "bool",
"iid": 4110
},
{
"minValue": 0,
"maxValue": 1,
"minStep": 1,
"perms": ["pr", "ev"],
"type": "79",
"value": 0,
"format": "uint8",
"iid": 4109
},
{
"minValue": -1,
"maxValue": 86400,
"perms": ["pr", "ev"],
"type": "BFE61C70-4A40-11E6-BDF4-0800200C9A66",
"value": 5472,
"format": "int",
"iid": 4107
}
],
"iid": 56
}
]
}
]

View file

@ -0,0 +1,166 @@
[
{
"aid": 1,
"services": [
{
"characteristics": [
{
"description": "Identify",
"format": "bool",
"iid": 2,
"perms": ["pw"],
"type": "00000014-0000-1000-8000-0026BB765291"
},
{
"description": "Manufacturer",
"format": "string",
"iid": 3,
"perms": ["pr"],
"type": "00000020-0000-1000-8000-0026BB765291",
"value": "Home Assistant"
},
{
"description": "Model",
"format": "string",
"iid": 4,
"perms": ["pr"],
"type": "00000021-0000-1000-8000-0026BB765291",
"value": "Bridge"
},
{
"description": "Name",
"format": "string",
"iid": 5,
"perms": ["pr"],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Home Assistant Bridge"
},
{
"description": "SerialNumber",
"format": "string",
"iid": 6,
"perms": ["pr"],
"type": "00000030-0000-1000-8000-0026BB765291",
"value": "homekit.bridge"
},
{
"description": "FirmwareRevision",
"format": "string",
"iid": 7,
"perms": ["pr"],
"type": "00000052-0000-1000-8000-0026BB765291",
"value": "0.104.0.dev0"
}
],
"iid": 1,
"stype": "accessory-information",
"type": "0000003E-0000-1000-8000-0026BB765291"
}
]
},
{
"aid": 1256851357,
"services": [
{
"characteristics": [
{
"description": "Identify",
"format": "bool",
"iid": 2,
"perms": ["pw"],
"type": "00000014-0000-1000-8000-0026BB765291"
},
{
"description": "Manufacturer",
"format": "string",
"iid": 3,
"perms": ["pr"],
"type": "00000020-0000-1000-8000-0026BB765291",
"value": "Home Assistant"
},
{
"description": "Model",
"format": "string",
"iid": 4,
"perms": ["pr"],
"type": "00000021-0000-1000-8000-0026BB765291",
"value": "Fan"
},
{
"description": "Name",
"format": "string",
"iid": 5,
"perms": ["pr"],
"type": "00000023-0000-1000-8000-0026BB765291",
"value": "Living Room Fan"
},
{
"description": "SerialNumber",
"format": "string",
"iid": 6,
"perms": ["pr"],
"type": "00000030-0000-1000-8000-0026BB765291",
"value": "fan.living_room_fan"
},
{
"description": "FirmwareRevision",
"format": "string",
"iid": 7,
"perms": ["pr"],
"type": "00000052-0000-1000-8000-0026BB765291",
"value": "0.104.0.dev0"
}
],
"iid": 1,
"stype": "accessory-information",
"type": "0000003E-0000-1000-8000-0026BB765291"
},
{
"characteristics": [
{
"description": "Active",
"format": "uint8",
"iid": 9,
"perms": ["pr", "pw", "ev"],
"type": "000000B0-0000-1000-8000-0026BB765291",
"valid-values": [0, 1],
"value": 0
},
{
"description": "RotationDirection",
"format": "int",
"iid": 10,
"perms": ["pr", "pw", "ev"],
"type": "00000028-0000-1000-8000-0026BB765291",
"valid-values": [0, 1],
"value": 0
},
{
"description": "SwingMode",
"format": "uint8",
"iid": 11,
"perms": ["pr", "pw", "ev"],
"type": "000000B6-0000-1000-8000-0026BB765291",
"valid-values": [0, 1],
"value": 0
},
{
"description": "RotationSpeed",
"format": "float",
"iid": 12,
"maxValue": 100,
"minStep": 1,
"minValue": 0,
"perms": ["pr", "pw", "ev"],
"type": "00000029-0000-1000-8000-0026BB765291",
"unit": "percentage",
"value": 100
}
],
"iid": 8,
"stype": "fanv2",
"type": "000000B7-0000-1000-8000-0026BB765291"
}
]
}
]

View file

@ -3935,6 +3935,656 @@
}),
])
# ---
# name: test_snapshots[ecobee3_service_removed]
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:4',
]),
]),
'is_new': False,
'manufacturer': 'ecobee Inc.',
'model': 'REMOTE SENSOR',
'name': 'Basement',
'name_by_user': None,
'suggested_area': None,
'sw_version': '1.0.0',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.basement',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.MOTION: 'motion'>,
'original_icon': None,
'original_name': 'Basement',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_4_56',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'device_class': 'motion',
'friendly_name': 'Basement',
}),
'entity_id': 'binary_sensor.basement',
'state': 'off',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.basement_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Basement Identify',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_4_1_4101',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'Basement Identify',
}),
'entity_id': 'button.basement_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:1',
]),
]),
'is_new': False,
'manufacturer': 'ecobee Inc.',
'model': 'ecobee3',
'name': 'HomeW',
'name_by_user': None,
'suggested_area': None,
'sw_version': '4.2.394',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.homew_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'HomeW 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({
'friendly_name': 'HomeW Identify',
}),
'entity_id': 'button.homew_identify',
'state': 'unknown',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'hvac_modes': list([
<HVACMode.OFF: 'off'>,
<HVACMode.HEAT: 'heat'>,
<HVACMode.COOL: 'cool'>,
<HVACMode.HEAT_COOL: 'heat_cool'>,
]),
'max_humidity': 50,
'max_temp': 33.3,
'min_humidity': 20,
'min_temp': 7.2,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'climate',
'entity_category': None,
'entity_id': 'climate.homew',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'HomeW',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': <ClimateEntityFeature: 7>,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1_16',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'current_humidity': 34,
'current_temperature': 21.8,
'friendly_name': 'HomeW',
'humidity': 36,
'hvac_action': <HVACAction.HEATING: 'heating'>,
'hvac_modes': list([
<HVACMode.OFF: 'off'>,
<HVACMode.HEAT: 'heat'>,
<HVACMode.COOL: 'cool'>,
<HVACMode.HEAT_COOL: 'heat_cool'>,
]),
'max_humidity': 50,
'max_temp': 33.3,
'min_humidity': 20,
'min_temp': 7.2,
'supported_features': <ClimateEntityFeature: 7>,
'target_temp_high': None,
'target_temp_low': None,
'temperature': 22.2,
}),
'entity_id': 'climate.homew',
'state': 'heat',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'options': list([
'celsius',
'fahrenheit',
]),
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.homew_temperature_display_units',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:thermometer',
'original_name': 'HomeW Temperature Display Units',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'temperature_display_units',
'unique_id': '00:00:00:00:00:00_1_16_21',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'HomeW Temperature Display Units',
'icon': 'mdi:thermometer',
'options': list([
'celsius',
'fahrenheit',
]),
}),
'entity_id': 'select.homew_temperature_display_units',
'state': 'fahrenheit',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.homew_current_humidity',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
'original_icon': None,
'original_name': 'HomeW Current Humidity',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1_16_24',
'unit_of_measurement': '%',
}),
'state': dict({
'attributes': dict({
'device_class': 'humidity',
'friendly_name': 'HomeW Current Humidity',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'entity_id': 'sensor.homew_current_humidity',
'state': '34',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.homew_current_temperature',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'HomeW Current Temperature',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1_16_19',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'state': dict({
'attributes': dict({
'device_class': 'temperature',
'friendly_name': 'HomeW Current Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'entity_id': 'sensor.homew_current_temperature',
'state': '21.8',
}),
}),
]),
}),
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,
'manufacturer': 'ecobee Inc.',
'model': 'REMOTE SENSOR',
'name': 'Kitchen',
'name_by_user': None,
'suggested_area': None,
'sw_version': '1.0.0',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.kitchen',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.MOTION: 'motion'>,
'original_icon': None,
'original_name': 'Kitchen',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_2_56',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'device_class': 'motion',
'friendly_name': 'Kitchen',
}),
'entity_id': 'binary_sensor.kitchen',
'state': 'off',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.kitchen_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Kitchen Identify',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_2_1_2053',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'Kitchen Identify',
}),
'entity_id': 'button.kitchen_identify',
'state': 'unknown',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.kitchen_temperature',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Kitchen Temperature',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_2_55',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'state': dict({
'attributes': dict({
'device_class': 'temperature',
'friendly_name': 'Kitchen Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'entity_id': 'sensor.kitchen_temperature',
'state': '21.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:3',
]),
]),
'is_new': False,
'manufacturer': 'ecobee Inc.',
'model': 'REMOTE SENSOR',
'name': 'Porch',
'name_by_user': None,
'suggested_area': None,
'sw_version': '1.0.0',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.porch',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.MOTION: 'motion'>,
'original_icon': None,
'original_name': 'Porch',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_3_56',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'device_class': 'motion',
'friendly_name': 'Porch',
}),
'entity_id': 'binary_sensor.porch',
'state': 'off',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.porch_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Porch Identify',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_3_1_3077',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'Porch Identify',
}),
'entity_id': 'button.porch_identify',
'state': 'unknown',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.porch_temperature',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Porch Temperature',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_3_55',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'state': dict({
'attributes': dict({
'device_class': 'temperature',
'friendly_name': 'Porch Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'entity_id': 'sensor.porch_temperature',
'state': '21',
}),
}),
]),
}),
])
# ---
# name: test_snapshots[ecobee_501]
list([
dict({
@ -6117,6 +6767,185 @@
}),
])
# ---
# name: test_snapshots[home_assistant_bridge_fan_one_removed]
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,
'manufacturer': 'Home Assistant',
'model': 'Bridge',
'name': 'Home Assistant Bridge',
'name_by_user': None,
'suggested_area': None,
'sw_version': '0.104.0.dev0',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.home_assistant_bridge_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Home Assistant Bridge Identify',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1_1_2',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'Home Assistant Bridge Identify',
}),
'entity_id': 'button.home_assistant_bridge_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:1256851357',
]),
]),
'is_new': False,
'manufacturer': 'Home Assistant',
'model': 'Fan',
'name': 'Living Room Fan',
'name_by_user': None,
'suggested_area': None,
'sw_version': '0.104.0.dev0',
}),
'entities': list([
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': None,
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'button',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'button.living_room_fan_identify',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Living Room Fan Identify',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1256851357_1_2',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'friendly_name': 'Living Room Fan Identify',
}),
'entity_id': 'button.living_room_fan_identify',
'state': 'unknown',
}),
}),
dict({
'entry': dict({
'aliases': list([
]),
'area_id': None,
'capabilities': dict({
'preset_modes': None,
}),
'config_entry_id': 'TestData',
'device_class': None,
'disabled_by': None,
'domain': 'fan',
'entity_category': None,
'entity_id': 'fan.living_room_fan',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Living Room Fan',
'platform': 'homekit_controller',
'previous_unique_id': None,
'supported_features': <FanEntityFeature: 7>,
'translation_key': None,
'unique_id': '00:00:00:00:00:00_1256851357_8',
'unit_of_measurement': None,
}),
'state': dict({
'attributes': dict({
'direction': 'forward',
'friendly_name': 'Living Room Fan',
'oscillating': False,
'percentage': 0,
'percentage_step': 1.0,
'preset_mode': None,
'preset_modes': None,
'supported_features': <FanEntityFeature: 7>,
}),
'entity_id': 'fan.living_room_fan',
'state': 'off',
}),
}),
]),
}),
])
# ---
# name: test_snapshots[homespan_daikin_bridge]
list([
dict({

View file

@ -252,3 +252,91 @@ async def test_ecobee3_add_sensors_at_runtime(hass: HomeAssistant) -> None:
occ3 = entity_registry.async_get("binary_sensor.basement")
assert occ3.unique_id == "00:00:00:00:00:00_4_56"
async def test_ecobee3_remove_sensors_at_runtime(hass: HomeAssistant) -> None:
"""Test that sensors are automatically removed."""
entity_registry = er.async_get(hass)
# Set up a base Ecobee 3 with additional sensors.
accessories = await setup_accessories_from_file(hass, "ecobee3.json")
await setup_test_accessories(hass, accessories)
climate = entity_registry.async_get("climate.homew")
assert climate.unique_id == "00:00:00:00:00:00_1_16"
occ1 = entity_registry.async_get("binary_sensor.kitchen")
assert occ1.unique_id == "00:00:00:00:00:00_2_56"
occ2 = entity_registry.async_get("binary_sensor.porch")
assert occ2.unique_id == "00:00:00:00:00:00_3_56"
occ3 = entity_registry.async_get("binary_sensor.basement")
assert occ3.unique_id == "00:00:00:00:00:00_4_56"
assert hass.states.get("binary_sensor.kitchen") is not None
assert hass.states.get("binary_sensor.porch") is not None
assert hass.states.get("binary_sensor.basement") is not None
# Now remove 3 new sensors at runtime - sensors should disappear and climate
# shouldn't be duplicated.
accessories = await setup_accessories_from_file(hass, "ecobee3_no_sensors.json")
await device_config_changed(hass, accessories)
assert hass.states.get("binary_sensor.kitchen") is None
assert hass.states.get("binary_sensor.porch") is None
assert hass.states.get("binary_sensor.basement") is None
# Now add the sensors back
accessories = await setup_accessories_from_file(hass, "ecobee3.json")
await device_config_changed(hass, accessories)
occ1 = entity_registry.async_get("binary_sensor.kitchen")
assert occ1.unique_id == "00:00:00:00:00:00_2_56"
occ2 = entity_registry.async_get("binary_sensor.porch")
assert occ2.unique_id == "00:00:00:00:00:00_3_56"
occ3 = entity_registry.async_get("binary_sensor.basement")
assert occ3.unique_id == "00:00:00:00:00:00_4_56"
# Currently it is not possible to add the entities back once
# they are removed because _add_new_entities has a guard to prevent
# the same entity from being added twice.
async def test_ecobee3_services_and_chars_removed(
hass: HomeAssistant,
) -> None:
"""Test handling removal of some services and chars."""
entity_registry = er.async_get(hass)
# Set up a base Ecobee 3 with additional sensors.
accessories = await setup_accessories_from_file(hass, "ecobee3.json")
await setup_test_accessories(hass, accessories)
climate = entity_registry.async_get("climate.homew")
assert climate.unique_id == "00:00:00:00:00:00_1_16"
assert hass.states.get("sensor.basement_temperature") is not None
assert hass.states.get("sensor.kitchen_temperature") is not None
assert hass.states.get("sensor.porch_temperature") is not None
assert hass.states.get("select.homew_current_mode") is not None
assert hass.states.get("button.homew_clear_hold") is not None
# Reconfigure with some of the chars removed and the basement temperature sensor
accessories = await setup_accessories_from_file(
hass, "ecobee3_service_removed.json"
)
await device_config_changed(hass, accessories)
# Make sure the climate entity is still there
assert hass.states.get("climate.homew") is not None
# Make sure the basement temperature sensor is gone
assert hass.states.get("sensor.basement_temperature") is None
# Make sure the current mode select and clear hold button are gone
assert hass.states.get("select.homew_current_mode") is None
assert hass.states.get("button.homew_clear_hold") is None

View file

@ -53,3 +53,90 @@ async def test_fan_add_feature_at_runtime(hass: HomeAssistant) -> None:
)
fan_state = hass.states.get("fan.ceiling_fan")
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
async def test_fan_remove_feature_at_runtime(hass: HomeAssistant) -> None:
"""Test that features can be removed at runtime."""
entity_registry = er.async_get(hass)
# Set up a basic fan that does not support oscillation
accessories = await setup_accessories_from_file(
hass, "home_assistant_bridge_fan.json"
)
await setup_test_accessories(hass, accessories)
fan = entity_registry.async_get("fan.living_room_fan")
assert fan.unique_id == "00:00:00:00:00:00_1256851357_8"
fan_state = hass.states.get("fan.living_room_fan")
assert (
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
is FanEntityFeature.SET_SPEED
| FanEntityFeature.DIRECTION
| FanEntityFeature.OSCILLATE
)
fan = entity_registry.async_get("fan.ceiling_fan")
assert fan.unique_id == "00:00:00:00:00:00_766313939_8"
fan_state = hass.states.get("fan.ceiling_fan")
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
# Now change the config to add oscillation
accessories = await setup_accessories_from_file(
hass, "home_assistant_bridge_basic_fan.json"
)
await device_config_changed(hass, accessories)
fan_state = hass.states.get("fan.living_room_fan")
assert (
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
is FanEntityFeature.SET_SPEED | FanEntityFeature.DIRECTION
)
fan_state = hass.states.get("fan.ceiling_fan")
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
async def test_bridge_with_two_fans_one_removed(hass: HomeAssistant) -> None:
"""Test a bridge with two fans and one gets removed."""
entity_registry = er.async_get(hass)
# Set up a basic fan that does not support oscillation
accessories = await setup_accessories_from_file(
hass, "home_assistant_bridge_fan.json"
)
await setup_test_accessories(hass, accessories)
fan = entity_registry.async_get("fan.living_room_fan")
assert fan.unique_id == "00:00:00:00:00:00_1256851357_8"
fan_state = hass.states.get("fan.living_room_fan")
assert (
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
is FanEntityFeature.SET_SPEED
| FanEntityFeature.DIRECTION
| FanEntityFeature.OSCILLATE
)
fan = entity_registry.async_get("fan.ceiling_fan")
assert fan.unique_id == "00:00:00:00:00:00_766313939_8"
fan_state = hass.states.get("fan.ceiling_fan")
assert fan_state.attributes[ATTR_SUPPORTED_FEATURES] is FanEntityFeature.SET_SPEED
# Now change the config to remove one of the fans
accessories = await setup_accessories_from_file(
hass, "home_assistant_bridge_fan_one_removed.json"
)
await device_config_changed(hass, accessories)
# Verify the first fan is still there
fan_state = hass.states.get("fan.living_room_fan")
assert (
fan_state.attributes[ATTR_SUPPORTED_FEATURES]
is FanEntityFeature.SET_SPEED
| FanEntityFeature.DIRECTION
| FanEntityFeature.OSCILLATE
)
# The second fan should have been removed
assert not hass.states.get("fan.ceiling_fan")