Tado code quality improvements (#107678)

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Erwin Douna 2024-02-28 11:28:51 +01:00 committed by GitHub
parent 38ba966d74
commit c52e2038be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 124 additions and 100 deletions

View File

@ -17,6 +17,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
from . import TadoConnector
from .const import ( from .const import (
DATA, DATA,
DOMAIN, DOMAIN,
@ -170,7 +171,10 @@ class TadoDeviceBinarySensor(TadoDeviceEntity, BinarySensorEntity):
entity_description: TadoBinarySensorEntityDescription entity_description: TadoBinarySensorEntityDescription
def __init__( def __init__(
self, tado, device_info, entity_description: TadoBinarySensorEntityDescription self,
tado: TadoConnector,
device_info: dict[str, Any],
entity_description: TadoBinarySensorEntityDescription,
) -> None: ) -> None:
"""Initialize of the Tado Sensor.""" """Initialize of the Tado Sensor."""
self.entity_description = entity_description self.entity_description = entity_description
@ -183,7 +187,6 @@ class TadoDeviceBinarySensor(TadoDeviceEntity, BinarySensorEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register for sensor updates.""" """Register for sensor updates."""
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,
@ -196,13 +199,13 @@ class TadoDeviceBinarySensor(TadoDeviceEntity, BinarySensorEntity):
self._async_update_device_data() self._async_update_device_data()
@callback @callback
def _async_update_callback(self): def _async_update_callback(self) -> None:
"""Update and write state.""" """Update and write state."""
self._async_update_device_data() self._async_update_device_data()
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback
def _async_update_device_data(self): def _async_update_device_data(self) -> None:
"""Handle update callbacks.""" """Handle update callbacks."""
try: try:
self._device_info = self._tado.data["device"][self.device_id] self._device_info = self._tado.data["device"][self.device_id]
@ -223,9 +226,9 @@ class TadoZoneBinarySensor(TadoZoneEntity, BinarySensorEntity):
def __init__( def __init__(
self, self,
tado, tado: TadoConnector,
zone_name, zone_name: str,
zone_id, zone_id: int,
entity_description: TadoBinarySensorEntityDescription, entity_description: TadoBinarySensorEntityDescription,
) -> None: ) -> None:
"""Initialize of the Tado Sensor.""" """Initialize of the Tado Sensor."""
@ -237,7 +240,6 @@ class TadoZoneBinarySensor(TadoZoneEntity, BinarySensorEntity):
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register for sensor updates.""" """Register for sensor updates."""
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,
@ -250,13 +252,13 @@ class TadoZoneBinarySensor(TadoZoneEntity, BinarySensorEntity):
self._async_update_zone_data() self._async_update_zone_data()
@callback @callback
def _async_update_callback(self): def _async_update_callback(self) -> None:
"""Update and write state.""" """Update and write state."""
self._async_update_zone_data() self._async_update_zone_data()
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback
def _async_update_zone_data(self): def _async_update_zone_data(self) -> None:
"""Handle update callbacks.""" """Handle update callbacks."""
try: try:
tado_zone_data = self._tado.data["zone"][self.zone_id] tado_zone_data = self._tado.data["zone"][self.zone_id]

View File

@ -1,9 +1,12 @@
"""Support for Tado thermostats.""" """Support for Tado thermostats."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Mapping
import logging import logging
from typing import Any from typing import Any
import PyTado
import voluptuous as vol import voluptuous as vol
from homeassistant.components.climate import ( from homeassistant.components.climate import (
@ -22,6 +25,7 @@ from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TadoConnector
from .const import ( from .const import (
CONST_EXCLUSIVE_OVERLAY_GROUP, CONST_EXCLUSIVE_OVERLAY_GROUP,
CONST_FAN_AUTO, CONST_FAN_AUTO,
@ -48,6 +52,8 @@ from .const import (
SIGNAL_TADO_UPDATE_RECEIVED, SIGNAL_TADO_UPDATE_RECEIVED,
SUPPORT_PRESET_AUTO, SUPPORT_PRESET_AUTO,
SUPPORT_PRESET_MANUAL, SUPPORT_PRESET_MANUAL,
TADO_DEFAULT_MAX_TEMP,
TADO_DEFAULT_MIN_TEMP,
TADO_HVAC_ACTION_TO_HA_HVAC_ACTION, TADO_HVAC_ACTION_TO_HA_HVAC_ACTION,
TADO_MODES_WITH_NO_TEMP_SETTING, TADO_MODES_WITH_NO_TEMP_SETTING,
TADO_SWING_OFF, TADO_SWING_OFF,
@ -111,7 +117,7 @@ async def async_setup_entry(
async_add_entities(entities, True) async_add_entities(entities, True)
def _generate_entities(tado): def _generate_entities(tado: TadoConnector) -> list[TadoClimate]:
"""Create all climate entities.""" """Create all climate entities."""
entities = [] entities = []
for zone in tado.zones: for zone in tado.zones:
@ -124,7 +130,9 @@ def _generate_entities(tado):
return entities return entities
def create_climate_entity(tado, name: str, zone_id: int, device_info: dict): def create_climate_entity(
tado: TadoConnector, name: str, zone_id: int, device_info: dict
) -> TadoClimate | None:
"""Create a Tado climate entity.""" """Create a Tado climate entity."""
capabilities = tado.get_capabilities(zone_id) capabilities = tado.get_capabilities(zone_id)
_LOGGER.debug("Capabilities for zone %s: %s", zone_id, capabilities) _LOGGER.debug("Capabilities for zone %s: %s", zone_id, capabilities)
@ -203,16 +211,16 @@ def create_climate_entity(tado, name: str, zone_id: int, device_info: dict):
name, name,
zone_id, zone_id,
zone_type, zone_type,
supported_hvac_modes,
support_flags,
device_info,
heat_min_temp, heat_min_temp,
heat_max_temp, heat_max_temp,
heat_step, heat_step,
cool_min_temp, cool_min_temp,
cool_max_temp, cool_max_temp,
cool_step, cool_step,
supported_hvac_modes,
supported_fan_modes, supported_fan_modes,
support_flags,
device_info,
) )
return entity return entity
@ -228,21 +236,21 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
def __init__( def __init__(
self, self,
tado, tado: TadoConnector,
zone_name, zone_name: str,
zone_id, zone_id: int,
zone_type, zone_type: str,
heat_min_temp, supported_hvac_modes: list[HVACMode],
heat_max_temp, support_flags: ClimateEntityFeature,
heat_step, device_info: dict[str, str],
cool_min_temp, heat_min_temp: float | None = None,
cool_max_temp, heat_max_temp: float | None = None,
cool_step, heat_step: float | None = None,
supported_hvac_modes, cool_min_temp: float | None = None,
supported_fan_modes, cool_max_temp: float | None = None,
support_flags, cool_step: float | None = None,
device_info, supported_fan_modes: list[str] | None = None,
): ) -> None:
"""Initialize of Tado climate entity.""" """Initialize of Tado climate entity."""
self._tado = tado self._tado = tado
super().__init__(zone_name, tado.home_id, zone_id) super().__init__(zone_name, tado.home_id, zone_id)
@ -276,24 +284,23 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
self._cool_max_temp = cool_max_temp self._cool_max_temp = cool_max_temp
self._cool_step = cool_step self._cool_step = cool_step
self._target_temp = None self._target_temp: float | None = None
self._current_tado_fan_speed = CONST_FAN_OFF self._current_tado_fan_speed = CONST_FAN_OFF
self._current_tado_hvac_mode = CONST_MODE_OFF self._current_tado_hvac_mode = CONST_MODE_OFF
self._current_tado_hvac_action = HVACAction.OFF self._current_tado_hvac_action = HVACAction.OFF
self._current_tado_swing_mode = TADO_SWING_OFF self._current_tado_swing_mode = TADO_SWING_OFF
self._tado_zone_data = None self._tado_zone_data: PyTado.TadoZone = {}
self._tado_geofence_data = None self._tado_geofence_data: dict[str, str] | None = None
self._tado_zone_temp_offset = {} self._tado_zone_temp_offset: dict[str, Any] = {}
self._async_update_home_data() self._async_update_home_data()
self._async_update_zone_data() self._async_update_zone_data()
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register for sensor updates.""" """Register for sensor updates."""
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,
@ -313,12 +320,12 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
) )
@property @property
def current_humidity(self): def current_humidity(self) -> int | None:
"""Return the current humidity.""" """Return the current humidity."""
return self._tado_zone_data.current_humidity return self._tado_zone_data.current_humidity
@property @property
def current_temperature(self): def current_temperature(self) -> float | None:
"""Return the sensor temperature.""" """Return the sensor temperature."""
return self._tado_zone_data.current_temp return self._tado_zone_data.current_temp
@ -341,7 +348,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
) )
@property @property
def fan_mode(self): def fan_mode(self) -> str | None:
"""Return the fan setting.""" """Return the fan setting."""
if self._ac_device: if self._ac_device:
return TADO_TO_HA_FAN_MODE_MAP.get(self._current_tado_fan_speed, FAN_AUTO) return TADO_TO_HA_FAN_MODE_MAP.get(self._current_tado_fan_speed, FAN_AUTO)
@ -352,10 +359,13 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
self._control_hvac(fan_mode=HA_TO_TADO_FAN_MODE_MAP[fan_mode]) self._control_hvac(fan_mode=HA_TO_TADO_FAN_MODE_MAP[fan_mode])
@property @property
def preset_mode(self): def preset_mode(self) -> str:
"""Return the current preset mode (home, away or auto).""" """Return the current preset mode (home, away or auto)."""
if "presenceLocked" in self._tado_geofence_data: if (
self._tado_geofence_data is not None
and "presenceLocked" in self._tado_geofence_data
):
if not self._tado_geofence_data["presenceLocked"]: if not self._tado_geofence_data["presenceLocked"]:
return PRESET_AUTO return PRESET_AUTO
if self._tado_zone_data.is_away: if self._tado_zone_data.is_away:
@ -363,7 +373,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
return PRESET_HOME return PRESET_HOME
@property @property
def preset_modes(self): def preset_modes(self) -> list[str]:
"""Return a list of available preset modes.""" """Return a list of available preset modes."""
if self._tado.get_auto_geofencing_supported(): if self._tado.get_auto_geofencing_supported():
return SUPPORT_PRESET_AUTO return SUPPORT_PRESET_AUTO
@ -374,14 +384,14 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
self._tado.set_presence(preset_mode) self._tado.set_presence(preset_mode)
@property @property
def target_temperature_step(self): def target_temperature_step(self) -> float | None:
"""Return the supported step of target temperature.""" """Return the supported step of target temperature."""
if self._tado_zone_data.current_hvac_mode == CONST_MODE_COOL: if self._tado_zone_data.current_hvac_mode == CONST_MODE_COOL:
return self._cool_step or self._heat_step return self._cool_step or self._heat_step
return self._heat_step or self._cool_step return self._heat_step or self._cool_step
@property @property
def target_temperature(self): def target_temperature(self) -> float | None:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
# If the target temperature will be None # If the target temperature will be None
# if the device is performing an action # if the device is performing an action
@ -389,7 +399,12 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
# the device is switching states # the device is switching states
return self._tado_zone_data.target_temp or self._tado_zone_data.current_temp return self._tado_zone_data.target_temp or self._tado_zone_data.current_temp
def set_timer(self, temperature=None, time_period=None, requested_overlay=None): def set_timer(
self,
temperature: float,
time_period: int,
requested_overlay: str,
):
"""Set the timer on the entity, and temperature if supported.""" """Set the timer on the entity, and temperature if supported."""
self._control_hvac( self._control_hvac(
@ -399,7 +414,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
overlay_mode=requested_overlay, overlay_mode=requested_overlay,
) )
def set_temp_offset(self, offset): def set_temp_offset(self, offset: float) -> None:
"""Set offset on the entity.""" """Set offset on the entity."""
_LOGGER.debug( _LOGGER.debug(
@ -428,7 +443,6 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
def set_hvac_mode(self, hvac_mode: HVACMode) -> None: def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode.""" """Set new target hvac mode."""
self._control_hvac(hvac_mode=HA_TO_TADO_HVAC_MODE_MAP[hvac_mode]) self._control_hvac(hvac_mode=HA_TO_TADO_HVAC_MODE_MAP[hvac_mode])
@property @property
@ -437,7 +451,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
return self._tado_zone_data.available return self._tado_zone_data.available
@property @property
def min_temp(self): def min_temp(self) -> float:
"""Return the minimum temperature.""" """Return the minimum temperature."""
if ( if (
self._current_tado_hvac_mode == CONST_MODE_COOL self._current_tado_hvac_mode == CONST_MODE_COOL
@ -447,10 +461,10 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
if self._heat_min_temp is not None: if self._heat_min_temp is not None:
return self._heat_min_temp return self._heat_min_temp
return self._cool_min_temp return TADO_DEFAULT_MIN_TEMP
@property @property
def max_temp(self): def max_temp(self) -> float:
"""Return the maximum temperature.""" """Return the maximum temperature."""
if ( if (
self._current_tado_hvac_mode == CONST_MODE_HEAT self._current_tado_hvac_mode == CONST_MODE_HEAT
@ -460,17 +474,17 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
if self._heat_max_temp is not None: if self._heat_max_temp is not None:
return self._heat_max_temp return self._heat_max_temp
return self._heat_max_temp return TADO_DEFAULT_MAX_TEMP
@property @property
def swing_mode(self): def swing_mode(self) -> str | None:
"""Active swing mode for the device.""" """Active swing mode for the device."""
return TADO_TO_HA_SWING_MODE_MAP[self._current_tado_swing_mode] return TADO_TO_HA_SWING_MODE_MAP[self._current_tado_swing_mode]
@property @property
def extra_state_attributes(self): def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return temperature offset.""" """Return temperature offset."""
state_attr = self._tado_zone_temp_offset state_attr: dict[str, Any] = self._tado_zone_temp_offset
state_attr[ state_attr[
HA_TERMINATION_TYPE HA_TERMINATION_TYPE
] = self._tado_zone_data.default_overlay_termination_type ] = self._tado_zone_data.default_overlay_termination_type
@ -484,7 +498,7 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
self._control_hvac(swing_mode=HA_TO_TADO_SWING_MODE_MAP[swing_mode]) self._control_hvac(swing_mode=HA_TO_TADO_SWING_MODE_MAP[swing_mode])
@callback @callback
def _async_update_zone_data(self): def _async_update_zone_data(self) -> None:
"""Load tado data into zone.""" """Load tado data into zone."""
self._tado_zone_data = self._tado.data["zone"][self.zone_id] self._tado_zone_data = self._tado.data["zone"][self.zone_id]
@ -504,49 +518,49 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
self._current_tado_swing_mode = self._tado_zone_data.current_swing_mode self._current_tado_swing_mode = self._tado_zone_data.current_swing_mode
@callback @callback
def _async_update_zone_callback(self): def _async_update_zone_callback(self) -> None:
"""Load tado data and update state.""" """Load tado data and update state."""
self._async_update_zone_data() self._async_update_zone_data()
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback
def _async_update_home_data(self): def _async_update_home_data(self) -> None:
"""Load tado geofencing data into zone.""" """Load tado geofencing data into zone."""
self._tado_geofence_data = self._tado.data["geofence"] self._tado_geofence_data = self._tado.data["geofence"]
@callback @callback
def _async_update_home_callback(self): def _async_update_home_callback(self) -> None:
"""Load tado data and update state.""" """Load tado data and update state."""
self._async_update_home_data() self._async_update_home_data()
self.async_write_ha_state() self.async_write_ha_state()
def _normalize_target_temp_for_hvac_mode(self): def _normalize_target_temp_for_hvac_mode(self) -> None:
def adjust_temp(min_temp, max_temp) -> float | None:
if max_temp is not None and self._target_temp > max_temp:
return max_temp
if min_temp is not None and self._target_temp < min_temp:
return min_temp
return self._target_temp
# Set a target temperature if we don't have any # Set a target temperature if we don't have any
# This can happen when we switch from Off to On # This can happen when we switch from Off to On
if self._target_temp is None: if self._target_temp is None:
self._target_temp = self._tado_zone_data.current_temp self._target_temp = self._tado_zone_data.current_temp
elif self._current_tado_hvac_mode == CONST_MODE_COOL: elif self._current_tado_hvac_mode == CONST_MODE_COOL:
if self._target_temp > self._cool_max_temp: self._target_temp = adjust_temp(self._cool_min_temp, self._cool_max_temp)
self._target_temp = self._cool_max_temp
elif self._target_temp < self._cool_min_temp:
self._target_temp = self._cool_min_temp
elif self._current_tado_hvac_mode == CONST_MODE_HEAT: elif self._current_tado_hvac_mode == CONST_MODE_HEAT:
if self._target_temp > self._heat_max_temp: self._target_temp = adjust_temp(self._heat_min_temp, self._heat_max_temp)
self._target_temp = self._heat_max_temp
elif self._target_temp < self._heat_min_temp:
self._target_temp = self._heat_min_temp
def _control_hvac( def _control_hvac(
self, self,
hvac_mode=None, hvac_mode: str | None = None,
target_temp=None, target_temp: float | None = None,
fan_mode=None, fan_mode: str | None = None,
swing_mode=None, swing_mode: str | None = None,
duration=None, duration: int | None = None,
overlay_mode=None, overlay_mode: str | None = None,
): ):
"""Send new target temperature to Tado.""" """Send new target temperature to Tado."""
if hvac_mode: if hvac_mode:
self._current_tado_hvac_mode = hvac_mode self._current_tado_hvac_mode = hvac_mode
@ -605,9 +619,9 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
# If we ended up with a timer but no duration, set a default duration # If we ended up with a timer but no duration, set a default duration
if overlay_mode == CONST_OVERLAY_TIMER and duration is None: if overlay_mode == CONST_OVERLAY_TIMER and duration is None:
duration = ( duration = (
self._tado_zone_data.default_overlay_termination_duration int(self._tado_zone_data.default_overlay_termination_duration)
if self._tado_zone_data.default_overlay_termination_duration is not None if self._tado_zone_data.default_overlay_termination_duration is not None
else "3600" else 3600
) )
_LOGGER.debug( _LOGGER.debug(

View File

@ -205,6 +205,8 @@ TADO_TO_HA_OFFSET_MAP = {
HA_TERMINATION_TYPE = "default_overlay_type" HA_TERMINATION_TYPE = "default_overlay_type"
HA_TERMINATION_DURATION = "default_overlay_seconds" HA_TERMINATION_DURATION = "default_overlay_seconds"
TADO_DEFAULT_MIN_TEMP = 5
TADO_DEFAULT_MAX_TEMP = 25
# Constants for service calls # Constants for service calls
SERVICE_ADD_METER_READING = "add_meter_reading" SERVICE_ADD_METER_READING = "add_meter_reading"
CONF_CONFIG_ENTRY = "config_entry" CONF_CONFIG_ENTRY = "config_entry"

View File

@ -2,6 +2,7 @@
import logging import logging
from typing import Any from typing import Any
import PyTado
import voluptuous as vol import voluptuous as vol
from homeassistant.components.water_heater import ( from homeassistant.components.water_heater import (
@ -15,6 +16,7 @@ from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TadoConnector
from .const import ( from .const import (
CONST_HVAC_HEAT, CONST_HVAC_HEAT,
CONST_MODE_AUTO, CONST_MODE_AUTO,
@ -27,6 +29,8 @@ from .const import (
DATA, DATA,
DOMAIN, DOMAIN,
SIGNAL_TADO_UPDATE_RECEIVED, SIGNAL_TADO_UPDATE_RECEIVED,
TADO_DEFAULT_MAX_TEMP,
TADO_DEFAULT_MIN_TEMP,
TYPE_HOT_WATER, TYPE_HOT_WATER,
) )
from .entity import TadoZoneEntity from .entity import TadoZoneEntity
@ -78,7 +82,7 @@ async def async_setup_entry(
async_add_entities(entities, True) async_add_entities(entities, True)
def _generate_entities(tado): def _generate_entities(tado: TadoConnector) -> list[WaterHeaterEntity]:
"""Create all water heater entities.""" """Create all water heater entities."""
entities = [] entities = []
@ -90,7 +94,7 @@ def _generate_entities(tado):
return entities return entities
def create_water_heater_entity(tado, name: str, zone_id: int, zone: str): def create_water_heater_entity(tado: TadoConnector, name: str, zone_id: int, zone: str):
"""Create a Tado water heater device.""" """Create a Tado water heater device."""
capabilities = tado.get_capabilities(zone_id) capabilities = tado.get_capabilities(zone_id)
@ -125,15 +129,14 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
def __init__( def __init__(
self, self,
tado, tado: TadoConnector,
zone_name, zone_name: str,
zone_id, zone_id: int,
supports_temperature_control, supports_temperature_control: bool,
min_temp, min_temp: float | None = None,
max_temp, max_temp: float | None = None,
): ) -> None:
"""Initialize of Tado water heater entity.""" """Initialize of Tado water heater entity."""
self._tado = tado self._tado = tado
super().__init__(zone_name, tado.home_id, zone_id) super().__init__(zone_name, tado.home_id, zone_id)
@ -143,10 +146,10 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
self._device_is_active = False self._device_is_active = False
self._supports_temperature_control = supports_temperature_control self._supports_temperature_control = supports_temperature_control
self._min_temperature = min_temp self._min_temperature = min_temp or TADO_DEFAULT_MIN_TEMP
self._max_temperature = max_temp self._max_temperature = max_temp or TADO_DEFAULT_MAX_TEMP
self._target_temp = None self._target_temp: float | None = None
self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE self._attr_supported_features = WaterHeaterEntityFeature.OPERATION_MODE
if self._supports_temperature_control: if self._supports_temperature_control:
@ -154,11 +157,10 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
self._current_tado_hvac_mode = CONST_MODE_SMART_SCHEDULE self._current_tado_hvac_mode = CONST_MODE_SMART_SCHEDULE
self._overlay_mode = CONST_MODE_SMART_SCHEDULE self._overlay_mode = CONST_MODE_SMART_SCHEDULE
self._tado_zone_data = None self._tado_zone_data: PyTado.TadoZone = {}
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Register for sensor updates.""" """Register for sensor updates."""
self.async_on_remove( self.async_on_remove(
async_dispatcher_connect( async_dispatcher_connect(
self.hass, self.hass,
@ -171,27 +173,27 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
self._async_update_data() self._async_update_data()
@property @property
def current_operation(self): def current_operation(self) -> str | None:
"""Return current readable operation mode.""" """Return current readable operation mode."""
return WATER_HEATER_MAP_TADO.get(self._current_tado_hvac_mode) return WATER_HEATER_MAP_TADO.get(self._current_tado_hvac_mode)
@property @property
def target_temperature(self): def target_temperature(self) -> float | None:
"""Return the temperature we try to reach.""" """Return the temperature we try to reach."""
return self._tado_zone_data.target_temp return self._tado_zone_data.target_temp
@property @property
def is_away_mode_on(self): def is_away_mode_on(self) -> bool:
"""Return true if away mode is on.""" """Return true if away mode is on."""
return self._tado_zone_data.is_away return self._tado_zone_data.is_away
@property @property
def min_temp(self): def min_temp(self) -> float:
"""Return the minimum temperature.""" """Return the minimum temperature."""
return self._min_temperature return self._min_temperature
@property @property
def max_temp(self): def max_temp(self) -> float:
"""Return the maximum temperature.""" """Return the maximum temperature."""
return self._max_temperature return self._max_temperature
@ -208,7 +210,7 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
self._control_heater(hvac_mode=mode) self._control_heater(hvac_mode=mode)
def set_timer(self, time_period, temperature=None): def set_timer(self, time_period: int, temperature: float | None = None):
"""Set the timer on the entity, and temperature if supported.""" """Set the timer on the entity, and temperature if supported."""
if not self._supports_temperature_control and temperature is not None: if not self._supports_temperature_control and temperature is not None:
temperature = None temperature = None
@ -234,21 +236,25 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
self._control_heater(target_temp=temperature, hvac_mode=CONST_MODE_HEAT) self._control_heater(target_temp=temperature, hvac_mode=CONST_MODE_HEAT)
@callback @callback
def _async_update_callback(self): def _async_update_callback(self) -> None:
"""Load tado data and update state.""" """Load tado data and update state."""
self._async_update_data() self._async_update_data()
self.async_write_ha_state() self.async_write_ha_state()
@callback @callback
def _async_update_data(self): def _async_update_data(self) -> None:
"""Load tado data.""" """Load tado data."""
_LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id) _LOGGER.debug("Updating water_heater platform for zone %d", self.zone_id)
self._tado_zone_data = self._tado.data["zone"][self.zone_id] self._tado_zone_data = self._tado.data["zone"][self.zone_id]
self._current_tado_hvac_mode = self._tado_zone_data.current_hvac_mode self._current_tado_hvac_mode = self._tado_zone_data.current_hvac_mode
def _control_heater(self, hvac_mode=None, target_temp=None, duration=None): def _control_heater(
self,
hvac_mode: str | None = None,
target_temp: float | None = None,
duration: int | None = None,
):
"""Send new target temperature.""" """Send new target temperature."""
if hvac_mode: if hvac_mode:
self._current_tado_hvac_mode = hvac_mode self._current_tado_hvac_mode = hvac_mode