From d67c1118dc1d6d9232de36c845c009777d994684 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 21 Oct 2021 20:22:51 -1000 Subject: [PATCH] Cleanup lookin entity MRO and inheritance (#58194) --- homeassistant/components/lookin/climate.py | 12 +- homeassistant/components/lookin/entity.py | 134 +++++++++++++++++---- homeassistant/components/lookin/sensor.py | 9 +- 3 files changed, 115 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/lookin/climate.py b/homeassistant/components/lookin/climate.py index 4cba00121d5..536d4ca4016 100644 --- a/homeassistant/components/lookin/climate.py +++ b/homeassistant/components/lookin/climate.py @@ -30,13 +30,10 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, PRECISION_WHOLE, TEMP_CELSIUS from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, - DataUpdateCoordinator, -) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN -from .entity import LookinEntity +from .entity import LookinCoordinatorEntity from .models import LookinData SUPPORT_FLAGS: int = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE | SUPPORT_SWING_MODE @@ -113,7 +110,7 @@ async def async_setup_entry( async_add_entities(entities) -class ConditionerEntity(LookinEntity, CoordinatorEntity, ClimateEntity): +class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity): """An aircon or heat pump.""" _attr_temperature_unit = TEMP_CELSIUS @@ -133,8 +130,7 @@ class ConditionerEntity(LookinEntity, CoordinatorEntity, ClimateEntity): coordinator: DataUpdateCoordinator, ) -> None: """Init the ConditionerEntity.""" - CoordinatorEntity.__init__(self, coordinator) - super().__init__(uuid, device, lookin_data) + super().__init__(coordinator, uuid, device, lookin_data) self._async_update_from_data() @property diff --git a/homeassistant/components/lookin/entity.py b/homeassistant/components/lookin/entity.py index fd2ee5e4a6c..228d69f8341 100644 --- a/homeassistant/components/lookin/entity.py +++ b/homeassistant/components/lookin/entity.py @@ -2,34 +2,94 @@ from __future__ import annotations from aiolookin import POWER_CMD, POWER_OFF_CMD, POWER_ON_CMD, Climate, Remote +from aiolookin.models import Device from homeassistant.helpers.entity import DeviceInfo, Entity +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) from .const import DOMAIN from .models import LookinData -class LookinDeviceEntity(Entity): +def _lookin_device_to_device_info(lookin_device: Device) -> DeviceInfo: + """Convert a lookin device into DeviceInfo.""" + return DeviceInfo( + identifiers={(DOMAIN, lookin_device.id)}, + name=lookin_device.name, + manufacturer="LOOKin", + model="LOOKin Remote2", + sw_version=lookin_device.firmware, + ) + + +def _lookin_controlled_device_to_device_info( + lookin_device: Device, uuid: str, device: Device +) -> DeviceInfo: + return DeviceInfo( + identifiers={(DOMAIN, uuid)}, + name=device.name, + model=device.device_type, + via_device=(DOMAIN, lookin_device.id), + ) + + +class LookinDeviceMixIn: + """A mix in to set lookin attributes for the lookin device.""" + + def _set_lookin_device_attrs(self, lookin_data: LookinData) -> None: + """Set attrs for the lookin device.""" + self._lookin_device = lookin_data.lookin_device + self._lookin_protocol = lookin_data.lookin_protocol + self._lookin_udp_subs = lookin_data.lookin_udp_subs + + +class LookinDeviceEntity(LookinDeviceMixIn, Entity): """A lookin device entity on the device itself.""" _attr_should_poll = False def __init__(self, lookin_data: LookinData) -> None: """Init the lookin device entity.""" - super().__init__() - self._lookin_device = lookin_data.lookin_device - self._lookin_protocol = lookin_data.lookin_protocol - self._lookin_udp_subs = lookin_data.lookin_udp_subs - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, self._lookin_device.id)}, - name=self._lookin_device.name, - manufacturer="LOOKin", - model="LOOKin Remote2", - sw_version=self._lookin_device.firmware, + self._set_lookin_device_attrs(lookin_data) + self._attr_device_info = _lookin_device_to_device_info( + lookin_data.lookin_device ) -class LookinEntity(Entity): +class LookinDeviceCoordinatorEntity(LookinDeviceMixIn, CoordinatorEntity): + """A lookin device entity on the device itself that uses the coordinator.""" + + _attr_should_poll = False + + def __init__(self, lookin_data: LookinData) -> None: + """Init the lookin device entity.""" + super().__init__(lookin_data.meteo_coordinator) + self._set_lookin_device_attrs(lookin_data) + self._attr_device_info = _lookin_device_to_device_info( + lookin_data.lookin_device + ) + + +class LookinEntityMixIn: + """A mix in to set attributes for a lookin entity.""" + + def _set_lookin_entity_attrs( + self, + uuid: str, + device: Remote | Climate, + lookin_data: LookinData, + ) -> None: + """Set attrs for the device controlled via the lookin device.""" + self._device = device + self._uuid = uuid + self._meteo_coordinator = lookin_data.meteo_coordinator + self._function_names = {function.name for function in self._device.functions} + + +class LookinEntity(LookinDeviceMixIn, LookinEntityMixIn, Entity): """A base class for lookin entities.""" _attr_should_poll = False @@ -42,21 +102,43 @@ class LookinEntity(Entity): lookin_data: LookinData, ) -> None: """Init the base entity.""" - self._device = device - self._uuid = uuid - self._lookin_device = lookin_data.lookin_device - self._lookin_protocol = lookin_data.lookin_protocol - self._lookin_udp_subs = lookin_data.lookin_udp_subs - self._meteo_coordinator = lookin_data.meteo_coordinator - self._function_names = {function.name for function in self._device.functions} - self._attr_unique_id = uuid - self._attr_name = self._device.name - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, self._uuid)}, - name=self._device.name, - model=self._device.device_type, - via_device=(DOMAIN, self._lookin_device.id), + self._set_lookin_device_attrs(lookin_data) + self._set_lookin_entity_attrs(uuid, device, lookin_data) + self._attr_device_info = _lookin_controlled_device_to_device_info( + self._lookin_device, uuid, device ) + self._attr_unique_id = uuid + self._attr_name = device.name + + async def _async_send_command(self, command: str) -> None: + """Send command from saved IR device.""" + await self._lookin_protocol.send_command( + uuid=self._uuid, command=command, signal="FF" + ) + + +class LookinCoordinatorEntity(LookinDeviceMixIn, LookinEntityMixIn, CoordinatorEntity): + """A lookin device entity for an external device that uses the coordinator.""" + + _attr_should_poll = False + _attr_assumed_state = True + + def __init__( + self, + coordinator: DataUpdateCoordinator, + uuid: str, + device: Remote | Climate, + lookin_data: LookinData, + ) -> None: + """Init the base entity.""" + super().__init__(coordinator) + self._set_lookin_device_attrs(lookin_data) + self._set_lookin_entity_attrs(uuid, device, lookin_data) + self._attr_device_info = _lookin_controlled_device_to_device_info( + self._lookin_device, uuid, device + ) + self._attr_unique_id = uuid + self._attr_name = device.name async def _async_send_command(self, command: str) -> None: """Send command from saved IR device.""" diff --git a/homeassistant/components/lookin/sensor.py b/homeassistant/components/lookin/sensor.py index 34a3859c7ec..d7d4a7a937a 100644 --- a/homeassistant/components/lookin/sensor.py +++ b/homeassistant/components/lookin/sensor.py @@ -15,12 +15,10 @@ from homeassistant.components.sensor import ( from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE, TEMP_CELSIUS from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN -from .entity import LookinDeviceEntity +from .entity import LookinDeviceCoordinatorEntity from .models import LookinData LOGGER = logging.getLogger(__name__) @@ -57,15 +55,14 @@ async def async_setup_entry( ) -class LookinSensorEntity(CoordinatorEntity, LookinDeviceEntity, SensorEntity, Entity): +class LookinSensorEntity(LookinDeviceCoordinatorEntity, SensorEntity): """A lookin device sensor entity.""" def __init__( self, description: SensorEntityDescription, lookin_data: LookinData ) -> None: """Init the lookin sensor entity.""" - super().__init__(lookin_data.meteo_coordinator) - LookinDeviceEntity.__init__(self, lookin_data) + super().__init__(lookin_data) self.entity_description = description self._attr_name = f"{self._lookin_device.name} {description.name}" self._attr_native_value = getattr(self.coordinator.data, description.key)