From c580bce879b6c2f68c4ea45707b5a05ee88c6ecc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" <nick@koston.org> Date: Sat, 6 Aug 2022 08:10:26 -1000 Subject: [PATCH] Move HKC entity classes into entity.py (#76333) --- .../components/homekit_controller/__init__.py | 198 +---------------- .../homekit_controller/alarm_control_panel.py | 3 +- .../homekit_controller/binary_sensor.py | 3 +- .../components/homekit_controller/button.py | 3 +- .../components/homekit_controller/camera.py | 3 +- .../components/homekit_controller/climate.py | 3 +- .../components/homekit_controller/cover.py | 3 +- .../components/homekit_controller/entity.py | 203 ++++++++++++++++++ .../components/homekit_controller/fan.py | 3 +- .../homekit_controller/humidifier.py | 3 +- .../components/homekit_controller/light.py | 3 +- .../components/homekit_controller/lock.py | 3 +- .../homekit_controller/media_player.py | 3 +- .../components/homekit_controller/number.py | 3 +- .../components/homekit_controller/select.py | 3 +- .../components/homekit_controller/sensor.py | 3 +- .../components/homekit_controller/switch.py | 3 +- 17 files changed, 235 insertions(+), 211 deletions(-) create mode 100644 homeassistant/components/homekit_controller/entity.py diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index b2ccad9a457..3a5ba42848c 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -3,7 +3,6 @@ from __future__ import annotations import asyncio import logging -from typing import Any import aiohomekit from aiohomekit.exceptions import ( @@ -11,216 +10,23 @@ from aiohomekit.exceptions import ( AccessoryNotFoundError, EncryptionError, ) -from aiohomekit.model import Accessory -from aiohomekit.model.characteristics import ( - Characteristic, - CharacteristicPermissions, - CharacteristicsTypes, -) -from aiohomekit.model.services import Service, ServicesTypes from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_IDENTIFIERS, EVENT_HOMEASSISTANT_STOP from homeassistant.core import Event, HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr -from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.entity import DeviceInfo, Entity from homeassistant.helpers.typing import ConfigType from .config_flow import normalize_hkid -from .connection import HKDevice, valid_serial_number +from .connection import HKDevice from .const import ENTITY_MAP, KNOWN_DEVICES, TRIGGERS from .storage import EntityMapStorage, async_get_entity_storage -from .utils import async_get_controller, folded_name +from .utils import async_get_controller _LOGGER = logging.getLogger(__name__) -class HomeKitEntity(Entity): - """Representation of a Home Assistant HomeKit device.""" - - _attr_should_poll = False - - def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None: - """Initialise a generic HomeKit device.""" - self._accessory = accessory - self._aid = devinfo["aid"] - self._iid = devinfo["iid"] - self._char_name: str | None = None - self._features = 0 - self.setup() - - super().__init__() - - @property - def accessory(self) -> Accessory: - """Return an Accessory model that this entity is attached to.""" - return self._accessory.entity_map.aid(self._aid) - - @property - def accessory_info(self) -> Service: - """Information about the make and model of an accessory.""" - return self.accessory.services.first( - service_type=ServicesTypes.ACCESSORY_INFORMATION - ) - - @property - def service(self) -> Service: - """Return a Service model that this entity is attached to.""" - return self.accessory.services.iid(self._iid) - - async def async_added_to_hass(self) -> None: - """Entity added to hass.""" - self.async_on_remove( - async_dispatcher_connect( - self.hass, - self._accessory.signal_state_updated, - self.async_write_ha_state, - ) - ) - - self._accessory.add_pollable_characteristics(self.pollable_characteristics) - await self._accessory.add_watchable_characteristics( - self.watchable_characteristics - ) - - async def async_will_remove_from_hass(self) -> None: - """Prepare to be removed from hass.""" - self._accessory.remove_pollable_characteristics(self._aid) - self._accessory.remove_watchable_characteristics(self._aid) - - async def async_put_characteristics(self, characteristics: dict[str, Any]) -> None: - """ - Write characteristics to the device. - - A characteristic type is unique within a service, but in order to write - to a named characteristic on a bridge we need to turn its type into - an aid and iid, and send it as a list of tuples, which is what this - helper does. - - E.g. you can do: - - await entity.async_put_characteristics({ - CharacteristicsTypes.ON: True - }) - """ - payload = self.service.build_update(characteristics) - return await self._accessory.put_characteristics(payload) - - def setup(self) -> None: - """Configure an entity based on its HomeKit characteristics metadata.""" - self.pollable_characteristics: list[tuple[int, int]] = [] - self.watchable_characteristics: list[tuple[int, int]] = [] - - char_types = self.get_characteristic_types() - - # Setup events and/or polling for characteristics directly attached to this entity - for char in self.service.characteristics.filter(char_types=char_types): - self._setup_characteristic(char) - - # Setup events and/or polling for characteristics attached to sub-services of this - # entity (like an INPUT_SOURCE). - for service in self.accessory.services.filter(parent_service=self.service): - for char in service.characteristics.filter(char_types=char_types): - self._setup_characteristic(char) - - def _setup_characteristic(self, char: Characteristic) -> None: - """Configure an entity based on a HomeKit characteristics metadata.""" - # Build up a list of (aid, iid) tuples to poll on update() - if CharacteristicPermissions.paired_read in char.perms: - self.pollable_characteristics.append((self._aid, char.iid)) - - # Build up a list of (aid, iid) tuples to subscribe to - if CharacteristicPermissions.events in char.perms: - self.watchable_characteristics.append((self._aid, char.iid)) - - if self._char_name is None: - self._char_name = char.service.value(CharacteristicsTypes.NAME) - - @property - def unique_id(self) -> str: - """Return the ID of this device.""" - info = self.accessory_info - serial = info.value(CharacteristicsTypes.SERIAL_NUMBER) - if valid_serial_number(serial): - return f"homekit-{serial}-{self._iid}" - # Some accessories do not have a serial number - return f"homekit-{self._accessory.unique_id}-{self._aid}-{self._iid}" - - @property - def default_name(self) -> str | None: - """Return the default name of the device.""" - return None - - @property - def name(self) -> str | None: - """Return the name of the device if any.""" - 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: - # Sometimes the device name includes the accessory - # name already like My ecobee Occupancy / My ecobee - if folded_device_name.startswith(folded_accessory_name): - return device_name - if ( - folded_accessory_name not in folded_device_name - and folded_device_name not in folded_accessory_name - ): - return f"{accessory_name} {device_name}" - return accessory_name - - @property - def available(self) -> bool: - """Return True if entity is available.""" - return self._accessory.available and self.service.available - - @property - def device_info(self) -> DeviceInfo: - """Return the device info.""" - return self._accessory.device_info_for_accessory(self.accessory) - - def get_characteristic_types(self) -> list[str]: - """Define the homekit characteristics the entity cares about.""" - raise NotImplementedError - - -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.""" - serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) - return f"homekit-{serial}-aid:{self._aid}" - - -class CharacteristicEntity(HomeKitEntity): - """ - A HomeKit entity that is related to an single characteristic rather than a whole service. - - This is typically used to expose additional sensor, binary_sensor or number entities that don't belong with - the service entity. - """ - - def __init__( - self, accessory: HKDevice, devinfo: ConfigType, char: Characteristic - ) -> None: - """Initialise a generic single characteristic HomeKit entity.""" - self._char = char - super().__init__(accessory, devinfo) - - @property - def unique_id(self) -> str: - """Return the 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}" - - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up a HomeKit connection on a config entry.""" conn = HKDevice(hass, entry, entry.data) diff --git a/homeassistant/components/homekit_controller/alarm_control_panel.py b/homeassistant/components/homekit_controller/alarm_control_panel.py index c7e499b6e89..204fa1bb3f8 100644 --- a/homeassistant/components/homekit_controller/alarm_control_panel.py +++ b/homeassistant/components/homekit_controller/alarm_control_panel.py @@ -22,7 +22,8 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity ICON = "mdi:security" diff --git a/homeassistant/components/homekit_controller/binary_sensor.py b/homeassistant/components/homekit_controller/binary_sensor.py index 5efd0915cb0..11c81e7e251 100644 --- a/homeassistant/components/homekit_controller/binary_sensor.py +++ b/homeassistant/components/homekit_controller/binary_sensor.py @@ -12,7 +12,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity class HomeKitMotionSensor(HomeKitEntity, BinarySensorEntity): diff --git a/homeassistant/components/homekit_controller/button.py b/homeassistant/components/homekit_controller/button.py index e9c85dbe876..d5a8bc733ad 100644 --- a/homeassistant/components/homekit_controller/button.py +++ b/homeassistant/components/homekit_controller/button.py @@ -21,8 +21,9 @@ from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType -from . import KNOWN_DEVICES, CharacteristicEntity +from . import KNOWN_DEVICES from .connection import HKDevice +from .entity import CharacteristicEntity @dataclass diff --git a/homeassistant/components/homekit_controller/camera.py b/homeassistant/components/homekit_controller/camera.py index 0f0dd4f9050..510c0c2f522 100644 --- a/homeassistant/components/homekit_controller/camera.py +++ b/homeassistant/components/homekit_controller/camera.py @@ -9,7 +9,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, AccessoryEntity +from . import KNOWN_DEVICES +from .entity import AccessoryEntity class HomeKitCamera(AccessoryEntity, Camera): diff --git a/homeassistant/components/homekit_controller/climate.py b/homeassistant/components/homekit_controller/climate.py index b76ed1ea6a9..7254363e835 100644 --- a/homeassistant/components/homekit_controller/climate.py +++ b/homeassistant/components/homekit_controller/climate.py @@ -38,7 +38,8 @@ from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index 4e8af03bba0..6cbc623596e 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -18,7 +18,8 @@ from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_O from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity STATE_STOPPED = "stopped" diff --git a/homeassistant/components/homekit_controller/entity.py b/homeassistant/components/homekit_controller/entity.py new file mode 100644 index 00000000000..ad99e65f2d8 --- /dev/null +++ b/homeassistant/components/homekit_controller/entity.py @@ -0,0 +1,203 @@ +"""Homekit Controller entities.""" +from __future__ import annotations + +from typing import Any + +from aiohomekit.model import Accessory +from aiohomekit.model.characteristics import ( + Characteristic, + CharacteristicPermissions, + CharacteristicsTypes, +) +from aiohomekit.model.services import Service, ServicesTypes + +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity import DeviceInfo, Entity +from homeassistant.helpers.typing import ConfigType + +from .connection import HKDevice, valid_serial_number +from .utils import folded_name + + +class HomeKitEntity(Entity): + """Representation of a Home Assistant HomeKit device.""" + + _attr_should_poll = False + + def __init__(self, accessory: HKDevice, devinfo: ConfigType) -> None: + """Initialise a generic HomeKit device.""" + self._accessory = accessory + self._aid = devinfo["aid"] + self._iid = devinfo["iid"] + self._char_name: str | None = None + self._features = 0 + self.setup() + + super().__init__() + + @property + def accessory(self) -> Accessory: + """Return an Accessory model that this entity is attached to.""" + return self._accessory.entity_map.aid(self._aid) + + @property + def accessory_info(self) -> Service: + """Information about the make and model of an accessory.""" + return self.accessory.services.first( + service_type=ServicesTypes.ACCESSORY_INFORMATION + ) + + @property + def service(self) -> Service: + """Return a Service model that this entity is attached to.""" + return self.accessory.services.iid(self._iid) + + async def async_added_to_hass(self) -> None: + """Entity added to hass.""" + self.async_on_remove( + async_dispatcher_connect( + self.hass, + self._accessory.signal_state_updated, + self.async_write_ha_state, + ) + ) + + self._accessory.add_pollable_characteristics(self.pollable_characteristics) + await self._accessory.add_watchable_characteristics( + self.watchable_characteristics + ) + + async def async_will_remove_from_hass(self) -> None: + """Prepare to be removed from hass.""" + self._accessory.remove_pollable_characteristics(self._aid) + self._accessory.remove_watchable_characteristics(self._aid) + + async def async_put_characteristics(self, characteristics: dict[str, Any]) -> None: + """ + Write characteristics to the device. + + A characteristic type is unique within a service, but in order to write + to a named characteristic on a bridge we need to turn its type into + an aid and iid, and send it as a list of tuples, which is what this + helper does. + + E.g. you can do: + + await entity.async_put_characteristics({ + CharacteristicsTypes.ON: True + }) + """ + payload = self.service.build_update(characteristics) + return await self._accessory.put_characteristics(payload) + + def setup(self) -> None: + """Configure an entity based on its HomeKit characteristics metadata.""" + self.pollable_characteristics: list[tuple[int, int]] = [] + self.watchable_characteristics: list[tuple[int, int]] = [] + + char_types = self.get_characteristic_types() + + # Setup events and/or polling for characteristics directly attached to this entity + for char in self.service.characteristics.filter(char_types=char_types): + self._setup_characteristic(char) + + # Setup events and/or polling for characteristics attached to sub-services of this + # entity (like an INPUT_SOURCE). + for service in self.accessory.services.filter(parent_service=self.service): + for char in service.characteristics.filter(char_types=char_types): + self._setup_characteristic(char) + + def _setup_characteristic(self, char: Characteristic) -> None: + """Configure an entity based on a HomeKit characteristics metadata.""" + # Build up a list of (aid, iid) tuples to poll on update() + if CharacteristicPermissions.paired_read in char.perms: + self.pollable_characteristics.append((self._aid, char.iid)) + + # Build up a list of (aid, iid) tuples to subscribe to + if CharacteristicPermissions.events in char.perms: + self.watchable_characteristics.append((self._aid, char.iid)) + + if self._char_name is None: + self._char_name = char.service.value(CharacteristicsTypes.NAME) + + @property + def unique_id(self) -> str: + """Return the ID of this device.""" + info = self.accessory_info + serial = info.value(CharacteristicsTypes.SERIAL_NUMBER) + if valid_serial_number(serial): + return f"homekit-{serial}-{self._iid}" + # Some accessories do not have a serial number + return f"homekit-{self._accessory.unique_id}-{self._aid}-{self._iid}" + + @property + def default_name(self) -> str | None: + """Return the default name of the device.""" + return None + + @property + def name(self) -> str | None: + """Return the name of the device if any.""" + 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: + # Sometimes the device name includes the accessory + # name already like My ecobee Occupancy / My ecobee + if folded_device_name.startswith(folded_accessory_name): + return device_name + if ( + folded_accessory_name not in folded_device_name + and folded_device_name not in folded_accessory_name + ): + return f"{accessory_name} {device_name}" + return accessory_name + + @property + def available(self) -> bool: + """Return True if entity is available.""" + return self._accessory.available and self.service.available + + @property + def device_info(self) -> DeviceInfo: + """Return the device info.""" + return self._accessory.device_info_for_accessory(self.accessory) + + def get_characteristic_types(self) -> list[str]: + """Define the homekit characteristics the entity cares about.""" + raise NotImplementedError + + +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.""" + serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER) + return f"homekit-{serial}-aid:{self._aid}" + + +class CharacteristicEntity(HomeKitEntity): + """ + A HomeKit entity that is related to an single characteristic rather than a whole service. + + This is typically used to expose additional sensor, binary_sensor or number entities that don't belong with + the service entity. + """ + + def __init__( + self, accessory: HKDevice, devinfo: ConfigType, char: Characteristic + ) -> None: + """Initialise a generic single characteristic HomeKit entity.""" + self._char = char + super().__init__(accessory, devinfo) + + @property + def unique_id(self) -> str: + """Return the 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}" diff --git a/homeassistant/components/homekit_controller/fan.py b/homeassistant/components/homekit_controller/fan.py index 159a1d936fa..03f4dade674 100644 --- a/homeassistant/components/homekit_controller/fan.py +++ b/homeassistant/components/homekit_controller/fan.py @@ -20,7 +20,8 @@ from homeassistant.util.percentage import ( ranged_value_to_percentage, ) -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity # 0 is clockwise, 1 is counter-clockwise. The match to forward and reverse is so that # its consistent with homeassistant.components.homekit. diff --git a/homeassistant/components/homekit_controller/humidifier.py b/homeassistant/components/homekit_controller/humidifier.py index 1676999ad78..ebba525e0c9 100644 --- a/homeassistant/components/homekit_controller/humidifier.py +++ b/homeassistant/components/homekit_controller/humidifier.py @@ -21,7 +21,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity HK_MODE_TO_HA = { 0: "off", diff --git a/homeassistant/components/homekit_controller/light.py b/homeassistant/components/homekit_controller/light.py index d882f6790f7..010411c60d0 100644 --- a/homeassistant/components/homekit_controller/light.py +++ b/homeassistant/components/homekit_controller/light.py @@ -17,7 +17,8 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity async def async_setup_entry( diff --git a/homeassistant/components/homekit_controller/lock.py b/homeassistant/components/homekit_controller/lock.py index 248bb93a68f..8e8919ae4f8 100644 --- a/homeassistant/components/homekit_controller/lock.py +++ b/homeassistant/components/homekit_controller/lock.py @@ -17,7 +17,8 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity CURRENT_STATE_MAP = { 0: STATE_UNLOCKED, diff --git a/homeassistant/components/homekit_controller/media_player.py b/homeassistant/components/homekit_controller/media_player.py index fbdf800edf8..092652ed17d 100644 --- a/homeassistant/components/homekit_controller/media_player.py +++ b/homeassistant/components/homekit_controller/media_player.py @@ -28,7 +28,8 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, HomeKitEntity +from . import KNOWN_DEVICES +from .entity import HomeKitEntity _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/homekit_controller/number.py b/homeassistant/components/homekit_controller/number.py index 7a6d0a01ab6..2987c82e829 100644 --- a/homeassistant/components/homekit_controller/number.py +++ b/homeassistant/components/homekit_controller/number.py @@ -20,8 +20,9 @@ from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType -from . import KNOWN_DEVICES, CharacteristicEntity +from . import KNOWN_DEVICES from .connection import HKDevice +from .entity import CharacteristicEntity NUMBER_ENTITIES: dict[str, NumberEntityDescription] = { CharacteristicsTypes.VENDOR_VOCOLINC_HUMIDIFIER_SPRAY_LEVEL: NumberEntityDescription( diff --git a/homeassistant/components/homekit_controller/select.py b/homeassistant/components/homekit_controller/select.py index 681f24b9ab8..a22f79d675b 100644 --- a/homeassistant/components/homekit_controller/select.py +++ b/homeassistant/components/homekit_controller/select.py @@ -8,8 +8,9 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import KNOWN_DEVICES, CharacteristicEntity +from . import KNOWN_DEVICES from .const import DEVICE_CLASS_ECOBEE_MODE +from .entity import CharacteristicEntity _ECOBEE_MODE_TO_TEXT = { 0: "home", diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index a6810c10d99..04856a60347 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -32,8 +32,9 @@ from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType -from . import KNOWN_DEVICES, CharacteristicEntity, HomeKitEntity +from . import KNOWN_DEVICES from .connection import HKDevice +from .entity import CharacteristicEntity, HomeKitEntity from .utils import folded_name diff --git a/homeassistant/components/homekit_controller/switch.py b/homeassistant/components/homekit_controller/switch.py index be6c3b8bfe0..c537233de7e 100644 --- a/homeassistant/components/homekit_controller/switch.py +++ b/homeassistant/components/homekit_controller/switch.py @@ -19,8 +19,9 @@ from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType -from . import KNOWN_DEVICES, CharacteristicEntity, HomeKitEntity +from . import KNOWN_DEVICES from .connection import HKDevice +from .entity import CharacteristicEntity, HomeKitEntity OUTLET_IN_USE = "outlet_in_use" -- GitLab