Compare commits

..

2 Commits

Author SHA1 Message Date
Jean-Marc Collin 5063374b97 Allow calculation even if slope is None 2024-10-31 22:29:30 +00:00
Jean-Marc Collin 461db8d86c Change algo to take slop into account 2024-10-31 21:57:55 +00:00
3 changed files with 24 additions and 21 deletions
@@ -79,7 +79,7 @@ class AutoStartStopDetectionAlgorithm:
saved_hvac_mode: HVACMode | None, saved_hvac_mode: HVACMode | None,
target_temp: float, target_temp: float,
current_temp: float, current_temp: float,
slope_min: float, slope_min: float | None,
now: datetime, now: datetime,
) -> AUTO_START_STOP_ACTIONS: ) -> AUTO_START_STOP_ACTIONS:
"""Calculate an eventual action to do depending of the value in parameter""" """Calculate an eventual action to do depending of the value in parameter"""
@@ -101,12 +101,7 @@ class AutoStartStopDetectionAlgorithm:
now, now,
) )
if ( if hvac_mode is None or target_temp is None or current_temp is None:
hvac_mode is None
or target_temp is None
or current_temp is None
or slope_min is None
):
_LOGGER.debug( _LOGGER.debug(
"%s - No all mandatory parameters are set. Disable auto-start/stop", "%s - No all mandatory parameters are set. Disable auto-start/stop",
self, self,
@@ -119,8 +114,8 @@ class AutoStartStopDetectionAlgorithm:
# reduce the error considering the dt between the last measurement # reduce the error considering the dt between the last measurement
if self._last_calculation_date is not None: if self._last_calculation_date is not None:
dtmin = (now - self._last_calculation_date).total_seconds() / CYCLE_SEC dtmin = (now - self._last_calculation_date).total_seconds() / CYCLE_SEC
# ignore two calls too near (< 1 min) # ignore two calls too near (< 24 sec)
if dtmin <= 0.5: if dtmin <= 0.2:
_LOGGER.debug( _LOGGER.debug(
"%s - new calculation of auto_start_stop (%s) is too near of the last one (%s). Forget it", "%s - new calculation of auto_start_stop (%s) is too near of the last one (%s). Forget it",
self, self,
@@ -144,10 +139,15 @@ class AutoStartStopDetectionAlgorithm:
self._last_calculation_date = now self._last_calculation_date = now
temp_at_dt = current_temp + slope_min * self._dt
# Check to turn-off # Check to turn-off
# When we hit the threshold, that mean we can turn off # When we hit the threshold, that mean we can turn off
if hvac_mode == HVACMode.HEAT: if hvac_mode == HVACMode.HEAT:
if self._accumulated_error <= -self._error_threshold and slope_min >= 0: if (
self._accumulated_error <= -self._error_threshold
and temp_at_dt >= target_temp
):
_LOGGER.info( _LOGGER.info(
"%s - We need to stop, there is no need for heating for a long time.", "%s - We need to stop, there is no need for heating for a long time.",
self, self,
@@ -158,7 +158,10 @@ class AutoStartStopDetectionAlgorithm:
return AUTO_START_STOP_ACTION_NOTHING return AUTO_START_STOP_ACTION_NOTHING
if hvac_mode == HVACMode.COOL: if hvac_mode == HVACMode.COOL:
if self._accumulated_error >= self._error_threshold and slope_min <= 0: if (
self._accumulated_error >= self._error_threshold
and temp_at_dt <= target_temp
):
_LOGGER.info( _LOGGER.info(
"%s - We need to stop, there is no need for cooling for a long time.", "%s - We need to stop, there is no need for cooling for a long time.",
self, self,
@@ -173,7 +176,7 @@ class AutoStartStopDetectionAlgorithm:
# check to turn on # check to turn on
if hvac_mode == HVACMode.OFF and saved_hvac_mode == HVACMode.HEAT: if hvac_mode == HVACMode.OFF and saved_hvac_mode == HVACMode.HEAT:
if current_temp + slope_min * self._dt <= target_temp: if temp_at_dt <= target_temp:
_LOGGER.info( _LOGGER.info(
"%s - We need to start, because it will be time to heat", "%s - We need to start, because it will be time to heat",
self, self,
@@ -187,7 +190,7 @@ class AutoStartStopDetectionAlgorithm:
return AUTO_START_STOP_ACTION_NOTHING return AUTO_START_STOP_ACTION_NOTHING
if hvac_mode == HVACMode.OFF and saved_hvac_mode == HVACMode.COOL: if hvac_mode == HVACMode.OFF and saved_hvac_mode == HVACMode.COOL:
if current_temp + slope_min * self._dt >= target_temp: if temp_at_dt >= target_temp:
_LOGGER.info( _LOGGER.info(
"%s - We need to start, because it will be time to cool", "%s - We need to start, because it will be time to cool",
self, self,
@@ -8,7 +8,6 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -912,16 +912,16 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
ret = await super().async_control_heating(force, _) ret = await super().async_control_heating(force, _)
# Check if we need to auto start/stop the Vtherm # Check if we need to auto start/stop the Vtherm
if ( if self.auto_start_stop_enable:
self.auto_start_stop_enable slope = (
and self._window_auto_algo.last_slope is not None self._window_auto_algo.last_slope or 0
): ) / 60 # to have the slope in °/min
action = self._auto_start_stop_algo.calculate_action( action = self._auto_start_stop_algo.calculate_action(
self.hvac_mode, self.hvac_mode,
self._saved_hvac_mode, self._saved_hvac_mode,
self.target_temperature, self.target_temperature,
self.current_temperature, self.current_temperature,
self._window_auto_algo.last_slope / 60, # to have the slope in °/min slope,
self.now, self.now,
) )
_LOGGER.debug("%s - auto_start_stop action is %s", self, action) _LOGGER.debug("%s - auto_start_stop action is %s", self, action)
@@ -943,7 +943,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
"saved_hvac_mode": self._saved_hvac_mode, "saved_hvac_mode": self._saved_hvac_mode,
"target_temperature": self.target_temperature, "target_temperature": self.target_temperature,
"current_temperature": self.current_temperature, "current_temperature": self.current_temperature,
"temperature_slope": self._window_auto_algo.last_slope, "temperature_slope": slope,
}, },
) )
@@ -966,7 +966,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
"saved_hvac_mode": self._saved_hvac_mode, "saved_hvac_mode": self._saved_hvac_mode,
"target_temperature": self.target_temperature, "target_temperature": self.target_temperature,
"current_temperature": self.current_temperature, "current_temperature": self.current_temperature,
"temperature_slope": self._window_auto_algo.last_slope, "temperature_slope": slope,
}, },
) )
@@ -987,6 +987,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
def set_auto_start_stop_enable(self, is_enabled: bool): def set_auto_start_stop_enable(self, is_enabled: bool):
"""Enable/Disable the auto-start/stop feature""" """Enable/Disable the auto-start/stop feature"""
self._is_auto_start_stop_enabled = is_enabled self._is_auto_start_stop_enabled = is_enabled
self.update_custom_attributes()
@property @property
def auto_regulation_mode(self) -> str | None: def auto_regulation_mode(self) -> str | None: