From 57a910a1443b764330303bda13a439175112ceac Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 24 Jun 2023 22:12:36 -0500 Subject: [PATCH] Relocate esphome entity code into its own module (#95092) --- homeassistant/components/esphome/__init__.py | 287 +--------------- .../components/esphome/alarm_control_panel.py | 6 +- .../components/esphome/binary_sensor.py | 6 +- homeassistant/components/esphome/button.py | 5 +- homeassistant/components/esphome/camera.py | 5 +- homeassistant/components/esphome/climate.py | 6 +- homeassistant/components/esphome/cover.py | 6 +- homeassistant/components/esphome/entity.py | 310 ++++++++++++++++++ homeassistant/components/esphome/fan.py | 6 +- homeassistant/components/esphome/light.py | 6 +- homeassistant/components/esphome/lock.py | 6 +- .../components/esphome/media_player.py | 6 +- homeassistant/components/esphome/number.py | 6 +- homeassistant/components/esphome/select.py | 4 +- homeassistant/components/esphome/sensor.py | 6 +- homeassistant/components/esphome/switch.py | 6 +- 16 files changed, 376 insertions(+), 301 deletions(-) create mode 100644 homeassistant/components/esphome/entity.py diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 0c962d82074..fdf0092389b 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -1,20 +1,14 @@ """Support for esphome devices.""" from __future__ import annotations -from collections.abc import Callable -import functools import logging -import math -from typing import Any, Generic, NamedTuple, TypeVar, cast +from typing import Any, NamedTuple, TypeVar from aioesphomeapi import ( APIClient, APIConnectionError, APIVersion, DeviceInfo as EsphomeDeviceInfo, - EntityCategory as EsphomeEntityCategory, - EntityInfo, - EntityState, HomeassistantServiceCall, InvalidAuthAPIError, InvalidEncryptionKeyAPIError, @@ -36,7 +30,6 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_PORT, EVENT_HOMEASSISTANT_STOP, - EntityCategory, __version__ as ha_version, ) from homeassistant.core import Event, HomeAssistant, ServiceCall, State, callback @@ -45,12 +38,6 @@ from homeassistant.helpers import template import homeassistant.helpers.config_validation as cv import homeassistant.helpers.device_registry as dr from homeassistant.helpers.device_registry import format_mac -from homeassistant.helpers.dispatcher import ( - async_dispatcher_connect, - async_dispatcher_send, -) -from homeassistant.helpers.entity import DeviceInfo, Entity -from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_state_change_event from homeassistant.helpers.issue_registry import ( IssueSeverity, @@ -68,7 +55,6 @@ from .domain_data import DomainData # Import config flow so that it's added to the registry from .entry_data import RuntimeEntryData -from .enum_mapper import EsphomeEnumMapper from .voice_assistant import VoiceAssistantUDPServer CONF_DEVICE_NAME = "device_name" @@ -669,274 +655,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: """Remove an esphome config entry.""" await DomainData.get(hass).get_or_create_store(hass, entry).async_remove() - - -_InfoT = TypeVar("_InfoT", bound=EntityInfo) -_EntityT = TypeVar("_EntityT", bound="EsphomeEntity[Any,Any]") -_StateT = TypeVar("_StateT", bound=EntityState) - - -async def platform_async_setup_entry( - hass: HomeAssistant, - entry: ConfigEntry, - async_add_entities: AddEntitiesCallback, - *, - component_key: str, - info_type: type[_InfoT], - entity_type: type[_EntityT], - state_type: type[_StateT], -) -> None: - """Set up an esphome platform. - - This method is in charge of receiving, distributing and storing - info and state updates. - """ - entry_data: RuntimeEntryData = DomainData.get(hass).get_entry_data(entry) - entry_data.info[component_key] = {} - entry_data.old_info[component_key] = {} - entry_data.state.setdefault(state_type, {}) - - @callback - def async_list_entities(infos: list[EntityInfo]) -> None: - """Update entities of this platform when entities are listed.""" - old_infos = entry_data.info[component_key] - new_infos: dict[int, EntityInfo] = {} - add_entities: list[_EntityT] = [] - for info in infos: - if info.key in old_infos: - # Update existing entity - old_infos.pop(info.key) - else: - # Create new entity - entity = entity_type(entry_data, component_key, info, state_type) - add_entities.append(entity) - new_infos[info.key] = info - - # Remove old entities - for info in old_infos.values(): - entry_data.async_remove_entity(hass, component_key, info.key) - - # First copy the now-old info into the backup object - entry_data.old_info[component_key] = entry_data.info[component_key] - # Then update the actual info - entry_data.info[component_key] = new_infos - - for key, new_info in new_infos.items(): - async_dispatcher_send( - hass, - entry_data.signal_component_key_static_info_updated(component_key, key), - new_info, - ) - - if add_entities: - # Add entities to Home Assistant - async_add_entities(add_entities) - - entry_data.cleanup_callbacks.append( - entry_data.async_register_static_info_callback(info_type, async_list_entities) - ) - - -def esphome_state_property( - func: Callable[[_EntityT], _R] -) -> Callable[[_EntityT], _R | None]: - """Wrap a state property of an esphome entity. - - This checks if the state object in the entity is set, and - prevents writing NAN values to the Home Assistant state machine. - """ - - @functools.wraps(func) - def _wrapper(self: _EntityT) -> _R | None: - # pylint: disable-next=protected-access - if not self._has_state: - return None - val = func(self) - if isinstance(val, float) and math.isnan(val): - # Home Assistant doesn't use NAN values in state machine - # (not JSON serializable) - return None - return val - - return _wrapper - - -ICON_SCHEMA = vol.Schema(cv.icon) - - -ENTITY_CATEGORIES: EsphomeEnumMapper[ - EsphomeEntityCategory, EntityCategory | None -] = EsphomeEnumMapper( - { - EsphomeEntityCategory.NONE: None, - EsphomeEntityCategory.CONFIG: EntityCategory.CONFIG, - EsphomeEntityCategory.DIAGNOSTIC: EntityCategory.DIAGNOSTIC, - } -) - - -class EsphomeEntity(Entity, Generic[_InfoT, _StateT]): - """Define a base esphome entity.""" - - _attr_should_poll = False - _static_info: _InfoT - _state: _StateT - _has_state: bool - - def __init__( - self, - entry_data: RuntimeEntryData, - component_key: str, - entity_info: EntityInfo, - state_type: type[_StateT], - ) -> None: - """Initialize.""" - self._entry_data = entry_data - self._on_entry_data_changed() - self._component_key = component_key - self._key = entity_info.key - self._state_type = state_type - self._on_static_info_update(entity_info) - assert entry_data.device_info is not None - device_info = entry_data.device_info - self._device_info = device_info - self._attr_has_entity_name = bool(device_info.friendly_name) - self._attr_device_info = DeviceInfo( - connections={(dr.CONNECTION_NETWORK_MAC, device_info.mac_address)} - ) - self._entry_id = entry_data.entry_id - - async def async_added_to_hass(self) -> None: - """Register callbacks.""" - entry_data = self._entry_data - hass = self.hass - component_key = self._component_key - key = self._key - - self.async_on_remove( - async_dispatcher_connect( - hass, - f"esphome_{self._entry_id}_remove_{component_key}_{key}", - functools.partial(self.async_remove, force_remove=True), - ) - ) - self.async_on_remove( - async_dispatcher_connect( - hass, - entry_data.signal_device_updated, - self._on_device_update, - ) - ) - self.async_on_remove( - entry_data.async_subscribe_state_update( - self._state_type, key, self._on_state_update - ) - ) - self.async_on_remove( - async_dispatcher_connect( - hass, - entry_data.signal_component_key_static_info_updated(component_key, key), - self._on_static_info_update, - ) - ) - self._update_state_from_entry_data() - - @callback - def _on_static_info_update(self, static_info: EntityInfo) -> None: - """Save the static info for this entity when it changes. - - This method can be overridden in child classes to know - when the static info changes. - """ - static_info = cast(_InfoT, static_info) - self._static_info = static_info - self._attr_unique_id = static_info.unique_id - self._attr_entity_registry_enabled_default = not static_info.disabled_by_default - self._attr_name = static_info.name - if entity_category := static_info.entity_category: - self._attr_entity_category = ENTITY_CATEGORIES.from_esphome(entity_category) - else: - self._attr_entity_category = None - if icon := static_info.icon: - self._attr_icon = cast(str, ICON_SCHEMA(icon)) - else: - self._attr_icon = None - - @callback - def _update_state_from_entry_data(self) -> None: - """Update state from entry data.""" - - state = self._entry_data.state - key = self._key - state_type = self._state_type - has_state = key in state[state_type] - if has_state: - self._state = cast(_StateT, state[state_type][key]) - self._has_state = has_state - - @callback - def _on_state_update(self) -> None: - """Call when state changed. - - Behavior can be changed in child classes - """ - self._update_state_from_entry_data() - self.async_write_ha_state() - - @callback - def _on_entry_data_changed(self) -> None: - entry_data = self._entry_data - self._api_version = entry_data.api_version - self._client = entry_data.client - - @callback - def _on_device_update(self) -> None: - """Call when device updates or entry data changes.""" - self._on_entry_data_changed() - if not self._entry_data.available: - # Only write state if the device has gone unavailable - # since _on_state_update will be called if the device - # is available when the full state arrives - # through the next entity state packet. - self.async_write_ha_state() - - @property - def available(self) -> bool: - """Return if the entity is available.""" - if self._device_info.has_deep_sleep: - # During deep sleep the ESP will not be connectable (by design) - # For these cases, show it as available - return True - - return self._entry_data.available - - -class EsphomeAssistEntity(Entity): - """Define a base entity for Assist Pipeline entities.""" - - _attr_has_entity_name = True - _attr_should_poll = False - - def __init__(self, entry_data: RuntimeEntryData) -> None: - """Initialize the binary sensor.""" - self._entry_data: RuntimeEntryData = entry_data - assert entry_data.device_info is not None - device_info = entry_data.device_info - self._device_info = device_info - self._attr_unique_id = ( - f"{device_info.mac_address}-{self.entity_description.key}" - ) - self._attr_device_info = DeviceInfo( - connections={(dr.CONNECTION_NETWORK_MAC, device_info.mac_address)} - ) - - @callback - def _update(self) -> None: - self.async_write_ha_state() - - async def async_added_to_hass(self) -> None: - """Register update callback.""" - await super().async_added_to_hass() - self.async_on_remove( - self._entry_data.async_subscribe_assist_pipeline_update(self._update) - ) diff --git a/homeassistant/components/esphome/alarm_control_panel.py b/homeassistant/components/esphome/alarm_control_panel.py index efa95dda710..6fadd7d4408 100644 --- a/homeassistant/components/esphome/alarm_control_panel.py +++ b/homeassistant/components/esphome/alarm_control_panel.py @@ -30,7 +30,11 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, EsphomeEnumMapper, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + platform_async_setup_entry, +) +from .enum_mapper import EsphomeEnumMapper _ESPHOME_ACP_STATE_TO_HASS_STATE: EsphomeEnumMapper[ AlarmControlPanelState, str diff --git a/homeassistant/components/esphome/binary_sensor.py b/homeassistant/components/esphome/binary_sensor.py index 81ffee1a380..a755bcf10ef 100644 --- a/homeassistant/components/esphome/binary_sensor.py +++ b/homeassistant/components/esphome/binary_sensor.py @@ -13,8 +13,12 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.enum import try_parse_enum -from . import EsphomeAssistEntity, EsphomeEntity, platform_async_setup_entry from .domain_data import DomainData +from .entity import ( + EsphomeAssistEntity, + EsphomeEntity, + platform_async_setup_entry, +) async def async_setup_entry( diff --git a/homeassistant/components/esphome/button.py b/homeassistant/components/esphome/button.py index 4b2f02b266d..71bb7017c55 100644 --- a/homeassistant/components/esphome/button.py +++ b/homeassistant/components/esphome/button.py @@ -9,7 +9,10 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.enum import try_parse_enum -from . import EsphomeEntity, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + platform_async_setup_entry, +) async def async_setup_entry( diff --git a/homeassistant/components/esphome/camera.py b/homeassistant/components/esphome/camera.py index 390208f689d..17f73f7c770 100644 --- a/homeassistant/components/esphome/camera.py +++ b/homeassistant/components/esphome/camera.py @@ -13,7 +13,10 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + platform_async_setup_entry, +) async def async_setup_entry( diff --git a/homeassistant/components/esphome/climate.py b/homeassistant/components/esphome/climate.py index b01e89ec2c8..5c252e888d9 100644 --- a/homeassistant/components/esphome/climate.py +++ b/homeassistant/components/esphome/climate.py @@ -54,7 +54,11 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) from .enum_mapper import EsphomeEnumMapper FAN_QUIET = "quiet" diff --git a/homeassistant/components/esphome/cover.py b/homeassistant/components/esphome/cover.py index 4fb9924613d..347ff98e689 100644 --- a/homeassistant/components/esphome/cover.py +++ b/homeassistant/components/esphome/cover.py @@ -17,7 +17,11 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.enum import try_parse_enum -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) async def async_setup_entry( diff --git a/homeassistant/components/esphome/entity.py b/homeassistant/components/esphome/entity.py new file mode 100644 index 00000000000..18bf15ce4ee --- /dev/null +++ b/homeassistant/components/esphome/entity.py @@ -0,0 +1,310 @@ +"""Support for esphome entities.""" +from __future__ import annotations + +from collections.abc import Callable +import functools +import math +from typing import ( # pylint: disable=unused-import + Any, + Generic, + TypeVar, + cast, +) + +from aioesphomeapi import ( + EntityCategory as EsphomeEntityCategory, + EntityInfo, + EntityState, +) +import voluptuous as vol + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + EntityCategory, +) +from homeassistant.core import HomeAssistant, callback +import homeassistant.helpers.config_validation as cv +import homeassistant.helpers.device_registry as dr +from homeassistant.helpers.dispatcher import ( + async_dispatcher_connect, + async_dispatcher_send, +) +from homeassistant.helpers.entity import DeviceInfo, Entity +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .domain_data import DomainData + +# Import config flow so that it's added to the registry +from .entry_data import RuntimeEntryData +from .enum_mapper import EsphomeEnumMapper + +_R = TypeVar("_R") +_InfoT = TypeVar("_InfoT", bound=EntityInfo) +_EntityT = TypeVar("_EntityT", bound="EsphomeEntity[Any,Any]") +_StateT = TypeVar("_StateT", bound=EntityState) + + +async def platform_async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, + *, + component_key: str, + info_type: type[_InfoT], + entity_type: type[_EntityT], + state_type: type[_StateT], +) -> None: + """Set up an esphome platform. + + This method is in charge of receiving, distributing and storing + info and state updates. + """ + entry_data: RuntimeEntryData = DomainData.get(hass).get_entry_data(entry) + entry_data.info[component_key] = {} + entry_data.old_info[component_key] = {} + entry_data.state.setdefault(state_type, {}) + + @callback + def async_list_entities(infos: list[EntityInfo]) -> None: + """Update entities of this platform when entities are listed.""" + old_infos = entry_data.info[component_key] + new_infos: dict[int, EntityInfo] = {} + add_entities: list[_EntityT] = [] + for info in infos: + if info.key in old_infos: + # Update existing entity + old_infos.pop(info.key) + else: + # Create new entity + entity = entity_type(entry_data, component_key, info, state_type) + add_entities.append(entity) + new_infos[info.key] = info + + # Remove old entities + for info in old_infos.values(): + entry_data.async_remove_entity(hass, component_key, info.key) + + # First copy the now-old info into the backup object + entry_data.old_info[component_key] = entry_data.info[component_key] + # Then update the actual info + entry_data.info[component_key] = new_infos + + for key, new_info in new_infos.items(): + async_dispatcher_send( + hass, + entry_data.signal_component_key_static_info_updated(component_key, key), + new_info, + ) + + if add_entities: + # Add entities to Home Assistant + async_add_entities(add_entities) + + entry_data.cleanup_callbacks.append( + entry_data.async_register_static_info_callback(info_type, async_list_entities) + ) + + +def esphome_state_property( + func: Callable[[_EntityT], _R] +) -> Callable[[_EntityT], _R | None]: + """Wrap a state property of an esphome entity. + + This checks if the state object in the entity is set, and + prevents writing NAN values to the Home Assistant state machine. + """ + + @functools.wraps(func) + def _wrapper(self: _EntityT) -> _R | None: + # pylint: disable-next=protected-access + if not self._has_state: + return None + val = func(self) + if isinstance(val, float) and math.isnan(val): + # Home Assistant doesn't use NAN values in state machine + # (not JSON serializable) + return None + return val + + return _wrapper + + +ICON_SCHEMA = vol.Schema(cv.icon) + + +ENTITY_CATEGORIES: EsphomeEnumMapper[ + EsphomeEntityCategory, EntityCategory | None +] = EsphomeEnumMapper( + { + EsphomeEntityCategory.NONE: None, + EsphomeEntityCategory.CONFIG: EntityCategory.CONFIG, + EsphomeEntityCategory.DIAGNOSTIC: EntityCategory.DIAGNOSTIC, + } +) + + +class EsphomeEntity(Entity, Generic[_InfoT, _StateT]): + """Define a base esphome entity.""" + + _attr_should_poll = False + _static_info: _InfoT + _state: _StateT + _has_state: bool + + def __init__( + self, + entry_data: RuntimeEntryData, + component_key: str, + entity_info: EntityInfo, + state_type: type[_StateT], + ) -> None: + """Initialize.""" + self._entry_data = entry_data + self._on_entry_data_changed() + self._component_key = component_key + self._key = entity_info.key + self._state_type = state_type + self._on_static_info_update(entity_info) + assert entry_data.device_info is not None + device_info = entry_data.device_info + self._device_info = device_info + self._attr_has_entity_name = bool(device_info.friendly_name) + self._attr_device_info = DeviceInfo( + connections={(dr.CONNECTION_NETWORK_MAC, device_info.mac_address)} + ) + self._entry_id = entry_data.entry_id + + async def async_added_to_hass(self) -> None: + """Register callbacks.""" + entry_data = self._entry_data + hass = self.hass + component_key = self._component_key + key = self._key + + self.async_on_remove( + async_dispatcher_connect( + hass, + f"esphome_{self._entry_id}_remove_{component_key}_{key}", + functools.partial(self.async_remove, force_remove=True), + ) + ) + self.async_on_remove( + async_dispatcher_connect( + hass, + entry_data.signal_device_updated, + self._on_device_update, + ) + ) + self.async_on_remove( + entry_data.async_subscribe_state_update( + self._state_type, key, self._on_state_update + ) + ) + self.async_on_remove( + async_dispatcher_connect( + hass, + entry_data.signal_component_key_static_info_updated(component_key, key), + self._on_static_info_update, + ) + ) + self._update_state_from_entry_data() + + @callback + def _on_static_info_update(self, static_info: EntityInfo) -> None: + """Save the static info for this entity when it changes. + + This method can be overridden in child classes to know + when the static info changes. + """ + static_info = cast(_InfoT, static_info) + self._static_info = static_info + self._attr_unique_id = static_info.unique_id + self._attr_entity_registry_enabled_default = not static_info.disabled_by_default + self._attr_name = static_info.name + if entity_category := static_info.entity_category: + self._attr_entity_category = ENTITY_CATEGORIES.from_esphome(entity_category) + else: + self._attr_entity_category = None + if icon := static_info.icon: + self._attr_icon = cast(str, ICON_SCHEMA(icon)) + else: + self._attr_icon = None + + @callback + def _update_state_from_entry_data(self) -> None: + """Update state from entry data.""" + + state = self._entry_data.state + key = self._key + state_type = self._state_type + has_state = key in state[state_type] + if has_state: + self._state = cast(_StateT, state[state_type][key]) + self._has_state = has_state + + @callback + def _on_state_update(self) -> None: + """Call when state changed. + + Behavior can be changed in child classes + """ + self._update_state_from_entry_data() + self.async_write_ha_state() + + @callback + def _on_entry_data_changed(self) -> None: + entry_data = self._entry_data + self._api_version = entry_data.api_version + self._client = entry_data.client + + @callback + def _on_device_update(self) -> None: + """Call when device updates or entry data changes.""" + self._on_entry_data_changed() + if not self._entry_data.available: + # Only write state if the device has gone unavailable + # since _on_state_update will be called if the device + # is available when the full state arrives + # through the next entity state packet. + self.async_write_ha_state() + + @property + def available(self) -> bool: + """Return if the entity is available.""" + if self._device_info.has_deep_sleep: + # During deep sleep the ESP will not be connectable (by design) + # For these cases, show it as available + return True + + return self._entry_data.available + + +class EsphomeAssistEntity(Entity): + """Define a base entity for Assist Pipeline entities.""" + + _attr_has_entity_name = True + _attr_should_poll = False + + def __init__(self, entry_data: RuntimeEntryData) -> None: + """Initialize the binary sensor.""" + self._entry_data: RuntimeEntryData = entry_data + assert entry_data.device_info is not None + device_info = entry_data.device_info + self._device_info = device_info + self._attr_unique_id = ( + f"{device_info.mac_address}-{self.entity_description.key}" + ) + self._attr_device_info = DeviceInfo( + connections={(dr.CONNECTION_NETWORK_MAC, device_info.mac_address)} + ) + + @callback + def _update(self) -> None: + self.async_write_ha_state() + + async def async_added_to_hass(self) -> None: + """Register update callback.""" + await super().async_added_to_hass() + self.async_on_remove( + self._entry_data.async_subscribe_assist_pipeline_update(self._update) + ) diff --git a/homeassistant/components/esphome/fan.py b/homeassistant/components/esphome/fan.py index 040e6585a4b..388413f161f 100644 --- a/homeassistant/components/esphome/fan.py +++ b/homeassistant/components/esphome/fan.py @@ -22,7 +22,11 @@ from homeassistant.util.percentage import ( ranged_value_to_percentage, ) -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) from .enum_mapper import EsphomeEnumMapper ORDERED_NAMED_FAN_SPEEDS = [FanSpeed.LOW, FanSpeed.MEDIUM, FanSpeed.HIGH] diff --git a/homeassistant/components/esphome/light.py b/homeassistant/components/esphome/light.py index a17c49caa73..f4232e320b0 100644 --- a/homeassistant/components/esphome/light.py +++ b/homeassistant/components/esphome/light.py @@ -31,7 +31,11 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) FLASH_LENGTHS = {FLASH_SHORT: 2, FLASH_LONG: 10} diff --git a/homeassistant/components/esphome/lock.py b/homeassistant/components/esphome/lock.py index d13d2d333dc..0cfc25e3882 100644 --- a/homeassistant/components/esphome/lock.py +++ b/homeassistant/components/esphome/lock.py @@ -11,7 +11,11 @@ from homeassistant.const import ATTR_CODE from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) async def async_setup_entry( diff --git a/homeassistant/components/esphome/media_player.py b/homeassistant/components/esphome/media_player.py index d554207f563..9933f523c26 100644 --- a/homeassistant/components/esphome/media_player.py +++ b/homeassistant/components/esphome/media_player.py @@ -25,7 +25,11 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) from .enum_mapper import EsphomeEnumMapper diff --git a/homeassistant/components/esphome/number.py b/homeassistant/components/esphome/number.py index 786512f3a42..ead3d5c4307 100644 --- a/homeassistant/components/esphome/number.py +++ b/homeassistant/components/esphome/number.py @@ -16,7 +16,11 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.enum import try_parse_enum -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) from .enum_mapper import EsphomeEnumMapper diff --git a/homeassistant/components/esphome/select.py b/homeassistant/components/esphome/select.py index 1323c9f5666..2de6ddd7111 100644 --- a/homeassistant/components/esphome/select.py +++ b/homeassistant/components/esphome/select.py @@ -9,13 +9,13 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import ( +from .domain_data import DomainData +from .entity import ( EsphomeAssistEntity, EsphomeEntity, esphome_state_property, platform_async_setup_entry, ) -from .domain_data import DomainData from .entry_data import RuntimeEntryData diff --git a/homeassistant/components/esphome/sensor.py b/homeassistant/components/esphome/sensor.py index 6c1fca1ffef..ac2fb9629a8 100644 --- a/homeassistant/components/esphome/sensor.py +++ b/homeassistant/components/esphome/sensor.py @@ -25,7 +25,11 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util import dt as dt_util from homeassistant.util.enum import try_parse_enum -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) from .enum_mapper import EsphomeEnumMapper diff --git a/homeassistant/components/esphome/switch.py b/homeassistant/components/esphome/switch.py index e71853a1287..4ecee203fa0 100644 --- a/homeassistant/components/esphome/switch.py +++ b/homeassistant/components/esphome/switch.py @@ -11,7 +11,11 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.enum import try_parse_enum -from . import EsphomeEntity, esphome_state_property, platform_async_setup_entry +from .entity import ( + EsphomeEntity, + esphome_state_property, + platform_async_setup_entry, +) async def async_setup_entry(