From d829a2045af3f0251eac20ec55aa5bc408ad5c76 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Wed, 8 Feb 2023 01:10:51 +0000 Subject: [PATCH] Fix incorrect unique_id for BLE HomeKit devices (#87550) --- .../homekit_controller/config_flow.py | 6 ++--- .../homekit_controller/connection.py | 17 +++++++++++++ .../homekit_controller/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../homekit_controller/test_config_flow.py | 2 +- .../homekit_controller/test_connection.py | 24 +++++++++++++++++++ 7 files changed, 48 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/homekit_controller/config_flow.py b/homeassistant/components/homekit_controller/config_flow.py index 9d77a0c37fa..f450c38527a 100644 --- a/homeassistant/components/homekit_controller/config_flow.py +++ b/homeassistant/components/homekit_controller/config_flow.py @@ -375,9 +375,6 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): # pylint: disable-next=import-outside-toplevel from aiohomekit.controller.ble.manufacturer_data import HomeKitAdvertisement - await self.async_set_unique_id(discovery_info.address) - self._abort_if_unique_id_configured() - mfr_data = discovery_info.manufacturer_data try: @@ -387,6 +384,9 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): except ValueError: return self.async_abort(reason="ignored_model") + await self.async_set_unique_id(normalize_hkid(device.id)) + self._abort_if_unique_id_configured() + if not (device.status_flags & StatusFlags.UNPAIRED): return self.async_abort(reason="already_paired") diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 37188487746..9a23344f972 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -27,6 +27,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.event import async_track_time_interval +from .config_flow import normalize_hkid from .const import ( CHARACTERISTIC_PLATFORMS, CONTROLLER, @@ -463,6 +464,20 @@ class HKDevice: device_registry.async_update_device(device.id, new_identifiers=identifiers) + @callback + def async_migrate_ble_unique_id(self) -> None: + """Config entries from step_bluetooth used incorrect identifier for unique_id.""" + unique_id = normalize_hkid(self.unique_id) + if unique_id != self.config_entry.unique_id: + _LOGGER.debug( + "Fixing incorrect unique_id: %s -> %s", + self.config_entry.unique_id, + unique_id, + ) + self.hass.config_entries.async_update_entry( + self.config_entry, unique_id=unique_id + ) + @callback def async_create_devices(self) -> None: """Build device registry entries for all accessories paired with the bridge. @@ -551,6 +566,8 @@ class HKDevice: # Remove any of the legacy serial numbers from the device registry self.async_remove_legacy_device_serial_numbers() + self.async_migrate_ble_unique_id() + self.async_create_devices() # Load any triggers for this config entry diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index f0a8cb74efe..f7e3957d0e1 100644 --- a/homeassistant/components/homekit_controller/manifest.json +++ b/homeassistant/components/homekit_controller/manifest.json @@ -3,7 +3,7 @@ "name": "HomeKit Controller", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/homekit_controller", - "requirements": ["aiohomekit==2.4.6"], + "requirements": ["aiohomekit==2.5.0"], "zeroconf": ["_hap._tcp.local.", "_hap._udp.local."], "bluetooth": [{ "manufacturer_id": 76, "manufacturer_data_start": [6] }], "dependencies": ["bluetooth_adapters", "zeroconf"], diff --git a/requirements_all.txt b/requirements_all.txt index cf35eeeb882..c8a1cebc729 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -174,7 +174,7 @@ aioguardian==2022.07.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==2.4.6 +aiohomekit==2.5.0 # homeassistant.components.emulated_hue # homeassistant.components.http diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 93dfb64c3be..0b1aa946b7a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -158,7 +158,7 @@ aioguardian==2022.07.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==2.4.6 +aiohomekit==2.5.0 # homeassistant.components.emulated_hue # homeassistant.components.http diff --git a/tests/components/homekit_controller/test_config_flow.py b/tests/components/homekit_controller/test_config_flow.py index 9aab999526d..54ab0eef165 100644 --- a/tests/components/homekit_controller/test_config_flow.py +++ b/tests/components/homekit_controller/test_config_flow.py @@ -1134,7 +1134,7 @@ async def test_bluetooth_valid_device_discovery_unpaired(hass, controller): assert get_flow_context(hass, result) == { "source": config_entries.SOURCE_BLUETOOTH, - "unique_id": "AA:BB:CC:DD:EE:FF", + "unique_id": "00:00:00:00:00:00", "title_placeholders": {"name": "TestDevice", "category": "Other"}, } diff --git a/tests/components/homekit_controller/test_connection.py b/tests/components/homekit_controller/test_connection.py index d21aedd6cb8..80b2d091e06 100644 --- a/tests/components/homekit_controller/test_connection.py +++ b/tests/components/homekit_controller/test_connection.py @@ -152,3 +152,27 @@ async def test_migrate_device_id_no_serial( assert device.identifiers == variant.after assert device.manufacturer == variant.manufacturer + + +async def test_migrate_ble_unique_id(hass: HomeAssistant): + """Test that a config entry with incorrect unique_id is repaired.""" + accessories = await setup_accessories_from_file(hass, "anker_eufycam.json") + + fake_controller = await setup_platform(hass) + await fake_controller.add_paired_device(accessories, "02:03:EF:02:03:EF") + config_entry = MockConfigEntry( + version=1, + domain="homekit_controller", + entry_id="TestData", + data={"AccessoryPairingID": "02:03:EF:02:03:EF"}, + title="test", + unique_id="01:02:AB:01:02:AB", + ) + config_entry.add_to_hass(hass) + + assert config_entry.unique_id == "01:02:AB:01:02:AB" + + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.unique_id == "02:03:ef:02:03:ef"