From 3014a651c34e5873db3a1b6ccfc7add98696d0ab Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 19 Oct 2023 20:50:07 -1000 Subject: [PATCH] Reduce overhead to write HomeKit Controller state (#102365) --- .../homekit_controller/connection.py | 3 +- .../components/homekit_controller/entity.py | 37 +++++++++---------- .../homekit_controller/humidifier.py | 11 +++--- .../components/homekit_controller/sensor.py | 10 ++--- .../components/homekit_controller/utils.py | 2 + 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 48bc3822001..923dfd8f96b 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -437,9 +437,10 @@ class HKDevice: @callback def async_migrate_unique_id( - self, old_unique_id: str, new_unique_id: str, platform: str + self, old_unique_id: str, new_unique_id: str | None, platform: str ) -> None: """Migrate legacy unique IDs to new format.""" + assert new_unique_id is not None _LOGGER.debug( "Checking if unique ID %s on %s needs to be migrated", old_unique_id, diff --git a/homeassistant/components/homekit_controller/entity.py b/homeassistant/components/homekit_controller/entity.py index 5bf46eb44ce..7511f95e283 100644 --- a/homeassistant/components/homekit_controller/entity.py +++ b/homeassistant/components/homekit_controller/entity.py @@ -42,6 +42,7 @@ class HomeKitEntity(Entity): self._char_name: str | None = None self._char_subscription: CALLBACK_TYPE | None = None self.async_setup() + self._attr_unique_id = f"{accessory.unique_id}_{self._aid}_{self._iid}" super().__init__() @callback @@ -190,11 +191,6 @@ 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.""" @@ -206,10 +202,9 @@ class HomeKitEntity(Entity): accessory_name = self.accessory.name # If the service has a name char, use that, if not # fallback to the default name provided by the subclass - device_name = self._char_name or self.default_name - folded_device_name = folded_name(device_name or "") - folded_accessory_name = folded_name(accessory_name) - if device_name: + if device_name := self._char_name or self.default_name: + folded_device_name = folded_name(device_name) + folded_accessory_name = folded_name(accessory_name) # Sometimes the device name includes the accessory # name already like My ecobee Occupancy / My ecobee if folded_device_name.startswith(folded_accessory_name): @@ -243,17 +238,17 @@ class HomeKitEntity(Entity): class AccessoryEntity(HomeKitEntity): """A HomeKit entity that is related to an entire accessory rather than a specific service or characteristic.""" + def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None: + """Initialise a generic HomeKit accessory.""" + super().__init__(accessory, devinfo) + self._attr_unique_id = f"{accessory.unique_id}_{self._aid}" + @property 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 BaseCharacteristicEntity(HomeKitEntity): """A HomeKit entity that is related to an single characteristic rather than a whole service. @@ -299,13 +294,17 @@ class CharacteristicEntity(BaseCharacteristicEntity): the service entity. """ + def __init__( + self, accessory: HKDevice, devinfo: ConfigType, char: Characteristic + ) -> None: + """Initialise a generic single characteristic HomeKit entity.""" + super().__init__(accessory, devinfo, char) + self._attr_unique_id = ( + f"{accessory.unique_id}_{self._aid}_{char.service.iid}_{char.iid}" + ) + @property 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/humidifier.py b/homeassistant/components/homekit_controller/humidifier.py index cd2cf4022e7..57e4e7e73d8 100644 --- a/homeassistant/components/homekit_controller/humidifier.py +++ b/homeassistant/components/homekit_controller/humidifier.py @@ -19,6 +19,7 @@ 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.helpers.typing import ConfigType from . import KNOWN_DEVICES from .connection import HKDevice @@ -152,6 +153,11 @@ class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity): _attr_device_class = HumidifierDeviceClass.DEHUMIDIFIER _attr_supported_features = HumidifierEntityFeature.MODES + def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None: + """Initialise the dehumidifier.""" + super().__init__(accessory, devinfo) + self._attr_unique_id = f"{accessory.unique_id}_{self._iid}_{self.device_class}" + def get_characteristic_types(self) -> list[str]: """Define the homekit characteristics the entity cares about.""" return [ @@ -260,11 +266,6 @@ class HomeKitDehumidifier(HomeKitEntity, HumidifierEntity): 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, diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index 1f17d32f912..2d30de24650 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -581,6 +581,11 @@ class RSSISensor(HomeKitEntity, SensorEntity): _attr_native_unit_of_measurement = SIGNAL_STRENGTH_DECIBELS_MILLIWATT _attr_should_poll = False + def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None: + """Initialise a HomeKit Controller RSSI sensor.""" + super().__init__(accessory, devinfo) + self._attr_unique_id = f"{accessory.unique_id}_rssi" + def get_characteristic_types(self) -> list[str]: """Define the homekit characteristics the entity cares about.""" return [] @@ -602,11 +607,6 @@ class RSSISensor(HomeKitEntity, SensorEntity): 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.""" diff --git a/homeassistant/components/homekit_controller/utils.py b/homeassistant/components/homekit_controller/utils.py index b43f1ee05f7..33a08504724 100644 --- a/homeassistant/components/homekit_controller/utils.py +++ b/homeassistant/components/homekit_controller/utils.py @@ -1,4 +1,5 @@ """Helper functions for the homekit_controller component.""" +from functools import lru_cache from typing import cast from aiohomekit import Controller @@ -11,6 +12,7 @@ from .const import CONTROLLER from .storage import async_get_entity_storage +@lru_cache def folded_name(name: str) -> str: """Return a name that is used for matching a similar string.""" return name.casefold().replace(" ", "")