From 7dff4d6ad749f8eccbf7e1de27878c835aa5ed43 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 27 May 2021 17:39:43 +0200 Subject: [PATCH] Define climate entity attributes as class variables (#51006) --- homeassistant/components/climate/__init__.py | 86 +++++++++++++------- homeassistant/components/toon/climate.py | 66 ++++++--------- 2 files changed, 83 insertions(+), 69 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 0369933dd0a..cd559a2e345 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -1,7 +1,6 @@ """Provides functionality to interact with climate devices.""" from __future__ import annotations -from abc import abstractmethod from datetime import timedelta import functools as ft import logging @@ -171,6 +170,31 @@ async def async_unload_entry(hass: HomeAssistant, entry): class ClimateEntity(Entity): """Base class for climate entities.""" + _attr_current_humidity: int | None = None + _attr_current_temperature: float | None = None + _attr_fan_mode: str | None + _attr_fan_modes: list[str] | None + _attr_hvac_action: str | None = None + _attr_hvac_mode: str + _attr_hvac_modes: list[str] + _attr_is_aux_heat: bool | None + _attr_max_humidity: int = DEFAULT_MAX_HUMIDITY + _attr_max_temp: float + _attr_min_humidity: int = DEFAULT_MIN_HUMIDITY + _attr_min_temp: float + _attr_precision: float + _attr_preset_mode: str | None + _attr_preset_modes: list[str] | None + _attr_supported_features: int + _attr_swing_mode: str | None + _attr_swing_modes: list[str] | None + _attr_target_humidity: int | None = None + _attr_target_temperature_high: float | None + _attr_target_temperature_low: float | None + _attr_target_temperature_step: float | None = None + _attr_target_temperature: float | None = None + _attr_temperature_unit: str + @property def state(self) -> str: """Return the current state.""" @@ -179,6 +203,8 @@ class ClimateEntity(Entity): @property def precision(self) -> float: """Return the precision of the system.""" + if hasattr(self, "_attr_precision"): + return self._attr_precision if self.hass.config.units.temperature_unit == TEMP_CELSIUS: return PRECISION_TENTHS return PRECISION_WHOLE @@ -277,33 +303,33 @@ class ClimateEntity(Entity): @property def temperature_unit(self) -> str: """Return the unit of measurement used by the platform.""" - raise NotImplementedError() + return self._attr_temperature_unit @property def current_humidity(self) -> int | None: """Return the current humidity.""" - return None + return self._attr_current_humidity @property def target_humidity(self) -> int | None: """Return the humidity we try to reach.""" - return None + return self._attr_target_humidity @property - @abstractmethod def hvac_mode(self) -> str: """Return hvac operation ie. heat, cool mode. Need to be one of HVAC_MODE_*. """ + return self._attr_hvac_mode @property - @abstractmethod def hvac_modes(self) -> list[str]: """Return the list of available hvac operation modes. Need to be a subset of HVAC_MODES. """ + return self._attr_hvac_modes @property def hvac_action(self) -> str | None: @@ -311,22 +337,22 @@ class ClimateEntity(Entity): Need to be one of CURRENT_HVAC_*. """ - return None + return self._attr_hvac_action @property def current_temperature(self) -> float | None: """Return the current temperature.""" - return None + return self._attr_current_temperature @property def target_temperature(self) -> float | None: """Return the temperature we try to reach.""" - return None + return self._attr_target_temperature @property def target_temperature_step(self) -> float | None: """Return the supported step of target temperature.""" - return None + return self._attr_target_temperature_step @property def target_temperature_high(self) -> float | None: @@ -334,7 +360,7 @@ class ClimateEntity(Entity): Requires SUPPORT_TARGET_TEMPERATURE_RANGE. """ - raise NotImplementedError + return self._attr_target_temperature_high @property def target_temperature_low(self) -> float | None: @@ -342,7 +368,7 @@ class ClimateEntity(Entity): Requires SUPPORT_TARGET_TEMPERATURE_RANGE. """ - raise NotImplementedError + return self._attr_target_temperature_low @property def preset_mode(self) -> str | None: @@ -350,7 +376,7 @@ class ClimateEntity(Entity): Requires SUPPORT_PRESET_MODE. """ - raise NotImplementedError + return self._attr_preset_mode @property def preset_modes(self) -> list[str] | None: @@ -358,7 +384,7 @@ class ClimateEntity(Entity): Requires SUPPORT_PRESET_MODE. """ - raise NotImplementedError + return self._attr_preset_modes @property def is_aux_heat(self) -> bool | None: @@ -366,7 +392,7 @@ class ClimateEntity(Entity): Requires SUPPORT_AUX_HEAT. """ - raise NotImplementedError + return self._attr_is_aux_heat @property def fan_mode(self) -> str | None: @@ -374,7 +400,7 @@ class ClimateEntity(Entity): Requires SUPPORT_FAN_MODE. """ - raise NotImplementedError + return self._attr_fan_mode @property def fan_modes(self) -> list[str] | None: @@ -382,7 +408,7 @@ class ClimateEntity(Entity): Requires SUPPORT_FAN_MODE. """ - raise NotImplementedError + return self._attr_fan_modes @property def swing_mode(self) -> str | None: @@ -390,7 +416,7 @@ class ClimateEntity(Entity): Requires SUPPORT_SWING_MODE. """ - raise NotImplementedError + return self._attr_swing_mode @property def swing_modes(self) -> list[str] | None: @@ -398,7 +424,7 @@ class ClimateEntity(Entity): Requires SUPPORT_SWING_MODE. """ - raise NotImplementedError + return self._attr_swing_modes def set_temperature(self, **kwargs) -> None: """Set new target temperature.""" @@ -494,31 +520,35 @@ class ClimateEntity(Entity): @property def supported_features(self) -> int: """Return the list of supported features.""" - raise NotImplementedError() + return self._attr_supported_features @property def min_temp(self) -> float: """Return the minimum temperature.""" - return convert_temperature( - DEFAULT_MIN_TEMP, TEMP_CELSIUS, self.temperature_unit - ) + if not hasattr(self, "_attr_min_temp"): + return convert_temperature( + DEFAULT_MIN_TEMP, TEMP_CELSIUS, self.temperature_unit + ) + return self._attr_min_temp @property def max_temp(self) -> float: """Return the maximum temperature.""" - return convert_temperature( - DEFAULT_MAX_TEMP, TEMP_CELSIUS, self.temperature_unit - ) + if not hasattr(self, "_attr_max_temp"): + return convert_temperature( + DEFAULT_MAX_TEMP, TEMP_CELSIUS, self.temperature_unit + ) + return self._attr_max_temp @property def min_humidity(self) -> int: """Return the minimum humidity.""" - return DEFAULT_MIN_HUMIDITY + return self._attr_min_humidity @property def max_humidity(self) -> int: """Return the maximum humidity.""" - return DEFAULT_MAX_HUMIDITY + return self._attr_max_humidity async def async_service_aux_heat( diff --git a/homeassistant/components/toon/climate.py b/homeassistant/components/toon/climate.py index 1c7bde7d9e5..e69c178e595 100644 --- a/homeassistant/components/toon/climate.py +++ b/homeassistant/components/toon/climate.py @@ -26,6 +26,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.core import HomeAssistant +from . import ToonDataUpdateCoordinator from .const import DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP, DOMAIN from .helpers import toon_exception_handler from .models import ToonDisplayDeviceEntity @@ -44,28 +45,31 @@ async def async_setup_entry( class ToonThermostatDevice(ToonDisplayDeviceEntity, ClimateEntity): """Representation of a Toon climate device.""" - @property - def unique_id(self) -> str: - """Return the unique ID for this thermostat.""" - agreement_id = self.coordinator.data.agreement.agreement_id - # This unique ID is a bit ugly and contains unneeded information. - # It is here for lecagy / backward compatible reasons. - return f"{DOMAIN}_{agreement_id}_climate" + _attr_hvac_mode = HVAC_MODE_HEAT + _attr_max_temp = DEFAULT_MAX_TEMP + _attr_min_temp = DEFAULT_MIN_TEMP + _attr_supported_features = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE + _attr_temperature_unit = TEMP_CELSIUS - @property - def supported_features(self) -> int: - """Return the list of supported features.""" - return SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE - - @property - def hvac_mode(self) -> str: - """Return hvac operation ie. heat, cool mode.""" - return HVAC_MODE_HEAT - - @property - def hvac_modes(self) -> list[str]: - """Return the list of available hvac operation modes.""" - return [HVAC_MODE_HEAT] + def __init__( + self, + coordinator: ToonDataUpdateCoordinator, + *, + name: str, + icon: str, + ) -> None: + """Initialize Toon climate entity.""" + super().__init__(coordinator, name=name, icon=icon) + self._attr_hvac_modes = [HVAC_MODE_HEAT] + self._attr_preset_modes = [ + PRESET_AWAY, + PRESET_COMFORT, + PRESET_HOME, + PRESET_SLEEP, + ] + self._attr_unique_id = ( + f"{DOMAIN}_{coordinator.data.agreement.agreement_id}_climate" + ) @property def hvac_action(self) -> str | None: @@ -74,11 +78,6 @@ class ToonThermostatDevice(ToonDisplayDeviceEntity, ClimateEntity): return CURRENT_HVAC_HEAT return CURRENT_HVAC_IDLE - @property - def temperature_unit(self) -> str: - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def preset_mode(self) -> str | None: """Return the current preset mode, e.g., home, away, temp.""" @@ -90,11 +89,6 @@ class ToonThermostatDevice(ToonDisplayDeviceEntity, ClimateEntity): } return mapping.get(self.coordinator.data.thermostat.active_state) - @property - def preset_modes(self) -> list[str]: - """Return a list of available preset modes.""" - return [PRESET_AWAY, PRESET_COMFORT, PRESET_HOME, PRESET_SLEEP] - @property def current_temperature(self) -> float | None: """Return the current temperature.""" @@ -105,16 +99,6 @@ class ToonThermostatDevice(ToonDisplayDeviceEntity, ClimateEntity): """Return the temperature we try to reach.""" return self.coordinator.data.thermostat.current_setpoint - @property - def min_temp(self) -> float: - """Return the minimum temperature.""" - return DEFAULT_MIN_TEMP - - @property - def max_temp(self) -> float: - """Return the maximum temperature.""" - return DEFAULT_MAX_TEMP - @property def extra_state_attributes(self) -> dict[str, Any]: """Return the current state of the burner."""