From 5db70d83da737e63150e7471f327f2d9caba2027 Mon Sep 17 00:00:00 2001 From: Matija Kovacic Date: Tue, 4 Apr 2023 15:43:04 +0200 Subject: [PATCH 1/5] Extracting Supla base entity --- homeassistant/components/supla/__init__.py | 60 +-------------------- homeassistant/components/supla/cover.py | 12 ++--- homeassistant/components/supla/entity.py | 62 ++++++++++++++++++++++ homeassistant/components/supla/switch.py | 7 +-- 4 files changed, 73 insertions(+), 68 deletions(-) create mode 100644 homeassistant/components/supla/entity.py diff --git a/homeassistant/components/supla/__init__.py b/homeassistant/components/supla/__init__.py index 96fe8f39aa92e..541b31eb0a3d8 100644 --- a/homeassistant/components/supla/__init__.py +++ b/homeassistant/components/supla/__init__.py @@ -14,10 +14,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.typing import ConfigType -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, - DataUpdateCoordinator, -) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -155,58 +152,3 @@ async def _fetch_channels(): # Load discovered devices for component_name, config in component_configs.items(): await async_load_platform(hass, component_name, DOMAIN, config, hass_config) - - -class SuplaChannel(CoordinatorEntity): - """Base class of a Supla Channel (an equivalent of HA's Entity).""" - - def __init__(self, config, server, coordinator): - """Init from config, hookup[ server and coordinator.""" - super().__init__(coordinator) - self.server_name = config["server_name"] - self.channel_id = config["channel_id"] - self.server = server - - @property - def channel_data(self): - """Return channel data taken from coordinator.""" - return self.coordinator.data.get(self.channel_id) - - @property - def unique_id(self) -> str: - """Return a unique ID.""" - return "supla-{}-{}".format( - self.channel_data["iodevice"]["gUIDString"].lower(), - self.channel_data["channelNumber"], - ) - - @property - def name(self) -> str | None: - """Return the name of the device.""" - return self.channel_data["caption"] - - @property - def available(self) -> bool: - """Return True if entity is available.""" - if self.channel_data is None: - return False - if (state := self.channel_data.get("state")) is None: - return False - return state.get("connected") - - async def async_action(self, action, **add_pars): - """Run server action. - - Actions are currently hardcoded in components. - Supla's API enables autodiscovery - """ - _LOGGER.debug( - "Executing action %s on channel %d, params: %s", - action, - self.channel_data["id"], - add_pars, - ) - await self.server.execute_action(self.channel_data["id"], action, **add_pars) - - # Update state - await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/supla/cover.py b/homeassistant/components/supla/cover.py index df4e9c7e1097a..f35d891e9cc22 100644 --- a/homeassistant/components/supla/cover.py +++ b/homeassistant/components/supla/cover.py @@ -10,7 +10,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS, SuplaChannel +from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS, SuplaEntity _LOGGER = logging.getLogger(__name__) @@ -38,16 +38,16 @@ async def async_setup_platform( if device_name == SUPLA_SHUTTER: entities.append( - SuplaCover( + SuplaCoverEntity( device, hass.data[DOMAIN][SUPLA_SERVERS][server_name], hass.data[DOMAIN][SUPLA_COORDINATORS][server_name], ) ) - elif device_name in {SUPLA_GATE, SUPLA_GARAGE_DOOR}: + elif device_name == SUPLA_GATE or device_name == SUPLA_GARAGE_DOOR: entities.append( - SuplaDoor( + SuplaDoorEntity( device, hass.data[DOMAIN][SUPLA_SERVERS][server_name], hass.data[DOMAIN][SUPLA_COORDINATORS][server_name], @@ -57,7 +57,7 @@ async def async_setup_platform( async_add_entities(entities) -class SuplaCover(SuplaChannel, CoverEntity): +class SuplaCoverEntity(SuplaEntity, CoverEntity): """Representation of a Supla Cover.""" @property @@ -91,7 +91,7 @@ async def async_stop_cover(self, **kwargs: Any) -> None: await self.async_action("STOP") -class SuplaDoor(SuplaChannel, CoverEntity): +class SuplaDoorEntity(SuplaEntity, CoverEntity): """Representation of a Supla door.""" @property diff --git a/homeassistant/components/supla/entity.py b/homeassistant/components/supla/entity.py new file mode 100644 index 0000000000000..a7c1488b3f5cf --- /dev/null +++ b/homeassistant/components/supla/entity.py @@ -0,0 +1,62 @@ +"""Base class for Supla channels.""" +from __future__ import annotations + +import logging + +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +_LOGGER = logging.getLogger(__name__) + +class SuplaEntity(CoordinatorEntity): + """Base class of a Supla Channel (an equivalent of HA's Entity).""" + + def __init__(self, config, server, coordinator): + """Init from config, hookup[ server and coordinator.""" + super().__init__(coordinator) + self.server_name = config["server_name"] + self.channel_id = config["channel_id"] + self.server = server + + @property + def channel_data(self): + """Return channel data taken from coordinator.""" + return self.coordinator.data.get(self.channel_id) + + @property + def unique_id(self) -> str: + """Return a unique ID.""" + return "supla-{}-{}".format( + self.channel_data["iodevice"]["gUIDString"].lower(), + self.channel_data["channelNumber"], + ) + + @property + def name(self) -> str | None: + """Return the name of the device.""" + return self.channel_data["caption"] + + @property + def available(self) -> bool: + """Return True if entity is available.""" + if self.channel_data is None: + return False + if (state := self.channel_data.get("state")) is None: + return False + return state.get("connected") + + async def async_action(self, action, **add_pars): + """Run server action. + + Actions are currently hardcoded in components. + Supla's API enables autodiscovery + """ + _LOGGER.debug( + "Executing action %s on channel %d, params: %s", + action, + self.channel_data["id"], + add_pars, + ) + await self.server.execute_action(self.channel_data["id"], action, **add_pars) + + # Update state + await self.coordinator.async_request_refresh() diff --git a/homeassistant/components/supla/switch.py b/homeassistant/components/supla/switch.py index 9c4c53c1e9f16..b270f4300e162 100644 --- a/homeassistant/components/supla/switch.py +++ b/homeassistant/components/supla/switch.py @@ -10,7 +10,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS, SuplaChannel +from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS +from .entity import SuplaEntity _LOGGER = logging.getLogger(__name__) @@ -32,7 +33,7 @@ async def async_setup_platform( server_name = device["server_name"] entities.append( - SuplaSwitch( + SuplaSwitchEntity( device, hass.data[DOMAIN][SUPLA_SERVERS][server_name], hass.data[DOMAIN][SUPLA_COORDINATORS][server_name], @@ -42,7 +43,7 @@ async def async_setup_platform( async_add_entities(entities) -class SuplaSwitch(SuplaChannel, SwitchEntity): +class SuplaSwitchEntity(SuplaEntity, SwitchEntity): """Representation of a Supla Switch.""" async def async_turn_on(self, **kwargs: Any) -> None: From 0bd0298e079fb194d42cb9a5ef07f6877ca71090 Mon Sep 17 00:00:00 2001 From: Matija Kovacic Date: Tue, 4 Apr 2023 15:46:22 +0200 Subject: [PATCH 2/5] Fix improper import --- homeassistant/components/supla/cover.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/supla/cover.py b/homeassistant/components/supla/cover.py index f35d891e9cc22..09536145586ea 100644 --- a/homeassistant/components/supla/cover.py +++ b/homeassistant/components/supla/cover.py @@ -10,7 +10,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType -from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS, SuplaEntity +from . import DOMAIN, SUPLA_COORDINATORS, SUPLA_SERVERS +from .entity import SuplaEntity _LOGGER = logging.getLogger(__name__) From e4353201342676e79d80b22c45237b0efb271df7 Mon Sep 17 00:00:00 2001 From: Matija Kovacic Date: Tue, 4 Apr 2023 15:55:41 +0200 Subject: [PATCH 3/5] Making Black happy. --- homeassistant/components/supla/entity.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/supla/entity.py b/homeassistant/components/supla/entity.py index a7c1488b3f5cf..92626236e59e2 100644 --- a/homeassistant/components/supla/entity.py +++ b/homeassistant/components/supla/entity.py @@ -7,6 +7,7 @@ _LOGGER = logging.getLogger(__name__) + class SuplaEntity(CoordinatorEntity): """Base class of a Supla Channel (an equivalent of HA's Entity).""" @@ -45,7 +46,8 @@ def available(self) -> bool: return state.get("connected") async def async_action(self, action, **add_pars): - """Run server action. + """ + Run server action. Actions are currently hardcoded in components. Supla's API enables autodiscovery From 1aec18c8172ff2295ee9bc0015f4c95d24fbc1f5 Mon Sep 17 00:00:00 2001 From: Matija Kovacic Date: Tue, 4 Apr 2023 16:01:27 +0200 Subject: [PATCH 4/5] Use set for membership check --- homeassistant/components/supla/cover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/supla/cover.py b/homeassistant/components/supla/cover.py index 09536145586ea..53e57fe18540e 100644 --- a/homeassistant/components/supla/cover.py +++ b/homeassistant/components/supla/cover.py @@ -46,7 +46,7 @@ async def async_setup_platform( ) ) - elif device_name == SUPLA_GATE or device_name == SUPLA_GARAGE_DOOR: + elif device_name in {SUPLA_GATE, SUPLA_GARAGE_DOOR}: entities.append( SuplaDoorEntity( device, From 848a22beb81c53e892db351d619ba604e4b77b2a Mon Sep 17 00:00:00 2001 From: Matija Kovacic Date: Tue, 4 Apr 2023 16:04:20 +0200 Subject: [PATCH 5/5] Making ruff happy. --- homeassistant/components/supla/entity.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/supla/entity.py b/homeassistant/components/supla/entity.py index 92626236e59e2..ae0a627b5387a 100644 --- a/homeassistant/components/supla/entity.py +++ b/homeassistant/components/supla/entity.py @@ -46,8 +46,7 @@ def available(self) -> bool: return state.get("connected") async def async_action(self, action, **add_pars): - """ - Run server action. + """Run server action. Actions are currently hardcoded in components. Supla's API enables autodiscovery