diff --git a/homeassistant/components/homekit_controller/alarm_control_panel.py b/homeassistant/components/homekit_controller/alarm_control_panel.py index 204fa1bb3f8..a466d15db58 100644 --- a/homeassistant/components/homekit_controller/alarm_control_panel.py +++ b/homeassistant/components/homekit_controller/alarm_control_panel.py @@ -18,11 +18,13 @@ from homeassistant.const import ( STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, + Platform, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity ICON = "mdi:security" @@ -49,15 +51,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit alarm control panel.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if service.type != ServicesTypes.SECURITY_SYSTEM: return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([HomeKitAlarmControlPanelEntity(conn, info)], True) + entity = HomeKitAlarmControlPanelEntity(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.ALARM_CONTROL_PANEL + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/binary_sensor.py b/homeassistant/components/homekit_controller/binary_sensor.py index c980e31b50c..8115023fa52 100644 --- a/homeassistant/components/homekit_controller/binary_sensor.py +++ b/homeassistant/components/homekit_controller/binary_sensor.py @@ -9,6 +9,7 @@ from homeassistant.components.binary_sensor import ( BinarySensorEntity, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -158,7 +159,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit lighting.""" - hkid = config_entry.data["AccessoryPairingID"] + hkid: str = config_entry.data["AccessoryPairingID"] conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback @@ -174,7 +175,11 @@ async def async_setup_entry( ): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)], True) + entity: HomeKitEntity = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.BINARY_SENSOR + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/button.py b/homeassistant/components/homekit_controller/button.py index d5a8bc733ad..4ce2b425a5e 100644 --- a/homeassistant/components/homekit_controller/button.py +++ b/homeassistant/components/homekit_controller/button.py @@ -16,6 +16,7 @@ from homeassistant.components.button import ( ButtonEntityDescription, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -63,12 +64,12 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit buttons.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_characteristic(char: Characteristic) -> bool: - entities = [] + entities: list[HomeKitButton | HomeKitEcobeeClearHoldButton] = [] info = {"aid": char.service.accessory.aid, "iid": char.service.iid} if description := BUTTON_ENTITIES.get(char.type): @@ -78,6 +79,11 @@ async def async_setup_entry( else: return False + for entity in entities: + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.BUTTON + ) + async_add_entities(entities, True) return True diff --git a/homeassistant/components/homekit_controller/camera.py b/homeassistant/components/homekit_controller/camera.py index 510c0c2f522..35a4b089641 100644 --- a/homeassistant/components/homekit_controller/camera.py +++ b/homeassistant/components/homekit_controller/camera.py @@ -6,10 +6,12 @@ from aiohomekit.model.services import ServicesTypes from homeassistant.components.camera import Camera from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import AccessoryEntity @@ -39,8 +41,8 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit sensors.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_accessory(accessory: Accessory) -> bool: @@ -51,7 +53,11 @@ async def async_setup_entry( return False info = {"aid": accessory.aid, "iid": stream_mgmt.iid} - async_add_entities([HomeKitCamera(conn, info)], True) + entity = HomeKitCamera(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.CAMERA + ) + async_add_entities([entity]) return True conn.add_accessory_factory(async_add_accessory) diff --git a/homeassistant/components/homekit_controller/climate.py b/homeassistant/components/homekit_controller/climate.py index 41788eb4cb2..de42243a6bb 100644 --- a/homeassistant/components/homekit_controller/climate.py +++ b/homeassistant/components/homekit_controller/climate.py @@ -32,11 +32,12 @@ from homeassistant.components.climate import ( HVACMode, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity _LOGGER = logging.getLogger(__name__) @@ -92,15 +93,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit climate.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if not (entity_class := ENTITY_TYPES.get(service.type)): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)], True) + entity: HomeKitEntity = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.CLIMATE + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 05a0a589bf1..e2ab68f8c63 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -21,7 +21,7 @@ from aiohomekit.model.services import Service from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_VIA_DEVICE from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.event import async_track_time_interval @@ -79,9 +79,7 @@ class HKDevice: connection: Controller = hass.data[CONTROLLER] - self.pairing = connection.load_pairing( - self.pairing_data["AccessoryPairingID"], self.pairing_data - ) + self.pairing = connection.load_pairing(self.unique_id, self.pairing_data) # A list of callbacks that turn HK accessories into entities self.accessory_factories: list[AddAccessoryCb] = [] @@ -253,7 +251,12 @@ class HKDevice: identifiers.add((IDENTIFIER_SERIAL_NUMBER, accessory.serial_number)) device_info = DeviceInfo( - identifiers=identifiers, + identifiers={ + ( + IDENTIFIER_ACCESSORY_ID, + f"{self.unique_id}:aid:{accessory.aid}", + ) + }, name=accessory.name, manufacturer=accessory.manufacturer, model=accessory.model, @@ -317,27 +320,87 @@ class HKDevice: self.unique_id, accessory.aid, ) + device_registry.async_update_device( + device.id, + new_identifiers={ + ( + IDENTIFIER_ACCESSORY_ID, + f"{self.unique_id}:aid:{accessory.aid}", + ) + }, + ) - new_identifiers = { + @callback + def async_migrate_unique_id( + self, old_unique_id: str, new_unique_id: str, platform: str + ) -> None: + """Migrate legacy unique IDs to new format.""" + _LOGGER.debug( + "Checking if unique ID %s on %s needs to be migrated", + old_unique_id, + platform, + ) + entity_registry = er.async_get(self.hass) + # async_get_entity_id wants the "homekit_controller" domain + # in the platform field and the actual platform in the domain + # field for historical reasons since everything used to be + # PLATFORM.INTEGRATION instead of INTEGRATION.PLATFORM + if ( + entity_id := entity_registry.async_get_entity_id( + platform, DOMAIN, old_unique_id + ) + ) is None: + _LOGGER.debug("Unique ID %s does not need to be migrated", old_unique_id) + return + if new_entity_id := entity_registry.async_get_entity_id( + platform, DOMAIN, new_unique_id + ): + _LOGGER.debug( + "Unique ID %s is already in use by %s (system may have been downgraded)", + new_unique_id, + new_entity_id, + ) + return + _LOGGER.debug( + "Migrating unique ID for entity %s (%s -> %s)", + entity_id, + old_unique_id, + new_unique_id, + ) + entity_registry.async_update_entity(entity_id, new_unique_id=new_unique_id) + + @callback + def async_remove_legacy_device_serial_numbers(self) -> None: + """Migrate remove legacy serial numbers from devices. + + We no longer use serial numbers as device identifiers + since they are not reliable, and the HomeKit spec + does not require them to be stable. + """ + _LOGGER.debug( + "Removing legacy serial numbers from device registry entries for pairing %s", + self.unique_id, + ) + + device_registry = dr.async_get(self.hass) + for accessory in self.entity_map.accessories: + identifiers = { ( IDENTIFIER_ACCESSORY_ID, f"{self.unique_id}:aid:{accessory.aid}", ) } - - if not self.unreliable_serial_numbers: - new_identifiers.add((IDENTIFIER_SERIAL_NUMBER, accessory.serial_number)) - else: - _LOGGER.debug( - "Not migrating serial number identifier for %s:aid:%s (it is wrong, not unique or unreliable)", - self.unique_id, - accessory.aid, - ) - - device_registry.async_update_device( - device.id, new_identifiers=new_identifiers + legacy_serial_identifier = ( + IDENTIFIER_SERIAL_NUMBER, + accessory.serial_number, ) + device = device_registry.async_get_device(identifiers=identifiers) + if not device or legacy_serial_identifier not in device.identifiers: + continue + + device_registry.async_update_device(device.id, new_identifiers=identifiers) + @callback def async_create_devices(self) -> None: """ @@ -416,6 +479,9 @@ class HKDevice: # Migrate to new device ids self.async_migrate_devices() + # Remove any of the legacy serial numbers from the device registry + self.async_remove_legacy_device_serial_numbers() + self.async_create_devices() # Load any triggers for this config entry diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index 6cbc623596e..d4feeccc77a 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -14,11 +14,18 @@ from homeassistant.components.cover import ( CoverEntityFeature, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING +from homeassistant.const import ( + STATE_CLOSED, + STATE_CLOSING, + STATE_OPEN, + STATE_OPENING, + Platform, +) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity STATE_STOPPED = "stopped" @@ -42,15 +49,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit covers.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if not (entity_class := ENTITY_TYPES.get(service.type)): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)], True) + entity: HomeKitEntity = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.COVER + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/entity.py b/homeassistant/components/homekit_controller/entity.py index ad99e65f2d8..a4e1b2b41b3 100644 --- a/homeassistant/components/homekit_controller/entity.py +++ b/homeassistant/components/homekit_controller/entity.py @@ -121,8 +121,8 @@ class HomeKitEntity(Entity): self._char_name = char.service.value(CharacteristicsTypes.NAME) @property - def unique_id(self) -> str: - """Return the ID of this device.""" + def old_unique_id(self) -> str: + """Return the OLD ID of this device.""" info = self.accessory_info serial = info.value(CharacteristicsTypes.SERIAL_NUMBER) if valid_serial_number(serial): @@ -130,6 +130,11 @@ class HomeKitEntity(Entity): # Some accessories do not have a serial number return f"homekit-{self._accessory.unique_id}-{self._aid}-{self._iid}" + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + return f"{self._accessory.unique_id}_{self._aid}_{self._iid}" + @property def default_name(self) -> str | None: """Return the default name of the device.""" @@ -175,11 +180,16 @@ class AccessoryEntity(HomeKitEntity): """A HomeKit entity that is related to an entire accessory rather than a specific service or characteristic.""" @property - def unique_id(self) -> str: - """Return the ID of this device.""" + def old_unique_id(self) -> str: + """Return the old ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) return f"homekit-{serial}-aid:{self._aid}" + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + return f"{self._accessory.unique_id}_{self._aid}" + class CharacteristicEntity(HomeKitEntity): """ @@ -197,7 +207,12 @@ class CharacteristicEntity(HomeKitEntity): super().__init__(accessory, devinfo) @property - def unique_id(self) -> str: - """Return the ID of this device.""" + def old_unique_id(self) -> str: + """Return the old ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) return f"homekit-{serial}-aid:{self._aid}-sid:{self._char.service.iid}-cid:{self._char.iid}" + + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + return f"{self._accessory.unique_id}_{self._aid}_{self._char.service.iid}_{self._char.iid}" diff --git a/homeassistant/components/homekit_controller/fan.py b/homeassistant/components/homekit_controller/fan.py index 03f4dade674..cdd9c3e803c 100644 --- a/homeassistant/components/homekit_controller/fan.py +++ b/homeassistant/components/homekit_controller/fan.py @@ -13,6 +13,7 @@ from homeassistant.components.fan import ( FanEntityFeature, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.percentage import ( @@ -21,6 +22,7 @@ from homeassistant.util.percentage import ( ) from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity # 0 is clockwise, 1 is counter-clockwise. The match to forward and reverse is so that @@ -193,15 +195,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit fans.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if not (entity_class := ENTITY_TYPES.get(service.type)): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)], True) + entity: HomeKitEntity = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.FAN + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/humidifier.py b/homeassistant/components/homekit_controller/humidifier.py index adc1b1c7935..e396b3c9c97 100644 --- a/homeassistant/components/homekit_controller/humidifier.py +++ b/homeassistant/components/homekit_controller/humidifier.py @@ -16,10 +16,12 @@ from homeassistant.components.humidifier import ( HumidifierEntityFeature, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity HK_MODE_TO_HA = { @@ -243,11 +245,16 @@ class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity): ) @property - def unique_id(self) -> str: - """Return the ID of this device.""" + def old_unique_id(self) -> str: + """Return the old ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) return f"homekit-{serial}-{self._iid}-{self.device_class}" + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + return f"{self._accessory.unique_id}_{self._iid}_{self.device_class}" + async def async_setup_entry( hass: HomeAssistant, @@ -255,8 +262,8 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit humidifer.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: @@ -265,7 +272,7 @@ async def async_setup_entry( info = {"aid": service.accessory.aid, "iid": service.iid} - entities: list[HumidifierEntity] = [] + entities: list[HomeKitHumidifier | HomeKitDehumidifier] = [] if service.has(CharacteristicsTypes.RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD): entities.append(HomeKitHumidifier(conn, info)) @@ -273,7 +280,12 @@ async def async_setup_entry( if service.has(CharacteristicsTypes.RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD): entities.append(HomeKitDehumidifier(conn, info)) - async_add_entities(entities, True) + for entity in entities: + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.HUMIDIFIER + ) + + async_add_entities(entities) return True diff --git a/homeassistant/components/homekit_controller/light.py b/homeassistant/components/homekit_controller/light.py index 010411c60d0..5bf810a89db 100644 --- a/homeassistant/components/homekit_controller/light.py +++ b/homeassistant/components/homekit_controller/light.py @@ -14,10 +14,12 @@ from homeassistant.components.light import ( LightEntity, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity @@ -27,15 +29,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit lightbulb.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if service.type != ServicesTypes.LIGHTBULB: return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([HomeKitLight(conn, info)], True) + entity = HomeKitLight(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.LIGHT + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/lock.py b/homeassistant/components/homekit_controller/lock.py index 8e8919ae4f8..a6c8a3672a3 100644 --- a/homeassistant/components/homekit_controller/lock.py +++ b/homeassistant/components/homekit_controller/lock.py @@ -13,11 +13,13 @@ from homeassistant.const import ( STATE_LOCKED, STATE_UNKNOWN, STATE_UNLOCKED, + Platform, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity CURRENT_STATE_MAP = { @@ -38,15 +40,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit lock.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if service.type != ServicesTypes.LOCK_MECHANISM: return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([HomeKitLock(conn, info)], True) + entity = HomeKitLock(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.LOCK + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/media_player.py b/homeassistant/components/homekit_controller/media_player.py index 5c791f165e2..4efa7dbce1c 100644 --- a/homeassistant/components/homekit_controller/media_player.py +++ b/homeassistant/components/homekit_controller/media_player.py @@ -19,10 +19,12 @@ from homeassistant.components.media_player import ( MediaPlayerState, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .entity import HomeKitEntity _LOGGER = logging.getLogger(__name__) @@ -41,15 +43,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit television.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if service.type != ServicesTypes.TELEVISION: return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([HomeKitTelevision(conn, info)], True) + entity = HomeKitTelevision(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.MEDIA_PLAYER + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) diff --git a/homeassistant/components/homekit_controller/number.py b/homeassistant/components/homekit_controller/number.py index 6347ccb2a56..a20ba83e80a 100644 --- a/homeassistant/components/homekit_controller/number.py +++ b/homeassistant/components/homekit_controller/number.py @@ -16,6 +16,7 @@ from homeassistant.components.number import ( NumberEntityDescription, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -59,12 +60,12 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit numbers.""" - hkid = config_entry.data["AccessoryPairingID"] + hkid: str = config_entry.data["AccessoryPairingID"] conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_characteristic(char: Characteristic) -> bool: - entities = [] + entities: list[HomeKitNumber] = [] info = {"aid": char.service.accessory.aid, "iid": char.service.iid} if description := NUMBER_ENTITIES.get(char.type): @@ -72,6 +73,11 @@ async def async_setup_entry( else: return False + for entity in entities: + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.NUMBER + ) + async_add_entities(entities, True) return True diff --git a/homeassistant/components/homekit_controller/select.py b/homeassistant/components/homekit_controller/select.py index a22f79d675b..ca5eaec4dc5 100644 --- a/homeassistant/components/homekit_controller/select.py +++ b/homeassistant/components/homekit_controller/select.py @@ -5,10 +5,12 @@ from aiohomekit.model.characteristics import Characteristic, CharacteristicsType from homeassistant.components.select import SelectEntity from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import KNOWN_DEVICES +from .connection import HKDevice from .const import DEVICE_CLASS_ECOBEE_MODE from .entity import CharacteristicEntity @@ -58,14 +60,18 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit select entities.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_characteristic(char: Characteristic) -> bool: if char.type == CharacteristicsTypes.VENDOR_ECOBEE_CURRENT_MODE: info = {"aid": char.service.accessory.aid, "iid": char.service.iid} - async_add_entities([EcobeeModeSelect(conn, info, char)]) + entity = EcobeeModeSelect(conn, info, char) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SELECT + ) + async_add_entities([entity]) return True return False diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index 564eb5ba9c6..e9f928dd571 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -30,6 +30,7 @@ from homeassistant.const import ( PRESSURE_HPA, SIGNAL_STRENGTH_DECIBELS_MILLIWATT, TEMP_CELSIUS, + Platform, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory @@ -556,11 +557,16 @@ class RSSISensor(HomeKitEntity, SensorEntity): return "Signal strength" @property - def unique_id(self) -> str: - """Return the ID of this device.""" + def old_unique_id(self) -> str: + """Return the old ID of this device.""" serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) return f"homekit-{serial}-rssi" + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + return f"{self._accessory.unique_id}_rssi" + @property def native_value(self) -> int | None: """Return the current rssi value.""" @@ -587,7 +593,11 @@ async def async_setup_entry( ) and not service.has(required_char): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)]) + entity: HomeKitSensor = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SENSOR + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) @@ -599,7 +609,11 @@ async def async_setup_entry( if description.probe and not description.probe(char): return False info = {"aid": char.service.accessory.aid, "iid": char.service.iid} - async_add_entities([SimpleSensor(conn, info, char, description)]) + entity = SimpleSensor(conn, info, char, description) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SENSOR + ) + async_add_entities([entity]) return True @@ -614,7 +628,11 @@ async def async_setup_entry( service_type=ServicesTypes.ACCESSORY_INFORMATION ) info = {"aid": accessory.aid, "iid": accessory_info.iid} - async_add_entities([RSSISensor(conn, info)]) + entity = RSSISensor(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SENSOR + ) + async_add_entities([entity]) return True conn.add_accessory_factory(async_add_accessory) diff --git a/homeassistant/components/homekit_controller/switch.py b/homeassistant/components/homekit_controller/switch.py index c537233de7e..d1e06e585b0 100644 --- a/homeassistant/components/homekit_controller/switch.py +++ b/homeassistant/components/homekit_controller/switch.py @@ -14,6 +14,7 @@ from aiohomekit.model.services import Service, ServicesTypes from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -182,7 +183,7 @@ class DeclarativeCharacteristicSwitch(CharacteristicEntity, SwitchEntity): ) -ENTITY_TYPES = { +ENTITY_TYPES: dict[str, type[HomeKitSwitch] | type[HomeKitValve]] = { ServicesTypes.SWITCH: HomeKitSwitch, ServicesTypes.OUTLET: HomeKitSwitch, ServicesTypes.VALVE: HomeKitValve, @@ -195,15 +196,19 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Homekit switches.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] + hkid: str = config_entry.data["AccessoryPairingID"] + conn: HKDevice = hass.data[KNOWN_DEVICES][hkid] @callback def async_add_service(service: Service) -> bool: if not (entity_class := ENTITY_TYPES.get(service.type)): return False info = {"aid": service.accessory.aid, "iid": service.iid} - async_add_entities([entity_class(conn, info)], True) + entity: HomeKitSwitch | HomeKitValve = entity_class(conn, info) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SWITCH + ) + async_add_entities([entity]) return True conn.add_listener(async_add_service) @@ -214,9 +219,11 @@ async def async_setup_entry( return False info = {"aid": char.service.accessory.aid, "iid": char.service.iid} - async_add_entities( - [DeclarativeCharacteristicSwitch(conn, info, char, description)], True + entity = DeclarativeCharacteristicSwitch(conn, info, char, description) + conn.async_migrate_unique_id( + entity.old_unique_id, entity.unique_id, Platform.SWITCH ) + async_add_entities([entity]) return True conn.add_char_factory(async_add_characteristic) diff --git a/tests/components/homekit_controller/common.py b/tests/components/homekit_controller/common.py index 07cc2b5cae7..b30ba6236a9 100644 --- a/tests/components/homekit_controller/common.py +++ b/tests/components/homekit_controller/common.py @@ -9,7 +9,12 @@ import os from typing import Any, Final from unittest import mock -from aiohomekit.model import Accessories, AccessoriesState, Accessory +from aiohomekit.model import ( + Accessories, + AccessoriesState, + Accessory, + mixin as model_mixin, +) from aiohomekit.testing import FakeController, FakePairing from aiohomekit.zeroconf import HomeKitService @@ -19,7 +24,6 @@ from homeassistant.components.homekit_controller.const import ( DOMAIN, HOMEKIT_ACCESSORY_DISPATCH, IDENTIFIER_ACCESSORY_ID, - IDENTIFIER_SERIAL_NUMBER, ) from homeassistant.components.homekit_controller.utils import async_get_controller from homeassistant.config_entries import ConfigEntry @@ -320,7 +324,6 @@ async def assert_devices_and_entities_created( device = device_registry.async_get_device( { - (IDENTIFIER_SERIAL_NUMBER, expected.serial_number), (IDENTIFIER_ACCESSORY_ID, expected.unique_id), } ) @@ -336,21 +339,15 @@ async def assert_devices_and_entities_created( # We might have matched the device by one identifier only # Lets check that the other one is correct. Otherwise the test might silently be wrong. - serial_number_set = False accessory_id_set = False for key, value in device.identifiers: - if key == IDENTIFIER_SERIAL_NUMBER: - assert value == expected.serial_number - serial_number_set = True - - elif key == IDENTIFIER_ACCESSORY_ID: + if key == IDENTIFIER_ACCESSORY_ID: assert value == expected.unique_id accessory_id_set = True # If unique_id or serial is provided it MUST actually appear in the device registry entry. assert (not expected.unique_id) ^ accessory_id_set - assert (not expected.serial_number) ^ serial_number_set for entity_info in expected.entities: entity = entity_registry.async_get(entity_info.entity_id) @@ -410,3 +407,8 @@ async def remove_device(ws_client, device_id, config_entry_id): ) response = await ws_client.receive_json() return response["success"] + + +def get_next_aid(): + """Get next aid.""" + return model_mixin.id_counter + 1 diff --git a/tests/components/homekit_controller/specific_devices/test_anker_eufycam.py b/tests/components/homekit_controller/specific_devices/test_anker_eufycam.py index 644abb8a3a6..f2e209a9fdb 100644 --- a/tests/components/homekit_controller/specific_devices/test_anker_eufycam.py +++ b/tests/components/homekit_controller/specific_devices/test_anker_eufycam.py @@ -39,7 +39,7 @@ async def test_eufycam_setup(hass): EntityTestInfo( entity_id="camera.eufycam2_0000", friendly_name="eufyCam2-0000", - unique_id="homekit-A0000A000000000D-aid:4", + unique_id="00:00:00:00:00:00_4", state="idle", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_aqara_gateway.py b/tests/components/homekit_controller/specific_devices/test_aqara_gateway.py index 75423f3373e..7df51316ceb 100644 --- a/tests/components/homekit_controller/specific_devices/test_aqara_gateway.py +++ b/tests/components/homekit_controller/specific_devices/test_aqara_gateway.py @@ -37,7 +37,7 @@ async def test_aqara_gateway_setup(hass): EntityTestInfo( "alarm_control_panel.aqara_hub_1563_security_system", friendly_name="Aqara Hub-1563 Security System", - unique_id="homekit-0000000123456789-66304", + unique_id="00:00:00:00:00:00_1_66304", supported_features=AlarmControlPanelEntityFeature.ARM_NIGHT | AlarmControlPanelEntityFeature.ARM_HOME | AlarmControlPanelEntityFeature.ARM_AWAY, @@ -46,7 +46,7 @@ async def test_aqara_gateway_setup(hass): EntityTestInfo( "light.aqara_hub_1563_lightbulb_1563", friendly_name="Aqara Hub-1563 Lightbulb-1563", - unique_id="homekit-0000000123456789-65792", + unique_id="00:00:00:00:00:00_1_65792", supported_features=0, capabilities={"supported_color_modes": ["hs"]}, state="off", @@ -54,7 +54,7 @@ async def test_aqara_gateway_setup(hass): EntityTestInfo( "number.aqara_hub_1563_volume", friendly_name="Aqara Hub-1563 Volume", - unique_id="homekit-0000000123456789-aid:1-sid:65536-cid:65541", + unique_id="00:00:00:00:00:00_1_65536_65541", capabilities={ "max": 100, "min": 0, @@ -67,7 +67,7 @@ async def test_aqara_gateway_setup(hass): EntityTestInfo( "switch.aqara_hub_1563_pairing_mode", friendly_name="Aqara Hub-1563 Pairing Mode", - unique_id="homekit-0000000123456789-aid:1-sid:65536-cid:65538", + unique_id="00:00:00:00:00:00_1_65536_65538", entity_category=EntityCategory.CONFIG, state="off", ), @@ -96,7 +96,7 @@ async def test_aqara_gateway_e1_setup(hass): EntityTestInfo( "alarm_control_panel.aqara_hub_e1_00a0_security_system", friendly_name="Aqara-Hub-E1-00A0 Security System", - unique_id="homekit-00aa00000a0-16", + unique_id="00:00:00:00:00:00_1_16", supported_features=AlarmControlPanelEntityFeature.ARM_NIGHT | AlarmControlPanelEntityFeature.ARM_HOME | AlarmControlPanelEntityFeature.ARM_AWAY, @@ -105,7 +105,7 @@ async def test_aqara_gateway_e1_setup(hass): EntityTestInfo( "number.aqara_hub_e1_00a0_volume", friendly_name="Aqara-Hub-E1-00A0 Volume", - unique_id="homekit-00aa00000a0-aid:1-sid:17-cid:1114116", + unique_id="00:00:00:00:00:00_1_17_1114116", capabilities={ "max": 100, "min": 0, @@ -118,7 +118,7 @@ async def test_aqara_gateway_e1_setup(hass): EntityTestInfo( "switch.aqara_hub_e1_00a0_pairing_mode", friendly_name="Aqara-Hub-E1-00A0 Pairing Mode", - unique_id="homekit-00aa00000a0-aid:1-sid:17-cid:1114117", + unique_id="00:00:00:00:00:00_1_17_1114117", entity_category=EntityCategory.CONFIG, state="off", ), diff --git a/tests/components/homekit_controller/specific_devices/test_aqara_switch.py b/tests/components/homekit_controller/specific_devices/test_aqara_switch.py index 793fb49af5b..6472d993974 100644 --- a/tests/components/homekit_controller/specific_devices/test_aqara_switch.py +++ b/tests/components/homekit_controller/specific_devices/test_aqara_switch.py @@ -42,7 +42,7 @@ async def test_aqara_switch_setup(hass): EntityTestInfo( entity_id="sensor.programmable_switch_battery_sensor", friendly_name="Programmable Switch Battery Sensor", - unique_id="homekit-111a1111a1a111-5", + unique_id="00:00:00:00:00:00_1_5", capabilities={"state_class": SensorStateClass.MEASUREMENT}, entity_category=EntityCategory.DIAGNOSTIC, unit_of_measurement=PERCENTAGE, diff --git a/tests/components/homekit_controller/specific_devices/test_arlo_baby.py b/tests/components/homekit_controller/specific_devices/test_arlo_baby.py index 1b2b4bda3d6..26c0c87e3b3 100644 --- a/tests/components/homekit_controller/specific_devices/test_arlo_baby.py +++ b/tests/components/homekit_controller/specific_devices/test_arlo_baby.py @@ -33,19 +33,19 @@ async def test_arlo_baby_setup(hass): entities=[ EntityTestInfo( entity_id="camera.arlobabya0", - unique_id="homekit-00A0000000000-aid:1", + unique_id="00:00:00:00:00:00_1", friendly_name="ArloBabyA0", state="idle", ), EntityTestInfo( entity_id="binary_sensor.arlobabya0_motion", - unique_id="homekit-00A0000000000-500", + unique_id="00:00:00:00:00:00_1_500", friendly_name="ArloBabyA0 Motion", state="off", ), EntityTestInfo( entity_id="sensor.arlobabya0_battery", - unique_id="homekit-00A0000000000-700", + unique_id="00:00:00:00:00:00_1_700", friendly_name="ArloBabyA0 Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -54,7 +54,7 @@ async def test_arlo_baby_setup(hass): ), EntityTestInfo( entity_id="sensor.arlobabya0_humidity", - unique_id="homekit-00A0000000000-900", + unique_id="00:00:00:00:00:00_1_900", friendly_name="ArloBabyA0 Humidity", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=PERCENTAGE, @@ -62,7 +62,7 @@ async def test_arlo_baby_setup(hass): ), EntityTestInfo( entity_id="sensor.arlobabya0_temperature", - unique_id="homekit-00A0000000000-1000", + unique_id="00:00:00:00:00:00_1_1000", friendly_name="ArloBabyA0 Temperature", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=TEMP_CELSIUS, @@ -70,14 +70,14 @@ async def test_arlo_baby_setup(hass): ), EntityTestInfo( entity_id="sensor.arlobabya0_air_quality", - unique_id="homekit-00A0000000000-aid:1-sid:800-cid:802", + unique_id="00:00:00:00:00:00_1_800_802", capabilities={"state_class": SensorStateClass.MEASUREMENT}, friendly_name="ArloBabyA0 Air Quality", state="1", ), EntityTestInfo( entity_id="light.arlobabya0_nightlight", - unique_id="homekit-00A0000000000-1100", + unique_id="00:00:00:00:00:00_1_1100", friendly_name="ArloBabyA0 Nightlight", supported_features=0, capabilities={"supported_color_modes": ["hs"]}, diff --git a/tests/components/homekit_controller/specific_devices/test_connectsense.py b/tests/components/homekit_controller/specific_devices/test_connectsense.py index 9e233ebdc10..096ed39a336 100644 --- a/tests/components/homekit_controller/specific_devices/test_connectsense.py +++ b/tests/components/homekit_controller/specific_devices/test_connectsense.py @@ -37,7 +37,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_current", friendly_name="InWall Outlet-0394DE Current", - unique_id="homekit-1020301376-aid:1-sid:13-cid:18", + unique_id="00:00:00:00:00:00_1_13_18", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=ELECTRIC_CURRENT_AMPERE, state="0.03", @@ -45,7 +45,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_power", friendly_name="InWall Outlet-0394DE Power", - unique_id="homekit-1020301376-aid:1-sid:13-cid:19", + unique_id="00:00:00:00:00:00_1_13_19", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=POWER_WATT, state="0.8", @@ -53,7 +53,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_energy_kwh", friendly_name="InWall Outlet-0394DE Energy kWh", - unique_id="homekit-1020301376-aid:1-sid:13-cid:20", + unique_id="00:00:00:00:00:00_1_13_20", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=ENERGY_KILO_WATT_HOUR, state="379.69299", @@ -61,13 +61,13 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="switch.inwall_outlet_0394de_outlet_a", friendly_name="InWall Outlet-0394DE Outlet A", - unique_id="homekit-1020301376-13", + unique_id="00:00:00:00:00:00_1_13", state="on", ), EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_current_2", friendly_name="InWall Outlet-0394DE Current", - unique_id="homekit-1020301376-aid:1-sid:25-cid:30", + unique_id="00:00:00:00:00:00_1_25_30", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=ELECTRIC_CURRENT_AMPERE, state="0.05", @@ -75,7 +75,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_power_2", friendly_name="InWall Outlet-0394DE Power", - unique_id="homekit-1020301376-aid:1-sid:25-cid:31", + unique_id="00:00:00:00:00:00_1_25_31", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=POWER_WATT, state="0.8", @@ -83,7 +83,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="sensor.inwall_outlet_0394de_energy_kwh_2", friendly_name="InWall Outlet-0394DE Energy kWh", - unique_id="homekit-1020301376-aid:1-sid:25-cid:32", + unique_id="00:00:00:00:00:00_1_25_32", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=ENERGY_KILO_WATT_HOUR, state="175.85001", @@ -91,7 +91,7 @@ async def test_connectsense_setup(hass): EntityTestInfo( entity_id="switch.inwall_outlet_0394de_outlet_b", friendly_name="InWall Outlet-0394DE Outlet B", - unique_id="homekit-1020301376-25", + unique_id="00:00:00:00:00:00_1_25", state="on", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_ecobee3.py b/tests/components/homekit_controller/specific_devices/test_ecobee3.py index 69a7d4f809c..299b8d24a9b 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): EntityTestInfo( entity_id="binary_sensor.kitchen", friendly_name="Kitchen", - unique_id="homekit-AB1C-56", + unique_id="00:00:00:00:00:00_2_56", state="off", ), ], @@ -78,7 +78,7 @@ async def test_ecobee3_setup(hass): EntityTestInfo( entity_id="binary_sensor.porch", friendly_name="Porch", - unique_id="homekit-AB2C-56", + unique_id="00:00:00:00:00:00_3_56", state="off", ), ], @@ -96,7 +96,7 @@ async def test_ecobee3_setup(hass): EntityTestInfo( entity_id="binary_sensor.basement", friendly_name="Basement", - unique_id="homekit-AB3C-56", + unique_id="00:00:00:00:00:00_4_56", state="off", ), ], @@ -106,7 +106,7 @@ async def test_ecobee3_setup(hass): EntityTestInfo( entity_id="climate.homew", friendly_name="HomeW", - unique_id="homekit-123456789012-16", + unique_id="00:00:00:00:00:00_1_16", supported_features=( SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_RANGE @@ -124,7 +124,7 @@ async def test_ecobee3_setup(hass): EntityTestInfo( entity_id="sensor.homew_current_temperature", friendly_name="HomeW Current Temperature", - unique_id="homekit-123456789012-aid:1-sid:16-cid:19", + unique_id="00:00:00:00:00:00_1_16_19", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=TEMP_CELSIUS, state="21.8", @@ -132,7 +132,7 @@ async def test_ecobee3_setup(hass): EntityTestInfo( entity_id="select.homew_current_mode", friendly_name="HomeW Current Mode", - unique_id="homekit-123456789012-aid:1-sid:16-cid:33", + unique_id="00:00:00:00:00:00_1_16_33", capabilities={"options": ["home", "sleep", "away"]}, state="home", ), @@ -164,16 +164,16 @@ async def test_ecobee3_setup_from_cache(hass, hass_storage): entity_registry = er.async_get(hass) climate = entity_registry.async_get("climate.homew") - assert climate.unique_id == "homekit-123456789012-16" + assert climate.unique_id == "00:00:00:00:00:00_1_16" occ1 = entity_registry.async_get("binary_sensor.kitchen") - assert occ1.unique_id == "homekit-AB1C-56" + assert occ1.unique_id == "00:00:00:00:00:00_2_56" occ2 = entity_registry.async_get("binary_sensor.porch") - assert occ2.unique_id == "homekit-AB2C-56" + assert occ2.unique_id == "00:00:00:00:00:00_3_56" occ3 = entity_registry.async_get("binary_sensor.basement") - assert occ3.unique_id == "homekit-AB3C-56" + assert occ3.unique_id == "00:00:00:00:00:00_4_56" async def test_ecobee3_setup_connection_failure(hass): @@ -204,16 +204,16 @@ async def test_ecobee3_setup_connection_failure(hass): await time_changed(hass, 5 * 60) climate = entity_registry.async_get("climate.homew") - assert climate.unique_id == "homekit-123456789012-16" + assert climate.unique_id == "00:00:00:00:00:00_1_16" occ1 = entity_registry.async_get("binary_sensor.kitchen") - assert occ1.unique_id == "homekit-AB1C-56" + assert occ1.unique_id == "00:00:00:00:00:00_2_56" occ2 = entity_registry.async_get("binary_sensor.porch") - assert occ2.unique_id == "homekit-AB2C-56" + assert occ2.unique_id == "00:00:00:00:00:00_3_56" occ3 = entity_registry.async_get("binary_sensor.basement") - assert occ3.unique_id == "homekit-AB3C-56" + assert occ3.unique_id == "00:00:00:00:00:00_4_56" async def test_ecobee3_add_sensors_at_runtime(hass): @@ -226,7 +226,7 @@ async def test_ecobee3_add_sensors_at_runtime(hass): await setup_test_accessories(hass, accessories) climate = entity_registry.async_get("climate.homew") - assert climate.unique_id == "homekit-123456789012-16" + assert climate.unique_id == "00:00:00:00:00:00_1_16" occ1 = entity_registry.async_get("binary_sensor.kitchen") assert occ1 is None @@ -243,10 +243,10 @@ async def test_ecobee3_add_sensors_at_runtime(hass): await device_config_changed(hass, accessories) occ1 = entity_registry.async_get("binary_sensor.kitchen") - assert occ1.unique_id == "homekit-AB1C-56" + assert occ1.unique_id == "00:00:00:00:00:00_2_56" occ2 = entity_registry.async_get("binary_sensor.porch") - assert occ2.unique_id == "homekit-AB2C-56" + assert occ2.unique_id == "00:00:00:00:00:00_3_56" occ3 = entity_registry.async_get("binary_sensor.basement") - assert occ3.unique_id == "homekit-AB3C-56" + assert occ3.unique_id == "00:00:00:00:00:00_4_56" diff --git a/tests/components/homekit_controller/specific_devices/test_ecobee_501.py b/tests/components/homekit_controller/specific_devices/test_ecobee_501.py index cf498a61e81..3d508df3a9e 100644 --- a/tests/components/homekit_controller/specific_devices/test_ecobee_501.py +++ b/tests/components/homekit_controller/specific_devices/test_ecobee_501.py @@ -39,7 +39,7 @@ async def test_ecobee501_setup(hass): EntityTestInfo( entity_id="climate.my_ecobee", friendly_name="My ecobee", - unique_id="homekit-123456789016-16", + unique_id="00:00:00:00:00:00_1_16", supported_features=( SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_RANGE @@ -59,7 +59,7 @@ async def test_ecobee501_setup(hass): EntityTestInfo( entity_id="binary_sensor.my_ecobee_occupancy", friendly_name="My ecobee Occupancy", - unique_id="homekit-123456789016-57", + unique_id="00:00:00:00:00:00_1_57", unit_of_measurement=None, state=STATE_ON, ), diff --git a/tests/components/homekit_controller/specific_devices/test_ecobee_occupancy.py b/tests/components/homekit_controller/specific_devices/test_ecobee_occupancy.py index 20dae666c69..88220279b0c 100644 --- a/tests/components/homekit_controller/specific_devices/test_ecobee_occupancy.py +++ b/tests/components/homekit_controller/specific_devices/test_ecobee_occupancy.py @@ -34,7 +34,7 @@ async def test_ecobee_occupancy_setup(hass): EntityTestInfo( entity_id="binary_sensor.master_fan", friendly_name="Master Fan", - unique_id="homekit-111111111111-56", + unique_id="00:00:00:00:00:00_1_56", state="off", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_eve_degree.py b/tests/components/homekit_controller/specific_devices/test_eve_degree.py index eab2de030db..c1a73dc37fa 100644 --- a/tests/components/homekit_controller/specific_devices/test_eve_degree.py +++ b/tests/components/homekit_controller/specific_devices/test_eve_degree.py @@ -34,7 +34,7 @@ async def test_eve_degree_setup(hass): entities=[ EntityTestInfo( entity_id="sensor.eve_degree_aa11_temperature", - unique_id="homekit-AA00A0A00000-22", + unique_id="00:00:00:00:00:00_1_22", friendly_name="Eve Degree AA11 Temperature", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=TEMP_CELSIUS, @@ -42,7 +42,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_degree_aa11_humidity", - unique_id="homekit-AA00A0A00000-27", + unique_id="00:00:00:00:00:00_1_27", friendly_name="Eve Degree AA11 Humidity", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=PERCENTAGE, @@ -50,7 +50,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_degree_aa11_air_pressure", - unique_id="homekit-AA00A0A00000-aid:1-sid:30-cid:32", + unique_id="00:00:00:00:00:00_1_30_32", friendly_name="Eve Degree AA11 Air Pressure", unit_of_measurement=PRESSURE_HPA, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -58,7 +58,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_degree_aa11_battery", - unique_id="homekit-AA00A0A00000-17", + unique_id="00:00:00:00:00:00_1_17", friendly_name="Eve Degree AA11 Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -67,7 +67,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="number.eve_degree_aa11_elevation", - unique_id="homekit-AA00A0A00000-aid:1-sid:30-cid:33", + unique_id="00:00:00:00:00:00_1_30_33", friendly_name="Eve Degree AA11 Elevation", capabilities={ "max": 9000, diff --git a/tests/components/homekit_controller/specific_devices/test_eve_energy.py b/tests/components/homekit_controller/specific_devices/test_eve_energy.py index 292ab9c66ac..65e5c16179f 100644 --- a/tests/components/homekit_controller/specific_devices/test_eve_energy.py +++ b/tests/components/homekit_controller/specific_devices/test_eve_energy.py @@ -19,7 +19,7 @@ from ..common import ( ) -async def test_eve_degree_setup(hass): +async def test_eve_energy_setup(hass): """Test that the accessory can be correctly setup in HA.""" accessories = await setup_accessories_from_file(hass, "eve_energy.json") await setup_test_accessories(hass, accessories) @@ -38,13 +38,13 @@ async def test_eve_degree_setup(hass): entities=[ EntityTestInfo( entity_id="switch.eve_energy_50ff", - unique_id="homekit-AA00A0A00000-28", + unique_id="00:00:00:00:00:00_1_28", friendly_name="Eve Energy 50FF", state="off", ), EntityTestInfo( entity_id="sensor.eve_energy_50ff_amps", - unique_id="homekit-AA00A0A00000-aid:1-sid:28-cid:33", + unique_id="00:00:00:00:00:00_1_28_33", friendly_name="Eve Energy 50FF Amps", unit_of_measurement=ELECTRIC_CURRENT_AMPERE, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -52,7 +52,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_energy_50ff_volts", - unique_id="homekit-AA00A0A00000-aid:1-sid:28-cid:32", + unique_id="00:00:00:00:00:00_1_28_32", friendly_name="Eve Energy 50FF Volts", unit_of_measurement=ELECTRIC_POTENTIAL_VOLT, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -60,7 +60,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_energy_50ff_power", - unique_id="homekit-AA00A0A00000-aid:1-sid:28-cid:34", + unique_id="00:00:00:00:00:00_1_28_34", friendly_name="Eve Energy 50FF Power", unit_of_measurement=POWER_WATT, capabilities={"state_class": SensorStateClass.MEASUREMENT}, @@ -68,7 +68,7 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="sensor.eve_energy_50ff_energy_kwh", - unique_id="homekit-AA00A0A00000-aid:1-sid:28-cid:35", + unique_id="00:00:00:00:00:00_1_28_35", friendly_name="Eve Energy 50FF Energy kWh", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=ENERGY_KILO_WATT_HOUR, @@ -76,14 +76,14 @@ async def test_eve_degree_setup(hass): ), EntityTestInfo( entity_id="switch.eve_energy_50ff_lock_physical_controls", - unique_id="homekit-AA00A0A00000-aid:1-sid:28-cid:36", + unique_id="00:00:00:00:00:00_1_28_36", friendly_name="Eve Energy 50FF Lock Physical Controls", entity_category=EntityCategory.CONFIG, state="off", ), EntityTestInfo( entity_id="button.eve_energy_50ff_identify", - unique_id="homekit-AA00A0A00000-aid:1-sid:1-cid:3", + unique_id="00:00:00:00:00:00_1_1_3", friendly_name="Eve Energy 50FF Identify", entity_category=EntityCategory.DIAGNOSTIC, state="unknown", diff --git a/tests/components/homekit_controller/specific_devices/test_haa_fan.py b/tests/components/homekit_controller/specific_devices/test_haa_fan.py index 2f01a2c404e..33eb5e24979 100644 --- a/tests/components/homekit_controller/specific_devices/test_haa_fan.py +++ b/tests/components/homekit_controller/specific_devices/test_haa_fan.py @@ -46,7 +46,7 @@ async def test_haa_fan_setup(hass): EntityTestInfo( entity_id="switch.haa_c718b3", friendly_name="HAA-C718B3", - unique_id="homekit-C718B3-2-8", + unique_id="00:00:00:00:00:00_2_8", state="off", ) ], @@ -56,7 +56,7 @@ async def test_haa_fan_setup(hass): EntityTestInfo( entity_id="fan.haa_c718b3", friendly_name="HAA-C718B3", - unique_id="homekit-C718B3-1-8", + unique_id="00:00:00:00:00:00_1_8", state="on", supported_features=FanEntityFeature.SET_SPEED, capabilities={ @@ -66,14 +66,14 @@ async def test_haa_fan_setup(hass): EntityTestInfo( entity_id="button.haa_c718b3_setup", friendly_name="HAA-C718B3 Setup", - unique_id="homekit-C718B3-1-aid:1-sid:1010-cid:1012", + unique_id="00:00:00:00:00:00_1_1010_1012", entity_category=EntityCategory.CONFIG, state="unknown", ), EntityTestInfo( entity_id="button.haa_c718b3_update", friendly_name="HAA-C718B3 Update", - unique_id="homekit-C718B3-1-aid:1-sid:1010-cid:1011", + unique_id="00:00:00:00:00:00_1_1010_1011", entity_category=EntityCategory.CONFIG, state="unknown", ), diff --git a/tests/components/homekit_controller/specific_devices/test_homeassistant_bridge.py b/tests/components/homekit_controller/specific_devices/test_homeassistant_bridge.py index 175e534f639..6848f4079b0 100644 --- a/tests/components/homekit_controller/specific_devices/test_homeassistant_bridge.py +++ b/tests/components/homekit_controller/specific_devices/test_homeassistant_bridge.py @@ -43,7 +43,7 @@ async def test_homeassistant_bridge_fan_setup(hass): EntityTestInfo( entity_id="fan.living_room_fan", friendly_name="Living Room Fan", - unique_id="homekit-fan.living_room_fan-8", + unique_id="00:00:00:00:00:00_1256851357_8", supported_features=( FanEntityFeature.DIRECTION | FanEntityFeature.SET_SPEED diff --git a/tests/components/homekit_controller/specific_devices/test_hue_bridge.py b/tests/components/homekit_controller/specific_devices/test_hue_bridge.py index 1092bb4f82c..361bfbfe178 100644 --- a/tests/components/homekit_controller/specific_devices/test_hue_bridge.py +++ b/tests/components/homekit_controller/specific_devices/test_hue_bridge.py @@ -46,7 +46,7 @@ async def test_hue_bridge_setup(hass): capabilities={"state_class": SensorStateClass.MEASUREMENT}, friendly_name="Hue dimmer switch battery", entity_category=EntityCategory.DIAGNOSTIC, - unique_id="homekit-6623462389072572-644245094400", + unique_id="00:00:00:00:00:00_6623462389072572_644245094400", unit_of_measurement=PERCENTAGE, state="100", ) diff --git a/tests/components/homekit_controller/specific_devices/test_koogeek_ls1.py b/tests/components/homekit_controller/specific_devices/test_koogeek_ls1.py index 99f34491e86..2e3102d8f13 100644 --- a/tests/components/homekit_controller/specific_devices/test_koogeek_ls1.py +++ b/tests/components/homekit_controller/specific_devices/test_koogeek_ls1.py @@ -46,7 +46,7 @@ async def test_koogeek_ls1_setup(hass): EntityTestInfo( entity_id="light.koogeek_ls1_20833f_light_strip", friendly_name="Koogeek-LS1-20833F Light Strip", - unique_id="homekit-AAAA011111111111-7", + unique_id="00:00:00:00:00:00_1_7", supported_features=0, capabilities={"supported_color_modes": ["hs"]}, state="off", @@ -54,7 +54,7 @@ async def test_koogeek_ls1_setup(hass): EntityTestInfo( entity_id="button.koogeek_ls1_20833f_identify", friendly_name="Koogeek-LS1-20833F Identify", - unique_id="homekit-AAAA011111111111-aid:1-sid:1-cid:6", + unique_id="00:00:00:00:00:00_1_1_6", entity_category=EntityCategory.DIAGNOSTIC, state="unknown", ), 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 7df1cee54d5..ee8c273904c 100644 --- a/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py +++ b/tests/components/homekit_controller/specific_devices/test_koogeek_p1eu.py @@ -33,13 +33,13 @@ async def test_koogeek_p1eu_setup(hass): EntityTestInfo( entity_id="switch.koogeek_p1_a00aa0_outlet", friendly_name="Koogeek-P1-A00AA0 outlet", - unique_id="homekit-EUCP03190xxxxx48-7", + unique_id="00:00:00:00:00:00_1_7", state="off", ), EntityTestInfo( entity_id="sensor.koogeek_p1_a00aa0_power", friendly_name="Koogeek-P1-A00AA0 Power", - unique_id="homekit-EUCP03190xxxxx48-aid:1-sid:21-cid:22", + unique_id="00:00:00:00:00:00_1_21_22", unit_of_measurement=POWER_WATT, capabilities={"state_class": SensorStateClass.MEASUREMENT}, state="5", 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 210fec0aafc..91edf91156a 100644 --- a/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py +++ b/tests/components/homekit_controller/specific_devices/test_koogeek_sw2.py @@ -39,19 +39,19 @@ async def test_koogeek_sw2_setup(hass): EntityTestInfo( entity_id="switch.koogeek_sw2_187a91_switch_1", friendly_name="Koogeek-SW2-187A91 Switch 1", - unique_id="homekit-CNNT061751001372-8", + unique_id="00:00:00:00:00:00_1_8", state="off", ), EntityTestInfo( entity_id="switch.koogeek_sw2_187a91_switch_2", friendly_name="Koogeek-SW2-187A91 Switch 2", - unique_id="homekit-CNNT061751001372-11", + unique_id="00:00:00:00:00:00_1_11", state="off", ), EntityTestInfo( entity_id="sensor.koogeek_sw2_187a91_power", friendly_name="Koogeek-SW2-187A91 Power", - unique_id="homekit-CNNT061751001372-aid:1-sid:14-cid:18", + unique_id="00:00:00:00:00:00_1_14_18", unit_of_measurement=POWER_WATT, capabilities={"state_class": SensorStateClass.MEASUREMENT}, state="0", diff --git a/tests/components/homekit_controller/specific_devices/test_lennox_e30.py b/tests/components/homekit_controller/specific_devices/test_lennox_e30.py index 1bb31241023..fb1c0d183d3 100644 --- a/tests/components/homekit_controller/specific_devices/test_lennox_e30.py +++ b/tests/components/homekit_controller/specific_devices/test_lennox_e30.py @@ -39,7 +39,7 @@ async def test_lennox_e30_setup(hass): EntityTestInfo( entity_id="climate.lennox", friendly_name="Lennox", - unique_id="homekit-XXXXXXXX-100", + unique_id="00:00:00:00:00:00_1_100", supported_features=( SUPPORT_TARGET_TEMPERATURE | SUPPORT_TARGET_TEMPERATURE_RANGE ), diff --git a/tests/components/homekit_controller/specific_devices/test_lg_tv.py b/tests/components/homekit_controller/specific_devices/test_lg_tv.py index 22d29f7500d..4af74e0cd86 100644 --- a/tests/components/homekit_controller/specific_devices/test_lg_tv.py +++ b/tests/components/homekit_controller/specific_devices/test_lg_tv.py @@ -36,7 +36,7 @@ async def test_lg_tv(hass): EntityTestInfo( entity_id="media_player.lg_webos_tv_af80", friendly_name="LG webOS TV AF80", - unique_id="homekit-999AAAAAA999-48", + unique_id="00:00:00:00:00:00_1_48", supported_features=( SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_SELECT_SOURCE ), diff --git a/tests/components/homekit_controller/specific_devices/test_lutron_caseta_bridge.py b/tests/components/homekit_controller/specific_devices/test_lutron_caseta_bridge.py index 9df8cf4e5ae..76c5bc70bff 100644 --- a/tests/components/homekit_controller/specific_devices/test_lutron_caseta_bridge.py +++ b/tests/components/homekit_controller/specific_devices/test_lutron_caseta_bridge.py @@ -41,7 +41,7 @@ async def test_lutron_caseta_bridge_setup(hass): EntityTestInfo( entity_id="fan.caseta_r_wireless_fan_speed_control", friendly_name="Caséta® Wireless Fan Speed Control", - unique_id="homekit-39024290-2", + unique_id="00:00:00:00:00:00_21474836482_2", unit_of_measurement=None, supported_features=1, state=STATE_OFF, diff --git a/tests/components/homekit_controller/specific_devices/test_mss425f.py b/tests/components/homekit_controller/specific_devices/test_mss425f.py index 6db4140bd75..86d8ebeca71 100644 --- a/tests/components/homekit_controller/specific_devices/test_mss425f.py +++ b/tests/components/homekit_controller/specific_devices/test_mss425f.py @@ -34,38 +34,38 @@ async def test_meross_mss425f_setup(hass): EntityTestInfo( entity_id="button.mss425f_15cc_identify", friendly_name="MSS425F-15cc Identify", - unique_id="homekit-HH41234-aid:1-sid:1-cid:2", + unique_id="00:00:00:00:00:00_1_1_2", entity_category=EntityCategory.DIAGNOSTIC, state=STATE_UNKNOWN, ), EntityTestInfo( entity_id="switch.mss425f_15cc_outlet_1", friendly_name="MSS425F-15cc Outlet-1", - unique_id="homekit-HH41234-12", + unique_id="00:00:00:00:00:00_1_12", state=STATE_ON, ), EntityTestInfo( entity_id="switch.mss425f_15cc_outlet_2", friendly_name="MSS425F-15cc Outlet-2", - unique_id="homekit-HH41234-15", + unique_id="00:00:00:00:00:00_1_15", state=STATE_ON, ), EntityTestInfo( entity_id="switch.mss425f_15cc_outlet_3", friendly_name="MSS425F-15cc Outlet-3", - unique_id="homekit-HH41234-18", + unique_id="00:00:00:00:00:00_1_18", state=STATE_ON, ), EntityTestInfo( entity_id="switch.mss425f_15cc_outlet_4", friendly_name="MSS425F-15cc Outlet-4", - unique_id="homekit-HH41234-21", + unique_id="00:00:00:00:00:00_1_21", state=STATE_ON, ), EntityTestInfo( entity_id="switch.mss425f_15cc_usb", friendly_name="MSS425F-15cc USB", - unique_id="homekit-HH41234-24", + unique_id="00:00:00:00:00:00_1_24", state=STATE_ON, ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_mss565.py b/tests/components/homekit_controller/specific_devices/test_mss565.py index 1a9c5bbbf6f..5140b563a9a 100644 --- a/tests/components/homekit_controller/specific_devices/test_mss565.py +++ b/tests/components/homekit_controller/specific_devices/test_mss565.py @@ -33,7 +33,7 @@ async def test_meross_mss565_setup(hass): EntityTestInfo( entity_id="light.mss565_28da_dimmer_switch", friendly_name="MSS565-28da Dimmer Switch", - unique_id="homekit-BB1121-12", + unique_id="00:00:00:00:00:00_1_12", capabilities={"supported_color_modes": ["brightness"]}, state=STATE_ON, ), diff --git a/tests/components/homekit_controller/specific_devices/test_mysa_living.py b/tests/components/homekit_controller/specific_devices/test_mysa_living.py index a5abe4ad2e7..83404d9dd99 100644 --- a/tests/components/homekit_controller/specific_devices/test_mysa_living.py +++ b/tests/components/homekit_controller/specific_devices/test_mysa_living.py @@ -34,7 +34,7 @@ async def test_mysa_living_setup(hass): EntityTestInfo( entity_id="climate.mysa_85dda9_thermostat", friendly_name="Mysa-85dda9 Thermostat", - unique_id="homekit-AAAAAAA000-20", + unique_id="00:00:00:00:00:00_1_20", supported_features=ClimateEntityFeature.TARGET_TEMPERATURE, capabilities={ "hvac_modes": ["off", "heat", "cool", "heat_cool"], @@ -46,7 +46,7 @@ async def test_mysa_living_setup(hass): EntityTestInfo( entity_id="sensor.mysa_85dda9_current_humidity", friendly_name="Mysa-85dda9 Current Humidity", - unique_id="homekit-AAAAAAA000-aid:1-sid:20-cid:27", + unique_id="00:00:00:00:00:00_1_20_27", unit_of_measurement=PERCENTAGE, capabilities={"state_class": SensorStateClass.MEASUREMENT}, state="40", @@ -54,7 +54,7 @@ async def test_mysa_living_setup(hass): EntityTestInfo( entity_id="sensor.mysa_85dda9_current_temperature", friendly_name="Mysa-85dda9 Current Temperature", - unique_id="homekit-AAAAAAA000-aid:1-sid:20-cid:25", + unique_id="00:00:00:00:00:00_1_20_25", unit_of_measurement=TEMP_CELSIUS, capabilities={"state_class": SensorStateClass.MEASUREMENT}, state="24.1", @@ -62,7 +62,7 @@ async def test_mysa_living_setup(hass): EntityTestInfo( entity_id="light.mysa_85dda9_display", friendly_name="Mysa-85dda9 Display", - unique_id="homekit-AAAAAAA000-40", + unique_id="00:00:00:00:00:00_1_40", supported_features=0, capabilities={"supported_color_modes": ["brightness"]}, state="off", diff --git a/tests/components/homekit_controller/specific_devices/test_nanoleaf_strip_nl55.py b/tests/components/homekit_controller/specific_devices/test_nanoleaf_strip_nl55.py index 61d872ccd2a..4afb61b19f3 100644 --- a/tests/components/homekit_controller/specific_devices/test_nanoleaf_strip_nl55.py +++ b/tests/components/homekit_controller/specific_devices/test_nanoleaf_strip_nl55.py @@ -34,7 +34,7 @@ async def test_nanoleaf_nl55_setup(hass): EntityTestInfo( entity_id="light.nanoleaf_strip_3b32_nanoleaf_light_strip", friendly_name="Nanoleaf Strip 3B32 Nanoleaf Light Strip", - unique_id="homekit-AAAA011111111111-19", + unique_id="00:00:00:00:00:00_1_19", supported_features=0, capabilities={ "max_color_temp_kelvin": 6535, @@ -48,21 +48,21 @@ async def test_nanoleaf_nl55_setup(hass): EntityTestInfo( entity_id="button.nanoleaf_strip_3b32_identify", friendly_name="Nanoleaf Strip 3B32 Identify", - unique_id="homekit-AAAA011111111111-aid:1-sid:1-cid:2", + unique_id="00:00:00:00:00:00_1_1_2", entity_category=EntityCategory.DIAGNOSTIC, state="unknown", ), EntityTestInfo( entity_id="sensor.nanoleaf_strip_3b32_thread_capabilities", friendly_name="Nanoleaf Strip 3B32 Thread Capabilities", - unique_id="homekit-AAAA011111111111-aid:1-sid:31-cid:115", + unique_id="00:00:00:00:00:00_1_31_115", entity_category=EntityCategory.DIAGNOSTIC, state="border_router_capable", ), EntityTestInfo( entity_id="sensor.nanoleaf_strip_3b32_thread_status", friendly_name="Nanoleaf Strip 3B32 Thread Status", - unique_id="homekit-AAAA011111111111-aid:1-sid:31-cid:117", + unique_id="00:00:00:00:00:00_1_31_117", entity_category=EntityCategory.DIAGNOSTIC, state="border_router", ), diff --git a/tests/components/homekit_controller/specific_devices/test_netamo_doorbell.py b/tests/components/homekit_controller/specific_devices/test_netamo_doorbell.py index 188bbaffedd..9ff84c45701 100644 --- a/tests/components/homekit_controller/specific_devices/test_netamo_doorbell.py +++ b/tests/components/homekit_controller/specific_devices/test_netamo_doorbell.py @@ -35,7 +35,7 @@ async def test_netamo_doorbell_setup(hass): EntityTestInfo( entity_id="camera.netatmo_doorbell_g738658", friendly_name="Netatmo-Doorbell-g738658", - unique_id="homekit-g738658-aid:1", + unique_id="00:00:00:00:00:00_1", state="idle", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_netamo_smart_co_alarm.py b/tests/components/homekit_controller/specific_devices/test_netamo_smart_co_alarm.py index b2c83a005f8..3f46ffdc9fa 100644 --- a/tests/components/homekit_controller/specific_devices/test_netamo_smart_co_alarm.py +++ b/tests/components/homekit_controller/specific_devices/test_netamo_smart_co_alarm.py @@ -35,14 +35,14 @@ async def test_netamo_smart_co_alarm_setup(hass): EntityTestInfo( entity_id="binary_sensor.smart_co_alarm_carbon_monoxide_sensor", friendly_name="Smart CO Alarm Carbon Monoxide Sensor", - unique_id="homekit-1234-22", + unique_id="00:00:00:00:00:00_1_22", state="off", ), EntityTestInfo( entity_id="binary_sensor.smart_co_alarm_low_battery", friendly_name="Smart CO Alarm Low Battery", entity_category=EntityCategory.DIAGNOSTIC, - unique_id="homekit-1234-36", + unique_id="00:00:00:00:00:00_1_36", state="off", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py b/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py index ecea2cdafbb..c93493f38b5 100644 --- a/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py +++ b/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py @@ -34,49 +34,49 @@ async def test_rainmachine_pro_8_setup(hass): EntityTestInfo( entity_id="switch.rainmachine_00ce4a", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-512", + unique_id="00:00:00:00:00:00_1_512", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_2", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-768", + unique_id="00:00:00:00:00:00_1_768", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_3", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-1024", + unique_id="00:00:00:00:00:00_1_1024", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_4", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-1280", + unique_id="00:00:00:00:00:00_1_1280", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_5", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-1536", + unique_id="00:00:00:00:00:00_1_1536", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_6", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-1792", + unique_id="00:00:00:00:00:00_1_1792", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_7", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-2048", + unique_id="00:00:00:00:00:00_1_2048", state="off", ), EntityTestInfo( entity_id="switch.rainmachine_00ce4a_8", friendly_name="RainMachine-00ce4a", - unique_id="homekit-00aa0000aa0a-2304", + unique_id="00:00:00:00:00:00_1_2304", state="off", ), ], diff --git a/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py b/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py index a0c84472429..1e572683ce3 100644 --- a/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py +++ b/tests/components/homekit_controller/specific_devices/test_ryse_smart_bridge.py @@ -47,7 +47,7 @@ async def test_ryse_smart_bridge_setup(hass): EntityTestInfo( entity_id="cover.master_bath_south_ryse_shade", friendly_name="Master Bath South RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-2-48", + unique_id="00:00:00:00:00:00_2_48", supported_features=RYSE_SUPPORTED_FEATURES, state="closed", ), @@ -56,7 +56,7 @@ async def test_ryse_smart_bridge_setup(hass): friendly_name="Master Bath South RYSE Shade Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-00:00:00:00:00:00-2-64", + unique_id="00:00:00:00:00:00_2_64", unit_of_measurement=PERCENTAGE, state="100", ), @@ -75,7 +75,7 @@ async def test_ryse_smart_bridge_setup(hass): EntityTestInfo( entity_id="cover.ryse_smartshade_ryse_shade", friendly_name="RYSE SmartShade RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-3-48", + unique_id="00:00:00:00:00:00_3_48", supported_features=RYSE_SUPPORTED_FEATURES, state="open", ), @@ -84,7 +84,7 @@ async def test_ryse_smart_bridge_setup(hass): friendly_name="RYSE SmartShade RYSE Shade Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-00:00:00:00:00:00-3-64", + unique_id="00:00:00:00:00:00_3_64", unit_of_measurement=PERCENTAGE, state="100", ), @@ -126,7 +126,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): EntityTestInfo( entity_id="cover.lr_left_ryse_shade", friendly_name="LR Left RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-2-48", + unique_id="00:00:00:00:00:00_2_48", supported_features=RYSE_SUPPORTED_FEATURES, state="closed", ), @@ -135,7 +135,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): friendly_name="LR Left RYSE Shade Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-00:00:00:00:00:00-2-64", + unique_id="00:00:00:00:00:00_2_64", unit_of_measurement=PERCENTAGE, state="89", ), @@ -154,7 +154,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): EntityTestInfo( entity_id="cover.lr_right_ryse_shade", friendly_name="LR Right RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-3-48", + unique_id="00:00:00:00:00:00_3_48", supported_features=RYSE_SUPPORTED_FEATURES, state="closed", ), @@ -163,7 +163,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): friendly_name="LR Right RYSE Shade Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-00:00:00:00:00:00-3-64", + unique_id="00:00:00:00:00:00_3_64", unit_of_measurement=PERCENTAGE, state="100", ), @@ -182,7 +182,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): EntityTestInfo( entity_id="cover.br_left_ryse_shade", friendly_name="BR Left RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-4-48", + unique_id="00:00:00:00:00:00_4_48", supported_features=RYSE_SUPPORTED_FEATURES, state="open", ), @@ -191,7 +191,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): friendly_name="BR Left RYSE Shade Battery", entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-00:00:00:00:00:00-4-64", + unique_id="00:00:00:00:00:00_4_64", unit_of_measurement=PERCENTAGE, state="100", ), @@ -210,7 +210,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): EntityTestInfo( entity_id="cover.rzss_ryse_shade", friendly_name="RZSS RYSE Shade", - unique_id="homekit-00:00:00:00:00:00-5-48", + unique_id="00:00:00:00:00:00_5_48", supported_features=RYSE_SUPPORTED_FEATURES, state="open", ), @@ -219,7 +219,7 @@ async def test_ryse_smart_bridge_four_shades_setup(hass): entity_category=EntityCategory.DIAGNOSTIC, capabilities={"state_class": SensorStateClass.MEASUREMENT}, friendly_name="RZSS RYSE Shade Battery", - unique_id="homekit-00:00:00:00:00:00-5-64", + unique_id="00:00:00:00:00:00_5_64", unit_of_measurement=PERCENTAGE, state="0", ), diff --git a/tests/components/homekit_controller/specific_devices/test_schlage_sense.py b/tests/components/homekit_controller/specific_devices/test_schlage_sense.py index 0a59ec6f70a..e1b55f6bd88 100644 --- a/tests/components/homekit_controller/specific_devices/test_schlage_sense.py +++ b/tests/components/homekit_controller/specific_devices/test_schlage_sense.py @@ -31,7 +31,7 @@ async def test_schlage_sense_setup(hass): EntityTestInfo( entity_id="lock.sense_lock_mechanism", friendly_name="SENSE Lock Mechanism", - unique_id="homekit-AAAAAAA000-30", + unique_id="00:00:00:00:00:00_1_30", supported_features=0, state="unknown", ), diff --git a/tests/components/homekit_controller/specific_devices/test_simpleconnect_fan.py b/tests/components/homekit_controller/specific_devices/test_simpleconnect_fan.py index ba24bdeef96..9a5edeb45b2 100644 --- a/tests/components/homekit_controller/specific_devices/test_simpleconnect_fan.py +++ b/tests/components/homekit_controller/specific_devices/test_simpleconnect_fan.py @@ -36,7 +36,7 @@ async def test_simpleconnect_fan_setup(hass): EntityTestInfo( entity_id="fan.simpleconnect_fan_06f674_hunter_fan", friendly_name="SIMPLEconnect Fan-06F674 Hunter Fan", - unique_id="homekit-1234567890abcd-8", + unique_id="00:00:00:00:00:00_1_8", supported_features=FanEntityFeature.DIRECTION | FanEntityFeature.SET_SPEED, capabilities={ diff --git a/tests/components/homekit_controller/specific_devices/test_velux_gateway.py b/tests/components/homekit_controller/specific_devices/test_velux_gateway.py index 8a5102e0a87..a82d995d4d1 100644 --- a/tests/components/homekit_controller/specific_devices/test_velux_gateway.py +++ b/tests/components/homekit_controller/specific_devices/test_velux_gateway.py @@ -51,7 +51,7 @@ async def test_velux_cover_setup(hass): EntityTestInfo( entity_id="cover.velux_window_roof_window", friendly_name="VELUX Window Roof Window", - unique_id="homekit-1111111a114a111a-8", + unique_id="00:00:00:00:00:00_3_8", supported_features=CoverEntityFeature.CLOSE | CoverEntityFeature.SET_POSITION | CoverEntityFeature.OPEN, @@ -73,7 +73,7 @@ async def test_velux_cover_setup(hass): entity_id="sensor.velux_sensor_temperature_sensor", friendly_name="VELUX Sensor Temperature sensor", capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-a11b111-8", + unique_id="00:00:00:00:00:00_2_8", unit_of_measurement=TEMP_CELSIUS, state="18.9", ), @@ -81,7 +81,7 @@ async def test_velux_cover_setup(hass): entity_id="sensor.velux_sensor_humidity_sensor", friendly_name="VELUX Sensor Humidity sensor", capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-a11b111-11", + unique_id="00:00:00:00:00:00_2_11", unit_of_measurement=PERCENTAGE, state="58", ), @@ -89,7 +89,7 @@ async def test_velux_cover_setup(hass): entity_id="sensor.velux_sensor_carbon_dioxide_sensor", friendly_name="VELUX Sensor Carbon Dioxide sensor", capabilities={"state_class": SensorStateClass.MEASUREMENT}, - unique_id="homekit-a11b111-14", + unique_id="00:00:00:00:00:00_2_14", unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION, state="400", ), 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 7c3262f3098..b07a10cf17d 100644 --- a/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py +++ b/tests/components/homekit_controller/specific_devices/test_vocolinc_flowerbud.py @@ -36,7 +36,7 @@ async def test_vocolinc_flowerbud_setup(hass): EntityTestInfo( entity_id="humidifier.vocolinc_flowerbud_0d324b", friendly_name="VOCOlinc-Flowerbud-0d324b", - unique_id="homekit-AM01121849000327-30", + unique_id="00:00:00:00:00:00_1_30", supported_features=HumidifierEntityFeature.MODES, capabilities={ "available_modes": ["normal", "auto"], @@ -48,7 +48,7 @@ async def test_vocolinc_flowerbud_setup(hass): EntityTestInfo( entity_id="light.vocolinc_flowerbud_0d324b_mood_light", friendly_name="VOCOlinc-Flowerbud-0d324b Mood Light", - unique_id="homekit-AM01121849000327-9", + unique_id="00:00:00:00:00:00_1_9", supported_features=0, capabilities={"supported_color_modes": ["hs"]}, state="on", @@ -56,7 +56,7 @@ async def test_vocolinc_flowerbud_setup(hass): EntityTestInfo( entity_id="number.vocolinc_flowerbud_0d324b_spray_quantity", friendly_name="VOCOlinc-Flowerbud-0d324b Spray Quantity", - unique_id="homekit-AM01121849000327-aid:1-sid:30-cid:38", + unique_id="00:00:00:00:00:00_1_30_38", capabilities={ "max": 5, "min": 1, @@ -69,7 +69,7 @@ async def test_vocolinc_flowerbud_setup(hass): EntityTestInfo( entity_id="sensor.vocolinc_flowerbud_0d324b_current_humidity", friendly_name="VOCOlinc-Flowerbud-0d324b Current Humidity", - unique_id="homekit-AM01121849000327-aid:1-sid:30-cid:33", + unique_id="00:00:00:00:00:00_1_30_33", capabilities={"state_class": SensorStateClass.MEASUREMENT}, unit_of_measurement=PERCENTAGE, state="45.0", diff --git a/tests/components/homekit_controller/specific_devices/test_vocolinc_vp3.py b/tests/components/homekit_controller/specific_devices/test_vocolinc_vp3.py index 4037a44898e..7ced8979c8a 100644 --- a/tests/components/homekit_controller/specific_devices/test_vocolinc_vp3.py +++ b/tests/components/homekit_controller/specific_devices/test_vocolinc_vp3.py @@ -2,6 +2,7 @@ from homeassistant.components.sensor import SensorStateClass from homeassistant.const import POWER_WATT +from homeassistant.helpers import entity_registry as er from ..common import ( HUB_TEST_ACCESSORY_ID, @@ -15,6 +16,21 @@ from ..common import ( async def test_vocolinc_vp3_setup(hass): """Test that a VOCOlinc VP3 can be correctly setup in HA.""" + + entity_registry = er.async_get(hass) + outlet = entity_registry.async_get_or_create( + "switch", + "homekit_controller", + "homekit-EU0121203xxxxx07-48", + suggested_object_id="original_vocolinc_vp3_outlet", + ) + sensor = entity_registry.async_get_or_create( + "sensor", + "homekit_controller", + "homekit-EU0121203xxxxx07-aid:1-sid:48-cid:97", + suggested_object_id="original_vocolinc_vp3_power", + ) + accessories = await setup_accessories_from_file(hass, "vocolinc_vp3.json") await setup_test_accessories(hass, accessories) @@ -31,15 +47,15 @@ async def test_vocolinc_vp3_setup(hass): devices=[], entities=[ EntityTestInfo( - entity_id="switch.vocolinc_vp3_123456_outlet", + entity_id="switch.original_vocolinc_vp3_outlet", friendly_name="VOCOlinc-VP3-123456 Outlet", - unique_id="homekit-EU0121203xxxxx07-48", + unique_id="00:00:00:00:00:00_1_48", state="on", ), EntityTestInfo( - entity_id="sensor.vocolinc_vp3_123456_power", + entity_id="sensor.original_vocolinc_vp3_power", friendly_name="VOCOlinc-VP3-123456 Power", - unique_id="homekit-EU0121203xxxxx07-aid:1-sid:48-cid:97", + unique_id="00:00:00:00:00:00_1_48_97", unit_of_measurement=POWER_WATT, capabilities={"state_class": SensorStateClass.MEASUREMENT}, state="0", @@ -47,3 +63,12 @@ async def test_vocolinc_vp3_setup(hass): ], ), ) + + assert ( + entity_registry.async_get(outlet.entity_id).unique_id + == "00:00:00:00:00:00_1_48" + ) + assert ( + entity_registry.async_get(sensor.entity_id).unique_id + == "00:00:00:00:00:00_1_48_97" + ) diff --git a/tests/components/homekit_controller/test_alarm_control_panel.py b/tests/components/homekit_controller/test_alarm_control_panel.py index 46979bd41f3..2c2ff92ccb6 100644 --- a/tests/components/homekit_controller/test_alarm_control_panel.py +++ b/tests/components/homekit_controller/test_alarm_control_panel.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_security_system_service(accessory): @@ -119,3 +121,20 @@ async def test_switch_read_alarm_state(hass, utcnow): ) state = await helper.poll_and_get_state() assert state.state == "triggered" + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a alarm_control_panel unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + alarm_control_panel_entry = entity_registry.async_get_or_create( + "alarm_control_panel", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_security_system_service) + + assert ( + entity_registry.async_get(alarm_control_panel_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_binary_sensor.py b/tests/components/homekit_controller/test_binary_sensor.py index e9cd9284332..7e926910da1 100644 --- a/tests/components/homekit_controller/test_binary_sensor.py +++ b/tests/components/homekit_controller/test_binary_sensor.py @@ -3,8 +3,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes from homeassistant.components.binary_sensor import BinarySensorDeviceClass +from homeassistant.helpers import entity_registry as er -from .common import setup_test_component +from .common import get_next_aid, setup_test_component def create_motion_sensor_service(accessory): @@ -169,3 +170,20 @@ async def test_leak_sensor_read_state(hass, utcnow): assert state.state == "on" assert state.attributes["device_class"] == BinarySensorDeviceClass.MOISTURE + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a binary_sensor unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + binary_sensor_entry = entity_registry.async_get_or_create( + "binary_sensor", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_leak_sensor_service) + + assert ( + entity_registry.async_get(binary_sensor_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_button.py b/tests/components/homekit_controller/test_button.py index 58c1feb8900..77551668ea5 100644 --- a/tests/components/homekit_controller/test_button.py +++ b/tests/components/homekit_controller/test_button.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import Helper, setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import Helper, get_next_aid, setup_test_component def create_switch_with_setup_button(accessory): @@ -89,3 +91,19 @@ async def test_ecobee_clear_hold_press_button(hass): CharacteristicsTypes.VENDOR_ECOBEE_CLEAR_HOLD: True, }, ) + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a button unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + button_entry = entity_registry.async_get_or_create( + "button", + "homekit_controller", + f"homekit-0001-aid:{aid}-sid:1-cid:2", + ) + await setup_test_component(hass, create_switch_with_ecobee_clear_hold_button) + assert ( + entity_registry.async_get(button_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_1_2" + ) diff --git a/tests/components/homekit_controller/test_camera.py b/tests/components/homekit_controller/test_camera.py index e0ba609b30e..f4207ca4ca9 100644 --- a/tests/components/homekit_controller/test_camera.py +++ b/tests/components/homekit_controller/test_camera.py @@ -5,8 +5,9 @@ from aiohomekit.model.services import ServicesTypes from aiohomekit.testing import FAKE_CAMERA_IMAGE from homeassistant.components import camera +from homeassistant.helpers import entity_registry as er -from .common import setup_test_component +from .common import get_next_aid, setup_test_component def create_camera(accessory): @@ -14,6 +15,22 @@ def create_camera(accessory): accessory.add_service(ServicesTypes.CAMERA_RTP_STREAM_MANAGEMENT) +async def test_migrate_unique_ids(hass, utcnow): + """Test migrating entity unique ids.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + camera = entity_registry.async_get_or_create( + "camera", + "homekit_controller", + f"homekit-0001-aid:{aid}", + ) + await setup_test_component(hass, create_camera) + assert ( + entity_registry.async_get(camera.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}" + ) + + async def test_read_state(hass, utcnow): """Test reading the state of a HomeKit camera.""" helper = await setup_test_component(hass, create_camera) diff --git a/tests/components/homekit_controller/test_climate.py b/tests/components/homekit_controller/test_climate.py index 0f669c9c51f..0f10f0f9fa0 100644 --- a/tests/components/homekit_controller/test_climate.py +++ b/tests/components/homekit_controller/test_climate.py @@ -17,8 +17,9 @@ from homeassistant.components.climate import ( SERVICE_SET_TEMPERATURE, HVACMode, ) +from homeassistant.helpers import entity_registry as er -from .common import setup_test_component +from .common import get_next_aid, setup_test_component # Test thermostat devices @@ -943,3 +944,19 @@ async def test_heater_cooler_turn_off(hass, utcnow): state = await helper.poll_and_get_state() assert state.state == "off" assert state.attributes["hvac_action"] == "off" + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a switch unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + climate_entry = entity_registry.async_get_or_create( + "climate", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_heater_cooler_service) + assert ( + entity_registry.async_get(climate_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_connection.py b/tests/components/homekit_controller/test_connection.py index 9db07a45d16..b853989ab15 100644 --- a/tests/components/homekit_controller/test_connection.py +++ b/tests/components/homekit_controller/test_connection.py @@ -9,7 +9,6 @@ from homeassistant.components.homekit_controller.const import ( IDENTIFIER_ACCESSORY_ID, IDENTIFIER_LEGACY_ACCESSORY_ID, IDENTIFIER_LEGACY_SERIAL_NUMBER, - IDENTIFIER_SERIAL_NUMBER, ) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr @@ -36,7 +35,6 @@ DEVICE_MIGRATION_TESTS = [ manufacturer="RYSE Inc.", before={ (DOMAIN, IDENTIFIER_LEGACY_ACCESSORY_ID, "00:00:00:00:00:00"), - (DOMAIN, IDENTIFIER_LEGACY_SERIAL_NUMBER, "0401.3521.0679"), }, after={(IDENTIFIER_ACCESSORY_ID, "00:00:00:00:00:00:aid:1")}, ), @@ -55,11 +53,9 @@ DEVICE_MIGRATION_TESTS = [ manufacturer="Philips Lighting", before={ (DOMAIN, IDENTIFIER_LEGACY_ACCESSORY_ID, "00:00:00:00:00:00"), - (DOMAIN, IDENTIFIER_LEGACY_SERIAL_NUMBER, "123456"), }, after={ (IDENTIFIER_ACCESSORY_ID, "00:00:00:00:00:00:aid:1"), - (IDENTIFIER_SERIAL_NUMBER, "123456"), }, ), # Test migrating a Hue remote - it has a valid serial number @@ -72,7 +68,6 @@ DEVICE_MIGRATION_TESTS = [ }, after={ (IDENTIFIER_ACCESSORY_ID, "00:00:00:00:00:00:aid:6623462389072572"), - (IDENTIFIER_SERIAL_NUMBER, "6623462389072572"), }, ), # Test migrating a Koogeek LS1. This is just for completeness (testing hub and hub-less devices) @@ -85,7 +80,6 @@ DEVICE_MIGRATION_TESTS = [ }, after={ (IDENTIFIER_ACCESSORY_ID, "00:00:00:00:00:00:aid:1"), - (IDENTIFIER_SERIAL_NUMBER, "AAAA011111111111"), }, ), ] diff --git a/tests/components/homekit_controller/test_cover.py b/tests/components/homekit_controller/test_cover.py index 15422f2f0bc..6ceb57f5e09 100644 --- a/tests/components/homekit_controller/test_cover.py +++ b/tests/components/homekit_controller/test_cover.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_window_covering_service(accessory): @@ -277,3 +279,20 @@ async def test_read_door_state(hass, utcnow): ) state = await helper.poll_and_get_state() assert state.attributes["obstruction-detected"] is True + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a cover unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + cover_entry = entity_registry.async_get_or_create( + "cover", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_garage_door_opener_service) + + assert ( + entity_registry.async_get(cover_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_fan.py b/tests/components/homekit_controller/test_fan.py index de13772b5a1..855f426da13 100644 --- a/tests/components/homekit_controller/test_fan.py +++ b/tests/components/homekit_controller/test_fan.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_fan_service(accessory): @@ -805,3 +807,20 @@ async def test_v2_set_percentage_non_standard_rotation_range(hass, utcnow): CharacteristicsTypes.ACTIVE: 0, }, ) + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a fan unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + fan_entry = entity_registry.async_get_or_create( + "fan", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_fanv2_service_non_standard_rotation_range) + + assert ( + entity_registry.async_get(fan_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_humidifier.py b/tests/components/homekit_controller/test_humidifier.py index da981e9eac0..1128459c4a6 100644 --- a/tests/components/homekit_controller/test_humidifier.py +++ b/tests/components/homekit_controller/test_humidifier.py @@ -3,8 +3,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes from homeassistant.components.humidifier import DOMAIN, MODE_AUTO, MODE_NORMAL +from homeassistant.helpers import entity_registry as er -from .common import setup_test_component +from .common import get_next_aid, setup_test_component def create_humidifier_service(accessory): @@ -436,3 +437,20 @@ async def test_dehumidifier_target_humidity_modes(hass, utcnow): ) assert state.attributes["mode"] == "normal" assert state.attributes["humidity"] == 73 + + +async def test_migrate_entity_ids(hass, utcnow): + """Test that we can migrate humidifier entity ids.""" + aid = get_next_aid() + + entity_registry = er.async_get(hass) + humidifier_entry = entity_registry.async_get_or_create( + "humidifier", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_humidifier_service) + assert ( + entity_registry.async_get(humidifier_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_light.py b/tests/components/homekit_controller/test_light.py index 726be15a32c..31604f2b1dd 100644 --- a/tests/components/homekit_controller/test_light.py +++ b/tests/components/homekit_controller/test_light.py @@ -9,8 +9,9 @@ from homeassistant.components.light import ( ColorMode, ) from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_UNAVAILABLE +from homeassistant.helpers import entity_registry as er -from .common import setup_test_component +from .common import get_next_aid, setup_test_component LIGHT_BULB_NAME = "TestDevice" LIGHT_BULB_ENTITY_ID = "light.testdevice" @@ -335,3 +336,47 @@ async def test_light_unloaded_removed(hass, utcnow): # Make sure entity is removed assert hass.states.get(helper.entity_id).state == STATE_UNAVAILABLE + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a light unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + light_entry = entity_registry.async_get_or_create( + "light", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_lightbulb_service_with_color_temp) + + assert ( + entity_registry.async_get(light_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) + + +async def test_only_migrate_once(hass, utcnow): + """Test a we handle migration happening after an upgrade and than a downgrade and then an upgrade.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + old_light_entry = entity_registry.async_get_or_create( + "light", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + new_light_entry = entity_registry.async_get_or_create( + "light", + "homekit_controller", + f"00:00:00:00:00:00_{aid}_8", + ) + await setup_test_component(hass, create_lightbulb_service_with_color_temp) + + assert ( + entity_registry.async_get(old_light_entry.entity_id).unique_id + == f"homekit-00:00:00:00:00:00-{aid}-8" + ) + + assert ( + entity_registry.async_get(new_light_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_lock.py b/tests/components/homekit_controller/test_lock.py index af21f26a012..719ff66c766 100644 --- a/tests/components/homekit_controller/test_lock.py +++ b/tests/components/homekit_controller/test_lock.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_lock_service(accessory): @@ -112,3 +114,20 @@ async def test_switch_read_lock_state(hass, utcnow): ) state = await helper.poll_and_get_state() assert state.state == "unlocking" + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a lock unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + lock_entry = entity_registry.async_get_or_create( + "lock", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_lock_service) + + assert ( + entity_registry.async_get(lock_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_media_player.py b/tests/components/homekit_controller/test_media_player.py index 7fb8c4edb2a..829f28cf341 100644 --- a/tests/components/homekit_controller/test_media_player.py +++ b/tests/components/homekit_controller/test_media_player.py @@ -6,7 +6,9 @@ from aiohomekit.model.characteristics import ( from aiohomekit.model.services import ServicesTypes import pytest -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_tv_service(accessory): @@ -364,3 +366,20 @@ async def test_tv_set_source_fail(hass, utcnow): state = await helper.poll_and_get_state() assert state.attributes["source"] == "HDMI 1" + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a media_player unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + media_player_entry = entity_registry.async_get_or_create( + "media_player", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + await setup_test_component(hass, create_tv_service_with_target_media_state) + + assert ( + entity_registry.async_get(media_player_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) diff --git a/tests/components/homekit_controller/test_number.py b/tests/components/homekit_controller/test_number.py index 6d060416861..cc6950e0f90 100644 --- a/tests/components/homekit_controller/test_number.py +++ b/tests/components/homekit_controller/test_number.py @@ -2,7 +2,9 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import Helper, setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import Helper, get_next_aid, setup_test_component def create_switch_with_spray_level(accessory): @@ -26,6 +28,24 @@ def create_switch_with_spray_level(accessory): return service +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a number unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + number = entity_registry.async_get_or_create( + "number", + "homekit_controller", + f"homekit-0001-aid:{aid}-sid:8-cid:9", + suggested_object_id="testdevice_spray_quantity", + ) + await setup_test_component(hass, create_switch_with_spray_level) + + assert ( + entity_registry.async_get(number.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8_9" + ) + + async def test_read_number(hass, utcnow): """Test a switch service that has a sensor characteristic is correctly handled.""" helper = await setup_test_component(hass, create_switch_with_spray_level) diff --git a/tests/components/homekit_controller/test_select.py b/tests/components/homekit_controller/test_select.py index 22cd53d7a31..d18f0b97ecc 100644 --- a/tests/components/homekit_controller/test_select.py +++ b/tests/components/homekit_controller/test_select.py @@ -3,7 +3,9 @@ from aiohomekit.model import Accessory from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes -from .common import Helper, setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import Helper, get_next_aid, setup_test_component def create_service_with_ecobee_mode(accessory: Accessory): @@ -19,6 +21,25 @@ def create_service_with_ecobee_mode(accessory: Accessory): return service +async def test_migrate_unique_id(hass, utcnow): + """Test we can migrate a select unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + select = entity_registry.async_get_or_create( + "select", + "homekit_controller", + f"homekit-0001-aid:{aid}-sid:8-cid:14", + suggested_object_id="testdevice_current_mode", + ) + + await setup_test_component(hass, create_service_with_ecobee_mode) + + assert ( + entity_registry.async_get(select.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8_14" + ) + + async def test_read_current_mode(hass, utcnow): """Test that Ecobee mode can be correctly read and show as human readable text.""" helper = await setup_test_component(hass, create_service_with_ecobee_mode) diff --git a/tests/components/homekit_controller/test_sensor.py b/tests/components/homekit_controller/test_sensor.py index 4bd6612026c..b769a916082 100644 --- a/tests/components/homekit_controller/test_sensor.py +++ b/tests/components/homekit_controller/test_sensor.py @@ -13,6 +13,7 @@ from homeassistant.components.homekit_controller.sensor import ( thread_status_to_str, ) from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass +from homeassistant.helpers import entity_registry as er from .common import TEST_DEVICE_SERVICE_INFO, Helper, setup_test_component @@ -361,7 +362,6 @@ async def test_rssi_sensor( hass, utcnow, entity_registry_enabled_by_default, enable_bluetooth ): """Test an rssi sensor.""" - inject_bluetooth_service_info(hass, TEST_DEVICE_SERVICE_INFO) class FakeBLEPairing(FakePairing): @@ -378,3 +378,38 @@ async def test_rssi_sensor( hass, create_battery_level_sensor, suffix="battery", connection="BLE" ) assert hass.states.get("sensor.testdevice_signal_strength").state == "-56" + + +async def test_migrate_rssi_sensor_unique_id( + hass, utcnow, entity_registry_enabled_by_default, enable_bluetooth +): + """Test an rssi sensor unique id migration.""" + entity_registry = er.async_get(hass) + rssi_sensor = entity_registry.async_get_or_create( + "sensor", + "homekit_controller", + "homekit-0001-rssi", + suggested_object_id="renamed_rssi", + ) + + inject_bluetooth_service_info(hass, TEST_DEVICE_SERVICE_INFO) + + class FakeBLEPairing(FakePairing): + """Fake BLE pairing.""" + + @property + def transport(self): + return Transport.BLE + + with patch("aiohomekit.testing.FakePairing", FakeBLEPairing): + # Any accessory will do for this test, but we need at least + # one or the rssi sensor will not be created + await setup_test_component( + hass, create_battery_level_sensor, suffix="battery", connection="BLE" + ) + assert hass.states.get("sensor.renamed_rssi").state == "-56" + + assert ( + entity_registry.async_get(rssi_sensor.entity_id).unique_id + == "00:00:00:00:00:00_rssi" + ) diff --git a/tests/components/homekit_controller/test_switch.py b/tests/components/homekit_controller/test_switch.py index a034624bd60..1e9b1cab730 100644 --- a/tests/components/homekit_controller/test_switch.py +++ b/tests/components/homekit_controller/test_switch.py @@ -7,7 +7,9 @@ from aiohomekit.model.characteristics import ( ) from aiohomekit.model.services import ServicesTypes -from .common import setup_test_component +from homeassistant.helpers import entity_registry as er + +from .common import get_next_aid, setup_test_component def create_switch_service(accessory): @@ -215,3 +217,30 @@ async def test_char_switch_read_state(hass, utcnow): {CharacteristicsTypes.VENDOR_AQARA_PAIRING_MODE: False}, ) assert switch_1.state == "off" + + +async def test_migrate_unique_id(hass, utcnow): + """Test a we can migrate a switch unique id.""" + entity_registry = er.async_get(hass) + aid = get_next_aid() + switch_entry = entity_registry.async_get_or_create( + "switch", + "homekit_controller", + f"homekit-00:00:00:00:00:00-{aid}-8", + ) + switch_entry_2 = entity_registry.async_get_or_create( + "switch", + "homekit_controller", + f"homekit-0001-aid:{aid}-sid:8-cid:9", + ) + await setup_test_component(hass, create_char_switch_service, suffix="pairing_mode") + + assert ( + entity_registry.async_get(switch_entry.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8" + ) + + assert ( + entity_registry.async_get(switch_entry_2.entity_id).unique_id + == f"00:00:00:00:00:00_{aid}_8_9" + )