diff --git a/custom_components/versatile_thermostat/base_thermostat.py b/custom_components/versatile_thermostat/base_thermostat.py index 177dd24..8b7bc2d 100644 --- a/custom_components/versatile_thermostat/base_thermostat.py +++ b/custom_components/versatile_thermostat/base_thermostat.py @@ -6,6 +6,8 @@ import math import logging from datetime import timedelta, datetime +from types import MappingProxyType +from typing import Any from homeassistant.util import dt as dt_util from homeassistant.core import ( @@ -20,10 +22,12 @@ from homeassistant.components.climate import ClimateEntity from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType +from homeassistant.helpers.typing import EventType as HASSEventType from homeassistant.helpers.event import ( async_track_state_change_event, async_call_later, + EventStateChangedData, ) from homeassistant.exceptions import ConditionError @@ -134,6 +138,7 @@ from .open_window_algorithm import WindowOpenDetectionAlgorithm from .ema import ExponentialMovingAverage _LOGGER = logging.getLogger(__name__) +ConfigData = MappingProxyType[str, Any] def get_tz(hass: HomeAssistant): @@ -197,7 +202,13 @@ class BaseThermostat(ClimateEntity, RestoreEntity): ) ) - def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None: + def __init__( + self, + hass: HomeAssistant, + unique_id: str, + name: str, + entry_infos: ConfigData, + ): """Initialize the thermostat.""" super().__init__() @@ -262,7 +273,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._last_change_time = None - self._underlyings = [] + self._underlyings: list[UnderlyingEntity] = [] self._ema_temp = None self._ema_algo = None @@ -276,7 +287,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.post_init(entry_infos) - def clean_central_config_doublon(self, config_entry, central_config) -> dict: + def clean_central_config_doublon( + self, config_entry: ConfigData, central_config: ConfigEntry | None + ) -> dict[str, Any]: """Removes all values from config with are concerned by central_config""" def clean_one(cfg, schema: vol.Schema): @@ -322,7 +335,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): return entry_infos - def post_init(self, config_entry): + def post_init(self, config_entry: ConfigData): """Finish the initialization of the thermostast""" _LOGGER.info( @@ -345,7 +358,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._attr_target_temperature_step = step # convert entry_infos into usable attributes - presets = {} + presets: dict[str, Any] = {} items = CONF_PRESETS_WITH_AC.items() if self._ac_mode else CONF_PRESETS.items() for key, value in items: _LOGGER.debug("looking for key=%s, value=%s", key, value) @@ -357,7 +370,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._attr_max_temp if self._ac_mode else self._attr_min_temp ) - presets_away = {} + presets_away: dict[str, Any] = {} items = ( CONF_PRESETS_AWAY_WITH_AC.items() if self._ac_mode @@ -805,7 +818,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): def init_underlyings(self): """Initialize all underlyings. Should be overriden if necessary""" - def restore_specific_previous_state(self, old_state): + def restore_specific_previous_state(self, old_state: State): """Should be overriden in each specific thermostat if a specific previous state or attribute should be restored @@ -886,7 +899,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._hvac_mode, ) - def __str__(self): + def __str__(self) -> str: return f"VersatileThermostat-{self.name}" @property @@ -916,19 +929,19 @@ class BaseThermostat(ClimateEntity, RestoreEntity): ) @property - def unique_id(self): + def unique_id(self) -> str: return self._unique_id @property - def should_poll(self): + def should_poll(self) -> bool: return False @property - def name(self): + def name(self) -> str: return self._name @property - def hvac_modes(self): + def hvac_modes(self) -> list[HVACMode]: """List of available operation modes.""" return self._hvac_list @@ -1016,17 +1029,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity): return self._is_used_by_central_boiler @property - def target_temperature(self): + def target_temperature(self) -> float | None: """Return the temperature we try to reach.""" return self._target_temp @property - def supported_features(self): + def supported_features(self) -> ClimateEntityFeature: """Return the list of supported features.""" return self._support_flags @property - def is_device_active(self): + def is_device_active(self) -> bool: """Returns true if one underlying is active""" for under in self._underlyings: if under.is_device_active: @@ -1034,7 +1047,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): return False @property - def current_temperature(self): + def current_temperature(self) -> float | None: """Return the sensor temperature.""" return self._cur_temp @@ -1203,7 +1216,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): """Turn auxiliary heater off.""" raise NotImplementedError() - async def async_set_hvac_mode(self, hvac_mode, need_control_heating=True): + async def async_set_hvac_mode(self, hvac_mode: HVACMode, need_control_heating=True): """Set new target hvac mode.""" _LOGGER.info("%s - Set hvac mode: %s", self, hvac_mode) @@ -1239,7 +1252,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": self._hvac_mode}) @overrides - async def async_set_preset_mode(self, preset_mode, overwrite_saved_preset=True): + async def async_set_preset_mode( + self, preset_mode: str, overwrite_saved_preset=True + ): """Set new preset mode.""" await self._async_set_preset_mode_internal( preset_mode, force=False, overwrite_saved_preset=overwrite_saved_preset @@ -1247,7 +1262,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): await self.async_control_heating(force=True) async def _async_set_preset_mode_internal( - self, preset_mode, force=False, overwrite_saved_preset=True + self, preset_mode: str, force=False, overwrite_saved_preset=True ): """Set new preset mode.""" _LOGGER.info("%s - Set preset_mode: %s force=%s", self, preset_mode, force) @@ -1296,13 +1311,13 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.send_event(EventType.PRESET_EVENT, {"preset": self._attr_preset_mode}) def reset_last_change_time( - self, old_preset_mode=None + self, old_preset_mode: str | None = None ): # pylint: disable=unused-argument """Reset to now the last change time""" self._last_change_time = datetime.now(tz=self._current_tz) _LOGGER.debug("%s - last_change_time is now %s", self, self._last_change_time) - def reset_last_temperature_time(self, old_preset_mode=None): + def reset_last_temperature_time(self, old_preset_mode: str | None = None): """Reset to now the last temperature time if conditions are satisfied""" if ( self._attr_preset_mode not in HIDDEN_PRESETS @@ -1312,7 +1327,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._last_ext_temperature_measure ) = datetime.now(tz=self._current_tz) - def find_preset_temp(self, preset_mode): + def find_preset_temp(self, preset_mode: str): """Find the right temperature of a preset considering the presence if configured""" if preset_mode is None or preset_mode == "none": return ( @@ -1348,11 +1363,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity): else: return self._presets_away[self.get_preset_away_name(preset_mode)] - def get_preset_away_name(self, preset_mode): + def get_preset_away_name(self, preset_mode: str) -> str: """Get the preset name in away mode (when presence is off)""" return preset_mode + PRESET_AWAY_SUFFIX - async def async_set_fan_mode(self, fan_mode): + async def async_set_fan_mode(self, fan_mode: str): """Set new target fan mode.""" _LOGGER.info("%s - Set fan mode: %s", self, fan_mode) return @@ -1362,7 +1377,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): _LOGGER.info("%s - Set fan mode: %s", self, humidity) return - async def async_set_swing_mode(self, swing_mode): + async def async_set_swing_mode(self, swing_mode: str): """Set new target swing operation.""" _LOGGER.info("%s - Set fan mode: %s", self, swing_mode) return @@ -1379,14 +1394,14 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.reset_last_change_time() await self.async_control_heating(force=True) - async def _async_internal_set_temperature(self, temperature): + async def _async_internal_set_temperature(self, temperature: float): """Set the target temperature and the target temperature of underlying climate if any For testing purpose you can pass an event_timestamp. """ self._target_temp = temperature return - def get_state_date_or_now(self, state: State): + def get_state_date_or_now(self, state: State) -> datetime: """Extract the last_changed state from State or return now if not available""" return ( state.last_changed.astimezone(self._current_tz) @@ -1394,7 +1409,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): else datetime.now(tz=self._current_tz) ) - def get_last_updated_date_or_now(self, state: State): + def get_last_updated_date_or_now(self, state: State) -> datetime: """Extract the last_changed state from State or return now if not available""" return ( state.last_updated.astimezone(self._current_tz) @@ -1679,7 +1694,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): _LOGGER.error("Unable to update external temperature from sensor: %s", ex) @callback - async def _async_power_changed(self, event): + async def _async_power_changed(self, event: HASSEventType[EventStateChangedData]): """Handle power changes.""" _LOGGER.debug("Thermostat %s - Receive new Power event", self.name) _LOGGER.debug(event) @@ -1705,7 +1720,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): _LOGGER.error("Unable to update current_power from sensor: %s", ex) @callback - async def _async_max_power_changed(self, event): + async def _async_max_power_changed( + self, event: HASSEventType[EventStateChangedData] + ): """Handle power max changes.""" _LOGGER.debug("Thermostat %s - Receive new Power Max event", self.name) _LOGGER.debug(event) @@ -1730,7 +1747,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): _LOGGER.error("Unable to update current_power from sensor: %s", ex) @callback - async def _async_presence_changed(self, event): + async def _async_presence_changed( + self, event: HASSEventType[EventStateChangedData] + ): """Handle presence changes.""" new_state = event.data.get("new_state") _LOGGER.info( @@ -1746,7 +1765,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): await self._async_update_presence(new_state.state) await self.async_control_heating(force=True) - async def _async_update_presence(self, new_state): + async def _async_update_presence(self, new_state: str): _LOGGER.info("%s - Updating presence. New state is %s", self, new_state) self._presence_state = ( STATE_ON if new_state in (STATE_ON, STATE_HOME) else STATE_OFF @@ -2044,7 +2063,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): return self._overpowering_state - async def check_central_mode(self, new_central_mode, old_central_mode) -> None: + async def check_central_mode( + self, new_central_mode: str | None, old_central_mode: str | None + ): """Take into account a central mode change""" if not self.is_controlled_by_central_mode: self._last_central_mode = None @@ -2334,7 +2355,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): else: # default is to turn_off await self.async_set_hvac_mode(HVACMode.OFF) - async def async_control_heating(self, force=False, _=None): + async def async_control_heating(self, force=False, _=None) -> bool: """The main function used to run the calculation at each cycle""" _LOGGER.debug( @@ -2402,7 +2423,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): def update_custom_attributes(self): """Update the custom extra attributes for the entity""" - self._attr_extra_state_attributes: dict(str, str) = { + self._attr_extra_state_attributes: dict[str, Any] = { "is_on": self.is_on, "hvac_action": self.hvac_action, "hvac_mode": self.hvac_mode, @@ -2483,7 +2504,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): """ _LOGGER.info("%s - The config entry have been updated") - async def service_set_presence(self, presence): + async def service_set_presence(self, presence: str): """Called by a service call: service: versatile_thermostat.set_presence data: @@ -2496,7 +2517,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity): await self.async_control_heating(force=True) async def service_set_preset_temperature( - self, preset, temperature=None, temperature_away=None + self, + preset: str, + temperature: float | None = None, + temperature_away: float | None = None, ): """Called by a service call: service: versatile_thermostat.set_preset_temperature @@ -2534,7 +2558,12 @@ class BaseThermostat(ClimateEntity, RestoreEntity): ) await self.async_control_heating(force=True) - async def service_set_security(self, delay_min, min_on_percent, default_on_percent): + async def service_set_security( + self, + delay_min: int | None, + min_on_percent: float | None, + default_on_percent: float | None, + ): """Called by a service call: service: versatile_thermostat.set_security data: @@ -2564,7 +2593,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): await self.async_control_heating() self.update_custom_attributes() - async def service_set_window_bypass_state(self, window_bypass): + async def service_set_window_bypass_state(self, window_bypass: bool): """Called by a service call: service: versatile_thermostat.set_window_bypass data: diff --git a/custom_components/versatile_thermostat/select.py b/custom_components/versatile_thermostat/select.py index 0ed16bd..554dda7 100644 --- a/custom_components/versatile_thermostat/select.py +++ b/custom_components/versatile_thermostat/select.py @@ -14,8 +14,10 @@ from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_component import EntityComponent - -from custom_components.versatile_thermostat.base_thermostat import BaseThermostat +from custom_components.versatile_thermostat.base_thermostat import ( + BaseThermostat, + ConfigData, +) from .const import ( DOMAIN, DEVICE_MANUFACTURER, @@ -57,7 +59,9 @@ async def async_setup_entry( class CentralModeSelect(SelectEntity, RestoreEntity): """Representation of the central mode choice""" - def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None: + def __init__( + self, hass: HomeAssistant, unique_id: str, name: str, entry_infos: ConfigData + ): """Initialize the energy sensor""" self._config_id = unique_id self._device_name = entry_infos.get(CONF_NAME) @@ -67,7 +71,7 @@ class CentralModeSelect(SelectEntity, RestoreEntity): self._attr_current_option = CENTRAL_MODE_AUTO @property - def icon(self) -> str | None: + def icon(self) -> str: return "mdi:form-select" @property @@ -116,7 +120,7 @@ class CentralModeSelect(SelectEntity, RestoreEntity): self._attr_current_option = option await self.notify_central_mode_change(old_central_mode=old_option) - async def notify_central_mode_change(self, old_central_mode=None): + async def notify_central_mode_change(self, old_central_mode: str | None = None): """Notify all VTherm that the central_mode have change""" # Update all VTherm states component: EntityComponent[ClimateEntity] = self.hass.data[CLIMATE_DOMAIN] @@ -130,5 +134,5 @@ class CentralModeSelect(SelectEntity, RestoreEntity): self._attr_current_option, old_central_mode ) - def __str__(self): + def __str__(self) -> str: return f"VersatileThermostat-{self.name}" diff --git a/custom_components/versatile_thermostat/thermostat_climate.py b/custom_components/versatile_thermostat/thermostat_climate.py index 1807daa..a938d07 100644 --- a/custom_components/versatile_thermostat/thermostat_climate.py +++ b/custom_components/versatile_thermostat/thermostat_climate.py @@ -3,12 +3,13 @@ import logging from datetime import timedelta, datetime -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant, State, callback from homeassistant.helpers.event import ( async_track_state_change_event, async_track_time_interval, + EventStateChangedData, ) - +from homeassistant.helpers.typing import EventType as HASSEventType from homeassistant.components.climate import ( HVACAction, HVACMode, @@ -16,7 +17,7 @@ from homeassistant.components.climate import ( ) from .commons import NowClass, round_to_nearest -from .base_thermostat import BaseThermostat +from .base_thermostat import BaseThermostat, ConfigData from .pi_algorithm import PITemperatureRegulator from .const import ( @@ -59,19 +60,19 @@ _LOGGER = logging.getLogger(__name__) class ThermostatOverClimate(BaseThermostat): """Representation of a base class for a Versatile Thermostat over a climate""" - _auto_regulation_mode: str = None + _auto_regulation_mode: str | None = None _regulation_algo = None - _regulated_target_temp: float = None - _auto_regulation_dtemp: float = None - _auto_regulation_period_min: int = None - _last_regulation_change: datetime = None + _regulated_target_temp: float | None = None + _auto_regulation_dtemp: float | None = None + _auto_regulation_period_min: int | None = None + _last_regulation_change: datetime | None = None # The fan mode configured in configEntry - _auto_fan_mode: str = None + _auto_fan_mode: str | None = None # The current fan mode (could be change by service call) - _current_auto_fan_mode: str = None + _current_auto_fan_mode: str | None = None # The fan_mode name depending of the current_mode - _auto_activated_fan_mode: str = None - _auto_deactivated_fan_mode: str = None + _auto_activated_fan_mode: str | None = None + _auto_deactivated_fan_mode: str | None = None _entity_component_unrecorded_attributes = ( BaseThermostat._entity_component_unrecorded_attributes.union( @@ -94,7 +95,9 @@ class ThermostatOverClimate(BaseThermostat): ) ) - def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None: + def __init__( + self, hass: HomeAssistant, unique_id: str, name: str, entry_infos: ConfigData + ): """Initialize the thermostat over switch.""" # super.__init__ calls post_init at the end. So it must be called after regulation initialization super().__init__(hass, unique_id, name, entry_infos) @@ -127,7 +130,7 @@ class ThermostatOverClimate(BaseThermostat): return HVACAction.OFF @overrides - async def _async_internal_set_temperature(self, temperature): + async def _async_internal_set_temperature(self, temperature: float): """Set the target temperature and the target temperature of underlying climate if any""" await super()._async_internal_set_temperature(temperature) @@ -239,7 +242,7 @@ class ThermostatOverClimate(BaseThermostat): await self.async_set_fan_mode(self._auto_deactivated_fan_mode) @overrides - def post_init(self, config_entry): + def post_init(self, config_entry: ConfigData): """Initialize the Thermostat""" super().post_init(config_entry) @@ -281,7 +284,7 @@ class ThermostatOverClimate(BaseThermostat): else CONF_AUTO_FAN_NONE ) - def choose_auto_regulation_mode(self, auto_regulation_mode): + def choose_auto_regulation_mode(self, auto_regulation_mode: str): """Choose or change the regulation mode""" self._auto_regulation_mode = auto_regulation_mode if self._auto_regulation_mode == CONF_AUTO_REGULATION_LIGHT: @@ -357,7 +360,7 @@ class ThermostatOverClimate(BaseThermostat): self.target_temperature, 0, 0, 0, 0, 0.1, 0 ) - def choose_auto_fan_mode(self, auto_fan_mode): + def choose_auto_fan_mode(self, auto_fan_mode: str): """Choose the correct fan mode depending of the underlying capacities and the configuration""" self._current_auto_fan_mode = auto_fan_mode @@ -369,7 +372,7 @@ class ThermostatOverClimate(BaseThermostat): self._auto_activated_fan_mode = self._auto_deactivated_fan_mode = None return - def find_fan_mode(fan_modes, fan_mode) -> str: + def find_fan_mode(fan_modes: list[str], fan_mode: str) -> str | None: """Return the fan_mode if it exist of None if not""" try: return fan_mode if fan_modes.index(fan_mode) >= 0 else None @@ -430,7 +433,7 @@ class ThermostatOverClimate(BaseThermostat): self.choose_auto_regulation_mode(self._auto_regulation_mode) @overrides - def restore_specific_previous_state(self, old_state): + def restore_specific_previous_state(self, old_state: State): """Restore my specific attributes from previous state""" old_error = old_state.attributes.get("regulation_accumulated_error") if old_error: @@ -542,7 +545,7 @@ class ThermostatOverClimate(BaseThermostat): ) @callback - async def _async_climate_changed(self, event): + async def _async_climate_changed(self, event: HASSEventType[EventStateChangedData]): """Handle unerdlying climate state changes. This method takes the underlying values and update the VTherm with them. To avoid loops (issues #121 #101 #95 #99), we discard the event if it is received @@ -552,7 +555,7 @@ class ThermostatOverClimate(BaseThermostat): which is important for feedaback and which cannot generates loops. """ - async def end_climate_changed(changes): + async def end_climate_changed(changes: bool): """To end the event management""" if changes: self.async_write_ha_state() @@ -745,7 +748,7 @@ class ThermostatOverClimate(BaseThermostat): await end_climate_changed(changes) @overrides - async def async_control_heating(self, force=False, _=None): + async def async_control_heating(self, force=False, _=None) -> bool: """The main function used to run the calculation at each cycle""" ret = await super().async_control_heating(force, _) @@ -757,27 +760,27 @@ class ThermostatOverClimate(BaseThermostat): return ret @property - def auto_regulation_mode(self): + def auto_regulation_mode(self) -> str | None: """Get the regulation mode""" return self._auto_regulation_mode @property - def auto_fan_mode(self): + def auto_fan_mode(self) -> str | None: """Get the auto fan mode""" return self._auto_fan_mode @property - def regulated_target_temp(self): + def regulated_target_temp(self) -> float | None: """Get the regulated target temperature""" return self._regulated_target_temp @property - def is_regulated(self): + def is_regulated(self) -> bool: """Check if the ThermostatOverClimate is regulated""" return self.auto_regulation_mode != CONF_AUTO_REGULATION_NONE @property - def hvac_modes(self): + def hvac_modes(self) -> list[HVACMode]: """List of available operation modes.""" if self.underlying_entity(0): return self.underlying_entity(0).hvac_modes @@ -944,7 +947,7 @@ class ThermostatOverClimate(BaseThermostat): await under.async_turn_aux_heat_off() @overrides - async def async_set_fan_mode(self, fan_mode): + async def async_set_fan_mode(self, fan_mode: str): """Set new target fan mode.""" _LOGGER.info("%s - Set fan mode: %s", self, fan_mode) if fan_mode is None: @@ -977,7 +980,7 @@ class ThermostatOverClimate(BaseThermostat): self._swing_mode = swing_mode self.async_write_ha_state() - async def service_set_auto_regulation_mode(self, auto_regulation_mode): + async def service_set_auto_regulation_mode(self, auto_regulation_mode: str): """Called by a service call: service: versatile_thermostat.set_auto_regulation_mode data: @@ -1006,7 +1009,7 @@ class ThermostatOverClimate(BaseThermostat): await self._send_regulated_temperature() self.update_custom_attributes() - async def service_set_auto_fan_mode(self, auto_fan_mode): + async def service_set_auto_fan_mode(self, auto_fan_mode: str): """Called by a service call: service: versatile_thermostat.set_auto_fan_mode data: diff --git a/custom_components/versatile_thermostat/thermostat_switch.py b/custom_components/versatile_thermostat/thermostat_switch.py index 761c244..99c69ee 100644 --- a/custom_components/versatile_thermostat/thermostat_switch.py +++ b/custom_components/versatile_thermostat/thermostat_switch.py @@ -3,7 +3,11 @@ """ A climate over switch classe """ import logging from homeassistant.core import callback -from homeassistant.helpers.event import async_track_state_change_event +from homeassistant.helpers.event import ( + async_track_state_change_event, + EventStateChangedData, +) +from homeassistant.helpers.typing import EventType as HASSEventType from homeassistant.components.climate import HVACMode from .const import ( @@ -15,7 +19,7 @@ from .const import ( overrides, ) -from .base_thermostat import BaseThermostat +from .base_thermostat import BaseThermostat, ConfigData from .underlyings import UnderlyingSwitch from .prop_algorithm import PropAlgorithm @@ -51,7 +55,7 @@ class ThermostatOverSwitch(BaseThermostat): # def __init__(self, hass: HomeAssistant, unique_id, name, config_entry) -> None: # """Initialize the thermostat over switch.""" # super().__init__(hass, unique_id, name, config_entry) - _is_inversed: bool = None + _is_inversed: bool | None = None @property def is_over_switch(self) -> bool: @@ -72,7 +76,7 @@ class ThermostatOverSwitch(BaseThermostat): return None @overrides - def post_init(self, config_entry): + def post_init(self, config_entry: ConfigData): """Initialize the Thermostat""" super().post_init(config_entry) @@ -200,7 +204,7 @@ class ThermostatOverSwitch(BaseThermostat): ) @callback - def _async_switch_changed(self, event): + def _async_switch_changed(self, event: HASSEventType[EventStateChangedData]): """Handle heater switch state changes.""" new_state = event.data.get("new_state") old_state = event.data.get("old_state") diff --git a/custom_components/versatile_thermostat/thermostat_valve.py b/custom_components/versatile_thermostat/thermostat_valve.py index 295af31..a42585d 100644 --- a/custom_components/versatile_thermostat/thermostat_valve.py +++ b/custom_components/versatile_thermostat/thermostat_valve.py @@ -6,11 +6,13 @@ from datetime import timedelta, datetime from homeassistant.helpers.event import ( async_track_state_change_event, async_track_time_interval, + EventStateChangedData, ) +from homeassistant.helpers.typing import EventType as HASSEventType from homeassistant.core import HomeAssistant, callback from homeassistant.components.climate import HVACMode -from .base_thermostat import BaseThermostat +from .base_thermostat import BaseThermostat, ConfigData from .prop_algorithm import PropAlgorithm from .const import ( @@ -55,12 +57,14 @@ class ThermostatOverValve(BaseThermostat): ) ) - def __init__(self, hass: HomeAssistant, unique_id, name, config_entry) -> None: + def __init__( + self, hass: HomeAssistant, unique_id: str, name: str, config_entry: ConfigData + ): """Initialize the thermostat over switch.""" self._valve_open_percent: int = 0 - self._last_calculation_timestamp: datetime = None - self._auto_regulation_dpercent: float = None - self._auto_regulation_period_min: int = None + self._last_calculation_timestamp: datetime | None = None + self._auto_regulation_dpercent: float | None = None + self._auto_regulation_period_min: int | None = None # Call to super must be done after initialization because it calls post_init at the end super().__init__(hass, unique_id, name, config_entry) @@ -79,7 +83,7 @@ class ThermostatOverValve(BaseThermostat): return self._valve_open_percent @overrides - def post_init(self, config_entry): + def post_init(self, config_entry: ConfigData): """Initialize the Thermostat""" super().post_init(config_entry) @@ -144,7 +148,7 @@ class ThermostatOverValve(BaseThermostat): ) @callback - async def _async_valve_changed(self, event): + async def _async_valve_changed(self, event: HASSEventType[EventStateChangedData]): """Handle unerdlying valve state changes. This method just log the change. It changes nothing to avoid loops. """