From 3acb5054560e496e4285478b87b54b041c2faa66 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 25 Mar 2024 02:28:56 -1000 Subject: [PATCH] Refactor homekit device linking to use the device index (#114145) Now that we have an index of devices in the entity registry we can avoid generating a lookup for devices we do not care about --- homeassistant/components/homekit/__init__.py | 104 +++++++++---------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index 51b3f5f376d..b00631c2249 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -803,18 +803,10 @@ class HomeKit: """Configure accessories for the included states.""" dev_reg = dr.async_get(self.hass) ent_reg = er.async_get(self.hass) - device_lookup = ent_reg.async_get_device_class_lookup( - { - (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING), - (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.MOTION), - (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.OCCUPANCY), - (SENSOR_DOMAIN, SensorDeviceClass.BATTERY), - (SENSOR_DOMAIN, SensorDeviceClass.HUMIDITY), - } - ) - + device_lookup: dict[str, dict[tuple[str, str | None], str]] = {} entity_states: list[State] = [] entity_filter = self._filter.get_filter() + entries = ent_reg.entities for state in self.hass.states.async_all(): entity_id = state.entity_id if not entity_filter(entity_id): @@ -830,7 +822,18 @@ class HomeKit: await self._async_set_device_info_attributes( ent_reg_ent, dev_reg, entity_id ) - self._async_configure_linked_sensors(ent_reg_ent, device_lookup, state) + if device_id := ent_reg_ent.device_id: + if device_id not in device_lookup: + device_lookup[device_id] = { + ( + entry.domain, + entry.device_class or entry.original_device_class, + ): entry.entity_id + for entry in entries.get_entries_for_device_id(device_id) + } + self._async_configure_linked_sensors( + ent_reg_ent, device_lookup[device_id], state + ) entity_states.append(state) @@ -1073,64 +1076,59 @@ class HomeKit: def _async_configure_linked_sensors( self, ent_reg_ent: er.RegistryEntry, - device_lookup: dict[str, dict[tuple[str, str | None], str]], + device_lookup: dict[tuple[str, str | None], str], state: State, ) -> None: - if ( - ent_reg_ent is None - or ent_reg_ent.device_id is None - or ent_reg_ent.device_id not in device_lookup - or (ent_reg_ent.device_class or ent_reg_ent.original_device_class) - in (BinarySensorDeviceClass.BATTERY_CHARGING, SensorDeviceClass.BATTERY) + if (ent_reg_ent.device_class or ent_reg_ent.original_device_class) in ( + BinarySensorDeviceClass.BATTERY_CHARGING, + SensorDeviceClass.BATTERY, ): return - if ATTR_BATTERY_CHARGING not in state.attributes: - battery_charging_binary_sensor_entity_id = device_lookup[ - ent_reg_ent.device_id - ].get((BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING)) - if battery_charging_binary_sensor_entity_id: - self._config.setdefault(state.entity_id, {}).setdefault( - CONF_LINKED_BATTERY_CHARGING_SENSOR, - battery_charging_binary_sensor_entity_id, - ) + domain = state.domain + attributes = state.attributes - if ATTR_BATTERY_LEVEL not in state.attributes: - battery_sensor_entity_id = device_lookup[ent_reg_ent.device_id].get( + if ATTR_BATTERY_CHARGING not in attributes and ( + battery_charging_binary_sensor_entity_id := device_lookup.get( + (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING) + ) + ): + self._config.setdefault(state.entity_id, {}).setdefault( + CONF_LINKED_BATTERY_CHARGING_SENSOR, + battery_charging_binary_sensor_entity_id, + ) + + if ATTR_BATTERY_LEVEL not in attributes and ( + battery_sensor_entity_id := device_lookup.get( (SENSOR_DOMAIN, SensorDeviceClass.BATTERY) ) - if battery_sensor_entity_id: - self._config.setdefault(state.entity_id, {}).setdefault( - CONF_LINKED_BATTERY_SENSOR, battery_sensor_entity_id - ) + ): + self._config.setdefault(state.entity_id, {}).setdefault( + CONF_LINKED_BATTERY_SENSOR, battery_sensor_entity_id + ) - if state.entity_id.startswith(f"{CAMERA_DOMAIN}."): - motion_binary_sensor_entity_id = device_lookup[ent_reg_ent.device_id].get( + if domain == CAMERA_DOMAIN: + if motion_binary_sensor_entity_id := device_lookup.get( (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.MOTION) - ) - if motion_binary_sensor_entity_id: + ): self._config.setdefault(state.entity_id, {}).setdefault( - CONF_LINKED_MOTION_SENSOR, - motion_binary_sensor_entity_id, + CONF_LINKED_MOTION_SENSOR, motion_binary_sensor_entity_id ) - doorbell_binary_sensor_entity_id = device_lookup[ent_reg_ent.device_id].get( + if doorbell_binary_sensor_entity_id := device_lookup.get( (BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.OCCUPANCY) - ) - if doorbell_binary_sensor_entity_id: + ): self._config.setdefault(state.entity_id, {}).setdefault( - CONF_LINKED_DOORBELL_SENSOR, - doorbell_binary_sensor_entity_id, + CONF_LINKED_DOORBELL_SENSOR, doorbell_binary_sensor_entity_id ) - if state.entity_id.startswith(f"{HUMIDIFIER_DOMAIN}."): - current_humidity_sensor_entity_id = device_lookup[ - ent_reg_ent.device_id - ].get((SENSOR_DOMAIN, SensorDeviceClass.HUMIDITY)) - if current_humidity_sensor_entity_id: - self._config.setdefault(state.entity_id, {}).setdefault( - CONF_LINKED_HUMIDITY_SENSOR, - current_humidity_sensor_entity_id, - ) + if domain == HUMIDIFIER_DOMAIN and ( + current_humidity_sensor_entity_id := device_lookup.get( + (SENSOR_DOMAIN, SensorDeviceClass.HUMIDITY) + ) + ): + self._config.setdefault(state.entity_id, {}).setdefault( + CONF_LINKED_HUMIDITY_SENSOR, current_humidity_sensor_entity_id + ) async def _async_set_device_info_attributes( self,