diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index 404b2f54ab0..c14cfbb8a7e 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -189,11 +189,16 @@ class CharacteristicEntity(HomeKitEntity): the service entity. """ + def __init__(self, accessory, devinfo, char): + """Initialise a generic single characteristic HomeKit entity.""" + self._char = char + super().__init__(accessory, devinfo) + @property def unique_id(self) -> str: """Return the ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) - return f"homekit-{serial}-aid:{self._aid}-sid:{self._iid}-cid:{self._iid}" + return f"homekit-{serial}-aid:{self._aid}-sid:{self._char.service.iid}-cid:{self._char.iid}" async def async_setup_entry(hass, entry): diff --git a/homeassistant/components/homekit_controller/number.py b/homeassistant/components/homekit_controller/number.py index 2e0193fa080..73d8cd6adbd 100644 --- a/homeassistant/components/homekit_controller/number.py +++ b/homeassistant/components/homekit_controller/number.py @@ -53,9 +53,8 @@ class HomeKitNumber(CharacteristicEntity, NumberEntity): self._device_class = device_class self._icon = icon self._name = name - self._char = char - super().__init__(conn, info) + super().__init__(conn, info, char) def get_characteristic_types(self): """Define the homekit characteristics the entity is tracking.""" diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index f34fc3f0a9b..6bf8a7fc084 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -254,9 +254,8 @@ class SimpleSensor(CharacteristicEntity, SensorEntity): self._unit = unit self._icon = icon self._name = name - self._char = char - super().__init__(conn, info) + super().__init__(conn, info, char) def get_characteristic_types(self): """Define the homekit characteristics the entity is tracking.""" diff --git a/tests/components/homekit_controller/specific_devices/test_ecobee3.py b/tests/components/homekit_controller/specific_devices/test_ecobee3.py index 96dbd3b0718..94f3aabc12a 100644 --- a/tests/components/homekit_controller/specific_devices/test_ecobee3.py +++ b/tests/components/homekit_controller/specific_devices/test_ecobee3.py @@ -60,7 +60,7 @@ async def test_ecobee3_setup(hass): assert climate_state.attributes["max_humidity"] == 50 climate_sensor = entity_registry.async_get("sensor.homew_current_temperature") - assert climate_sensor.unique_id == "homekit-123456789012-aid:1-sid:16-cid:16" + assert climate_sensor.unique_id == "homekit-123456789012-aid:1-sid:16-cid:19" occ1 = entity_registry.async_get("binary_sensor.kitchen") assert occ1.unique_id == "homekit-AB1C-56" diff --git a/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py b/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py index db72aad7541..6302013223d 100644 --- a/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py +++ b/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py @@ -37,7 +37,7 @@ async def test_koogeek_p1eu_setup(hass): # Assert the power sensor is detected entry = entity_registry.async_get("sensor.koogeek_p1_a00aa0_real_time_energy") - assert entry.unique_id == "homekit-EUCP03190xxxxx48-aid:1-sid:21-cid:21" + assert entry.unique_id == "homekit-EUCP03190xxxxx48-aid:1-sid:21-cid:22" helper = Helper( hass, diff --git a/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py b/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py index 00057822071..1d46b633153 100644 --- a/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py +++ b/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py @@ -45,7 +45,7 @@ async def test_koogeek_ls1_setup(hass): # Assert that the power sensor entity is correctly added to the entity registry entry = entity_registry.async_get("sensor.koogeek_sw2_187a91_real_time_energy") - assert entry.unique_id == "homekit-CNNT061751001372-aid:1-sid:14-cid:14" + assert entry.unique_id == "homekit-CNNT061751001372-aid:1-sid:14-cid:18" helper = Helper( hass, diff --git a/tests/components/homekit_controller/specific_devices/test_mysa_living.py b/tests/components/homekit_controller/specific_devices/test_mysa_living.py new file mode 100644 index 00000000000..ea1c1084071 --- /dev/null +++ b/tests/components/homekit_controller/specific_devices/test_mysa_living.py @@ -0,0 +1,91 @@ +"""Make sure that Mysa Living is enumerated properly.""" + +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from tests.components.homekit_controller.common import ( + Helper, + setup_accessories_from_file, + setup_test_accessories, +) + + +async def test_mysa_living_setup(hass): + """Test that the accessory can be correctly setup in HA.""" + accessories = await setup_accessories_from_file(hass, "mysa_living.json") + config_entry, pairing = await setup_test_accessories(hass, accessories) + + entity_registry = er.async_get(hass) + device_registry = dr.async_get(hass) + + # Check that the switch entity is handled correctly + + entry = entity_registry.async_get("sensor.mysa_85dda9_current_humidity") + assert entry.unique_id == "homekit-AAAAAAA000-aid:1-sid:20-cid:27" + + helper = Helper( + hass, + "sensor.mysa_85dda9_current_humidity", + pairing, + accessories[0], + config_entry, + ) + state = await helper.poll_and_get_state() + assert state.attributes["friendly_name"] == "Mysa-85dda9 - Current Humidity" + + device = device_registry.async_get(entry.device_id) + assert device.manufacturer == "Empowered Homes Inc." + assert device.name == "Mysa-85dda9" + assert device.model == "v1" + assert device.sw_version == "2.8.1" + assert device.via_device_id is None + + # Assert the humidifier is detected + entry = entity_registry.async_get("sensor.mysa_85dda9_current_temperature") + assert entry.unique_id == "homekit-AAAAAAA000-aid:1-sid:20-cid:25" + + helper = Helper( + hass, + "sensor.mysa_85dda9_current_temperature", + pairing, + accessories[0], + config_entry, + ) + state = await helper.poll_and_get_state() + assert state.attributes["friendly_name"] == "Mysa-85dda9 - Current Temperature" + + # The sensor should be part of the same device + assert entry.device_id == device.id + + # Assert the light is detected + entry = entity_registry.async_get("light.mysa_85dda9") + assert entry.unique_id == "homekit-AAAAAAA000-40" + + helper = Helper( + hass, + "light.mysa_85dda9", + pairing, + accessories[0], + config_entry, + ) + state = await helper.poll_and_get_state() + assert state.attributes["friendly_name"] == "Mysa-85dda9" + + # The light should be part of the same device + assert entry.device_id == device.id + + # Assert the climate entity is detected + entry = entity_registry.async_get("climate.mysa_85dda9") + assert entry.unique_id == "homekit-AAAAAAA000-20" + + helper = Helper( + hass, + "climate.mysa_85dda9", + pairing, + accessories[0], + config_entry, + ) + state = await helper.poll_and_get_state() + assert state.attributes["friendly_name"] == "Mysa-85dda9" + + # The light should be part of the same device + assert entry.device_id == device.id diff --git a/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py b/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py index e2762b5c153..6968c62257f 100644 --- a/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py +++ b/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py @@ -20,7 +20,7 @@ async def test_vocolinc_flowerbud_setup(hass): # Check that the switch entity is handled correctly entry = entity_registry.async_get("number.vocolinc_flowerbud_0d324b") - assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:30" + assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:38" helper = Helper( hass, "number.vocolinc_flowerbud_0d324b", pairing, accessories[0], config_entry @@ -73,7 +73,7 @@ async def test_vocolinc_flowerbud_setup(hass): entry = entity_registry.async_get( "sensor.vocolinc_flowerbud_0d324b_current_humidity" ) - assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:30" + assert entry.unique_id == "homekit-AM01121849000327-aid:1-sid:30-cid:33" helper = Helper( hass, diff --git a/tests/fixtures/homekit_controller/mysa_living.json b/tests/fixtures/homekit_controller/mysa_living.json new file mode 100644 index 00000000000..da26b654fe5 --- /dev/null +++ b/tests/fixtures/homekit_controller/mysa_living.json @@ -0,0 +1,250 @@ +[ + { + "aid": 1, + "primary": true, + "services": [ + { + "type": "0000004A-0000-1000-8000-0026BB765291", + "primary": true, + "iid": 20, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "Thermostat", + "perms": [ + "pr" + ], + "iid": 24 + }, + { + "type": "00000010-0000-1000-8000-0026BB765291", + "format": "float", + "minValue": 0, + "maxValue": 100, + "stepValue": 1, + "value": 40, + "iid": 27, + "unit": "percentage", + "perms": [ + "pr", + "ev" + ] + }, + { + "type": "0000000F-0000-1000-8000-0026BB765291", + "value": 0, + "minValue": 0, + "maxValue": 2, + "stepValue": 1, + "format": "uint8", + "perms": [ + "pr", + "ev" + ], + "iid": 21 + }, + { + "type": "00000033-0000-1000-8000-0026BB765291", + "value": 0, + "minValue": 0, + "maxValue": 3, + "stepValue": 1, + "format": "uint8", + "perms": [ + "pr", + "pw", + "ev" + ], + "iid": 22 + }, + { + "type": "00000011-0000-1000-8000-0026BB765291", + "value": 24.1, + "minValue": 0, + "maxValue": 100, + "stepValue": 0.1, + "unit": "celsius", + "format": "float", + "perms": [ + "pr", + "ev" + ], + "iid": 25 + }, + { + "type": "00000035-0000-1000-8000-0026BB765291", + "value": 22, + "minValue": 5, + "maxValue": 30, + "stepValue": 0.1, + "unit": "celsius", + "format": "float", + "perms": [ + "pr", + "pw", + "ev" + ], + "iid": 23 + }, + { + "type": "00000036-0000-1000-8000-0026BB765291", + "format": "uint8", + "minValue": 0, + "maxValue": 1, + "stepValue": 1, + "value": 0, + "iid": 26, + "perms": [ + "pr", + "pw", + "ev" + ] + } + ] + }, + { + "type": "0000003E-0000-1000-8000-0026BB765291", + "iid": 1, + "characteristics": [ + { + "type": "00000014-0000-1000-8000-0026BB765291", + "perms": [ + "pw" + ], + "iid": 2, + "format": "bool" + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "format": "string", + "value": "Empowered Homes Inc.", + "perms": [ + "pr" + ], + "iid": 3 + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "format": "string", + "value": "v1", + "perms": [ + "pr" + ], + "iid": 4 + }, + { + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "Mysa-85dda9", + "perms": [ + "pr" + ], + "iid": 5 + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "format": "string", + "value": "AAAAAAA000", + "perms": [ + "pr" + ], + "iid": 6 + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "format": "string", + "value": "2.8.1", + "perms": [ + "pr" + ], + "iid": 7 + }, + { + "hidden": true, + "type": "22280E2C-9B79-43BD-8370-5A8F67777B29", + "format": "string", + "value": "b4e62d85dda9", + "perms": [ + "pr" + ], + "iid": 8 + } + ] + }, + { + "type": "000000A2-0000-1000-8000-0026BB765291", + "iid": 10, + "characteristics": [ + { + "type": "00000037-0000-1000-8000-0026BB765291", + "format": "string", + "value": "1.1.0", + "perms": [ + "pr" + ], + "iid": 11 + } + ] + }, + { + "type": "00000043-0000-1000-8000-0026BB765291", + "iid": 40, + "characteristics": [ + { + "type": "00000025-0000-1000-8000-0026BB765291", + "format": "bool", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "iid": 42 + }, + { + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "Display", + "perms": [ + "pr" + ], + "iid": 41 + }, + { + "type": "00000008-0000-1000-8000-0026BB765291", + "format": "int", + "minValue": 0, + "maxValue": 100, + "stepValue": 1, + "value": 0, + "iid": 43, + "unit": "percentage", + "perms": [ + "pr", + "pw", + "ev" + ] + } + ] + }, + { + "type": "3354EC82-AF38-4755-B4A4-4DB8E418F555", + "iid": 50, + "characteristics": [ + { + "hidden": true, + "type": "E71D8348-BB33-4C34-8C50-A64B1136EDD2", + "format": "bool", + "value": 0, + "perms": [ + "pr", + "pw" + ], + "iid": 51 + } + ] + } + ] + } +] \ No newline at end of file