Migrate HomeKit Controller to use stable identifiers (#80064)

pull/80147/head
J. Nick Koston 2022-10-11 11:26:03 -10:00 committed by GitHub
parent e3a3f93441
commit f23b1750e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 781 additions and 234 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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}"

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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",
),
],

View File

@ -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",
),

View File

@ -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,

View File

@ -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"]},

View File

@ -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",
),
],

View File

@ -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"

View File

@ -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,
),

View File

@ -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",
),
],

View File

@ -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,

View File

@ -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",

View File

@ -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",
),

View File

@ -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

View File

@ -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",
)

View File

@ -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",
),

View File

@ -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",

View File

@ -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",

View File

@ -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
),

View File

@ -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
),

View File

@ -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,

View File

@ -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,
),
],

View File

@ -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,
),

View File

@ -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",

View File

@ -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",
),

View File

@ -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",
),
],

View File

@ -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",
),
],

View File

@ -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",
),
],

View File

@ -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",
),

View File

@ -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",
),

View File

@ -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={

View File

@ -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",
),

View File

@ -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",

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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)

View File

@ -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"
)

View File

@ -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"),
},
),
]

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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)

View File

@ -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)

View File

@ -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"
)

View File

@ -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"
)