From 86c6c9746407ae097140d915d6cb92255278aef0 Mon Sep 17 00:00:00 2001 From: Bouwe Date: Sun, 3 Apr 2022 18:07:37 +0000 Subject: [PATCH 1/8] Refactor select.py --- homeassistant/components/plugwise/entity.py | 16 +++- homeassistant/components/plugwise/select.py | 96 ++++++++++++++++----- 2 files changed, 89 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/plugwise/entity.py b/homeassistant/components/plugwise/entity.py index b0896c3cd6dea0..306249ba822fe5 100644 --- a/homeassistant/components/plugwise/entity.py +++ b/homeassistant/components/plugwise/entity.py @@ -3,7 +3,7 @@ from typing import Any -from homeassistant.const import ATTR_NAME, ATTR_VIA_DEVICE, CONF_HOST +from homeassistant.const import ATTR_NAME, ATTR_VIA_DEVICE, CONF_HOST, STATE_ON from homeassistant.helpers.device_registry import ( CONNECTION_NETWORK_MAC, CONNECTION_ZIGBEE, @@ -60,6 +60,20 @@ def __init__( } ) + async def async_send_api_call(self, target: str, command: str) -> bool: + """Send api call.""" + result = False + if command == "set_regulation_mode": + result = await self.coordinator.api.set_regulation_mode(target) + if command == "set_schedule_state": + result = await self.coordinator.api.set_schedule_state( + self.device.get("location"), + target, + STATE_ON, + ) + + return result + @property def available(self) -> bool: """Return if entity is available.""" diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index b3cfb366889286..8f3a444114a94b 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -1,64 +1,116 @@ """Plugwise Select component for Home Assistant.""" from __future__ import annotations -from homeassistant.components.select import SelectEntity +from dataclasses import dataclass + +from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry -from homeassistant.const import STATE_ON from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .const import DOMAIN, THERMOSTAT_CLASSES +from .const import DOMAIN from .coordinator import PlugwiseDataUpdateCoordinator from .entity import PlugwiseEntity +@dataclass +class PlugwiseSelectDescriptionMixin: + """Mixin values for Plugwise Select entities.""" + + command: str + current_option: str + options: str + + +@dataclass +class PlugwiseSelectEntityDescription( + SelectEntityDescription, PlugwiseSelectDescriptionMixin +): + """Class describing Plugwise Number entities.""" + + +SELECT_TYPES = ( + PlugwiseSelectEntityDescription( + key="select_schedule", + name="Thermostat Schedule", + icon="mdi:calendar-clock", + command="set_schedule_state", + current_option="selected_schedule", + options="available_schedules", + ), + PlugwiseSelectEntityDescription( + key="select_regulation_mode", + name="Regulation Mode", + icon="mdi:hvac", + entity_category=EntityCategory.CONFIG, + command="set_regulation_mode", + current_option="regulation_mode", + options="regulation_modes", + entity_registry_enabled_default=False, + ), +) + + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up the Smile selector from a config entry.""" - coordinator = hass.data[DOMAIN][config_entry.entry_id] - async_add_entities( - PlugwiseSelectEntity(coordinator, device_id) - for device_id, device in coordinator.data.devices.items() - if device["class"] in THERMOSTAT_CLASSES - and len(device.get("available_schedules")) > 1 - ) + coordinator: PlugwiseDataUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] + + entities: list[PlugwiseSelectEntity] = [] + for device_id, device in coordinator.data.devices.items(): + for description in SELECT_TYPES: + if ( + description.options in device + and len(device.get(description.options, [])) > 1 + ): + entities.append( + PlugwiseSelectEntity(coordinator, device_id, description) + ) + + async_add_entities(entities) class PlugwiseSelectEntity(PlugwiseEntity, SelectEntity): """Represent Smile selector.""" + entity_description: PlugwiseSelectEntityDescription + def __init__( self, coordinator: PlugwiseDataUpdateCoordinator, device_id: str, + entity_description: PlugwiseSelectEntityDescription, ) -> None: """Initialise the selector.""" super().__init__(coordinator, device_id) - self._attr_unique_id = f"{device_id}-select_schedule" - self._attr_name = (f"{self.device.get('name', '')} Select Schedule").lstrip() + self.entity_description = entity_description + self._attr_unique_id = f"{device_id}-{entity_description.key}" + self._attr_name = ( + f"{self.device.get('name', '')} {entity_description.name}" + ).lstrip() @property def current_option(self) -> str | None: """Return the selected entity option to represent the entity state.""" - return self.device.get("selected_schedule") + return self.device.get(self.entity_description.current_option) @property def options(self) -> list[str]: - """Return a set of selectable options.""" - return self.device.get("available_schedules", []) + """Return the selectable entity options.""" + return self.device.get(self.entity_description.options, []) async def async_select_option(self, option: str) -> None: - """Change the selected option.""" + """Change to the selected entity option.""" if not ( - await self.coordinator.api.set_schedule_state( - self.device.get("location"), - option, - STATE_ON, - ) + await self.async_send_api_call(option, self.entity_description.command) ): - raise HomeAssistantError(f"Failed to change to schedule {option}") + raise HomeAssistantError(f"Failed to set {self.entity_description.name}") + await self.coordinator.async_request_refresh() From 9d2a0be41fe6aae2396023ccf24a350448cc2b8b Mon Sep 17 00:00:00 2001 From: Bouwe Date: Sun, 10 Apr 2022 09:27:45 +0000 Subject: [PATCH 2/8] Update to using lambda-functions, as suggested --- homeassistant/components/plugwise/entity.py | 16 +-------- homeassistant/components/plugwise/select.py | 37 ++++++++++----------- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/plugwise/entity.py b/homeassistant/components/plugwise/entity.py index 306249ba822fe5..b0896c3cd6dea0 100644 --- a/homeassistant/components/plugwise/entity.py +++ b/homeassistant/components/plugwise/entity.py @@ -3,7 +3,7 @@ from typing import Any -from homeassistant.const import ATTR_NAME, ATTR_VIA_DEVICE, CONF_HOST, STATE_ON +from homeassistant.const import ATTR_NAME, ATTR_VIA_DEVICE, CONF_HOST from homeassistant.helpers.device_registry import ( CONNECTION_NETWORK_MAC, CONNECTION_ZIGBEE, @@ -60,20 +60,6 @@ def __init__( } ) - async def async_send_api_call(self, target: str, command: str) -> bool: - """Send api call.""" - result = False - if command == "set_regulation_mode": - result = await self.coordinator.api.set_regulation_mode(target) - if command == "set_schedule_state": - result = await self.coordinator.api.set_schedule_state( - self.device.get("location"), - target, - STATE_ON, - ) - - return result - @property def available(self) -> bool: """Return if entity is available.""" diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 8f3a444114a94b..64eb1c1ad240b6 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -1,12 +1,14 @@ """Plugwise Select component for Home Assistant.""" from __future__ import annotations +from collections.abc import Awaitable, Callable from dataclasses import dataclass +from typing import Any from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry +from homeassistant.const import STATE_ON from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -19,7 +21,7 @@ class PlugwiseSelectDescriptionMixin: """Mixin values for Plugwise Select entities.""" - command: str + command: Callable[..., Awaitable[Any]] current_option: str options: str @@ -36,7 +38,9 @@ class PlugwiseSelectEntityDescription( key="select_schedule", name="Thermostat Schedule", icon="mdi:calendar-clock", - command="set_schedule_state", + command=lambda coordinator, location, option: coordinator.api.set_schedule_state( + location, option, STATE_ON + ), current_option="selected_schedule", options="available_schedules", ), @@ -45,10 +49,11 @@ class PlugwiseSelectEntityDescription( name="Regulation Mode", icon="mdi:hvac", entity_category=EntityCategory.CONFIG, - command="set_regulation_mode", + command=lambda coordinator, dummy, option: coordinator.api.set_regulation_mode( + option + ), current_option="regulation_mode", options="regulation_modes", - entity_registry_enabled_default=False, ), ) @@ -66,10 +71,7 @@ async def async_setup_entry( entities: list[PlugwiseSelectEntity] = [] for device_id, device in coordinator.data.devices.items(): for description in SELECT_TYPES: - if ( - description.options in device - and len(device.get(description.options, [])) > 1 - ): + if description.options in device and len(device[description.options]) > 1: entities.append( PlugwiseSelectEntity(coordinator, device_id, description) ) @@ -92,25 +94,22 @@ def __init__( super().__init__(coordinator, device_id) self.entity_description = entity_description self._attr_unique_id = f"{device_id}-{entity_description.key}" - self._attr_name = ( - f"{self.device.get('name', '')} {entity_description.name}" - ).lstrip() + self._attr_name = (f"{self.device['name']} {entity_description.name}").lstrip() @property - def current_option(self) -> str | None: + def current_option(self) -> str: """Return the selected entity option to represent the entity state.""" - return self.device.get(self.entity_description.current_option) + return self.device[self.entity_description.current_option] @property def options(self) -> list[str]: """Return the selectable entity options.""" - return self.device.get(self.entity_description.options, []) + return self.device[self.entity_description.options] async def async_select_option(self, option: str) -> None: """Change to the selected entity option.""" - if not ( - await self.async_send_api_call(option, self.entity_description.command) - ): - raise HomeAssistantError(f"Failed to set {self.entity_description.name}") + await self.entity_description.command( + self.coordinator, self.device["location"], option + ) await self.coordinator.async_request_refresh() From e0605e09e6745b34bc423b87b7566012fe6fefd4 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:40:36 +0200 Subject: [PATCH 3/8] Update homeassistant/components/plugwise/select.py Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 64eb1c1ad240b6..7c8f68927bed98 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -5,6 +5,9 @@ from dataclasses import dataclass from typing import Any +from plugwise import Smile + + from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.const import STATE_ON From ad8aaf2582c6907a501291b3a07f4439c2c7aa3b Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:40:43 +0200 Subject: [PATCH 4/8] Update homeassistant/components/plugwise/select.py Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 7c8f68927bed98..0db68f0fd0f026 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -24,7 +24,7 @@ class PlugwiseSelectDescriptionMixin: """Mixin values for Plugwise Select entities.""" - command: Callable[..., Awaitable[Any]] + command: Callable[[Smile, str, str], Awaitable[Any]] current_option: str options: str From 5d6646c8798afc6b2d3a7a8e82bee0a0805e54c3 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:41:04 +0200 Subject: [PATCH 5/8] Update homeassistant/components/plugwise/select.py Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 0db68f0fd0f026..c9046e76a09461 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -41,9 +41,7 @@ class PlugwiseSelectEntityDescription( key="select_schedule", name="Thermostat Schedule", icon="mdi:calendar-clock", - command=lambda coordinator, location, option: coordinator.api.set_schedule_state( - location, option, STATE_ON - ), + command=lambda api, loc, opt: api.set_schedule_state(loc, opt, STATE_ON), current_option="selected_schedule", options="available_schedules", ), From e0ee1d0814302807468268ec785a44bd543f0ba0 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:41:12 +0200 Subject: [PATCH 6/8] Update homeassistant/components/plugwise/select.py Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index c9046e76a09461..111d0e640ec21e 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -50,9 +50,7 @@ class PlugwiseSelectEntityDescription( name="Regulation Mode", icon="mdi:hvac", entity_category=EntityCategory.CONFIG, - command=lambda coordinator, dummy, option: coordinator.api.set_regulation_mode( - option - ), + command=lambda api, loc, opt: api.set_regulation_mode(opt), current_option="regulation_mode", options="regulation_modes", ), From 4857f276ccc14f82a933a152304d7dedd46929b4 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:41:28 +0200 Subject: [PATCH 7/8] Update homeassistant/components/plugwise/select.py Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index 111d0e640ec21e..d5d525e4436158 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -108,7 +108,7 @@ def options(self) -> list[str]: async def async_select_option(self, option: str) -> None: """Change to the selected entity option.""" await self.entity_description.command( - self.coordinator, self.device["location"], option + self.coordinator.api, self.device["location"], option ) await self.coordinator.async_request_refresh() From 99dad713a69df166d143e9487cd496be7a937b49 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 11 May 2022 09:48:32 +0200 Subject: [PATCH 8/8] Fix isort error Co-authored-by: Franck Nijhof --- homeassistant/components/plugwise/select.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/plugwise/select.py b/homeassistant/components/plugwise/select.py index d5d525e4436158..cac9c3e56375e6 100644 --- a/homeassistant/components/plugwise/select.py +++ b/homeassistant/components/plugwise/select.py @@ -7,7 +7,6 @@ from plugwise import Smile - from homeassistant.components.select import SelectEntity, SelectEntityDescription from homeassistant.config_entries import ConfigEntry from homeassistant.const import STATE_ON