Fix too much shedding in over_climate

This commit is contained in:
Jean-Marc Collin
2025-01-05 08:44:59 +00:00
parent 460281603f
commit 34181b4204
9 changed files with 192 additions and 221 deletions

View File

@@ -1609,14 +1609,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
return False
# Check overpowering condition
await VersatileThermostatAPI.get_vtherm_api().central_power_manager.refresh_state()
# TODO remove this
# overpowering is now centralized
# overpowering = await self._power_manager.check_overpowering()
# if overpowering == STATE_ON:
# _LOGGER.debug("%s - End of cycle (overpowering)", self)
# return True
# Not usefull. Will be done at the next power refresh
# await VersatileThermostatAPI.get_vtherm_api().central_power_manager.refresh_state()
safety: bool = await self._safety_manager.refresh_state()
if safety and self.is_over_climate:
@@ -1974,5 +1968,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
@property
def power_percent(self) -> float | None:
"""Get the current on_percent as a percentage value. valid only for Vtherm with a TPI algo"""
"""Get the current on_percent value"""
if self._prop_algorithm and self._prop_algorithm.on_percent is not None:
return round(self._prop_algorithm.on_percent * 100, 0)
else:
return None
@property
def on_percent(self) -> float | None:
"""Get the current on_percent value. valid only for Vtherm with a TPI algo"""
return None
if self._prop_algorithm and self._prop_algorithm.on_percent is not None:
return self._prop_algorithm.on_percent
else:
return None

View File

@@ -4,6 +4,7 @@ import logging
from typing import Any
from functools import cmp_to_key
from homeassistant.const import STATE_OFF
from homeassistant.core import HomeAssistant, Event, callback
from homeassistant.helpers.event import (
async_track_state_change_event,
@@ -163,54 +164,52 @@ class CentralFeaturePowerManager(BaseFeatureManager):
total_power_gain = 0
for vtherm in vtherms_sorted:
device_power = vtherm.power_manager.device_power
if vtherm.is_device_active and not vtherm.power_manager.is_overpowering_detected:
device_power = vtherm.power_manager.device_power
total_power_gain += device_power
_LOGGER.debug("vtherm %s should be in overpowering state", vtherm.name)
_LOGGER.info("vtherm %s should be in overpowering state (device_power=%.2f)", vtherm.name, device_power)
await vtherm.power_manager.set_overpowering(True, device_power)
_LOGGER.debug("after vtherm %s total_power_gain=%s, available_power=%s", vtherm.name, total_power_gain, available_power)
if total_power_gain >= -available_power:
_LOGGER.debug("We have found enough vtherm to set to overpowering")
break
# unshedding only
else:
# vtherms_sorted.reverse()
vtherms_sorted.reverse()
_LOGGER.debug("The available power is is > 0 (%s). Do a complete shedding/un-shedding calculation for list: %s", available_power, vtherms_sorted)
total_affected_power = 0
force_overpowering = False
total_power_added = 0
for vtherm in vtherms_sorted:
device_power = vtherm.power_manager.device_power
# We want to do always unshedding in order to initialize the state
# so we cannot use is_overpowering_detected which test also UNKNOWN and UNAVAILABLE
if vtherm.power_manager.overpowering_state == STATE_OFF:
continue
power_consumption_max = device_power = vtherm.power_manager.device_power
# calculate the power_consumption_max
if vtherm.is_device_active:
power_consumption_max = 0
else:
if vtherm.is_over_climate:
power_consumption_max = device_power
else:
if vtherm.proportional_algorithm.on_percent > 0:
power_consumption_max = max(
device_power / vtherm.nb_underlying_entities,
device_power * vtherm.proportional_algorithm.on_percent,
)
else:
power_consumption_max = 0
if vtherm.on_percent is not None:
power_consumption_max = max(
device_power / vtherm.nb_underlying_entities,
device_power * vtherm.on_percent,
)
_LOGGER.debug("vtherm %s power_consumption_max is %s (device_power=%s, overclimate=%s)", vtherm.name, power_consumption_max, device_power, vtherm.is_over_climate)
if force_overpowering or (total_affected_power + power_consumption_max >= available_power):
_LOGGER.debug("vtherm %s should be in overpowering state", vtherm.name)
if not vtherm.power_manager.is_overpowering_detected:
# To force all others vtherms to be in overpowering
force_overpowering = True
await vtherm.power_manager.set_overpowering(True, power_consumption_max)
else:
total_affected_power += power_consumption_max
# Always set to false to init the state
_LOGGER.debug("vtherm %s should not be in overpowering state", vtherm.name)
await vtherm.power_manager.set_overpowering(False)
# if total_power_added + power_consumption_max < available_power or not vtherm.power_manager.is_overpowering_detected:
_LOGGER.info("vtherm %s should not be in overpowering state (power_consumption_max=%.2f)", vtherm.name, power_consumption_max)
_LOGGER.debug("after vtherm %s total_affected_power=%s, available_power=%s", vtherm.name, total_affected_power, available_power)
# we count the unshedding only if the VTherm was in shedding
if vtherm.power_manager.is_overpowering_detected:
total_power_added += power_consumption_max
await vtherm.power_manager.set_overpowering(False)
if total_power_added >= available_power:
_LOGGER.debug("We have found enough vtherm to set to non-overpowering")
break
_LOGGER.debug("after vtherm %s total_power_added=%s, available_power=%s", vtherm.name, total_power_added, available_power)
def get_climate_components_entities(self) -> list:
"""Get all VTherms entitites"""

View File

@@ -263,15 +263,6 @@ class ThermostatOverClimateValve(ThermostatOverClimate):
"""True if the Thermostat is regulated by valve"""
return True
@overrides
@property
def power_percent(self) -> float | None:
"""Get the current on_percent value"""
if self._prop_algorithm:
return round(self._prop_algorithm.on_percent * 100, 0)
else:
return None
# @property
# def hvac_modes(self) -> list[HVACMode]:
# """Get the hvac_modes"""

View File

@@ -61,15 +61,6 @@ class ThermostatOverSwitch(BaseThermostat[UnderlyingSwitch]):
"""True if the switch is inversed (for pilot wire and diode)"""
return self._is_inversed is True
@overrides
@property
def power_percent(self) -> float | None:
"""Get the current on_percent value"""
if self._prop_algorithm:
return round(self._prop_algorithm.on_percent * 100, 0)
else:
return None
@overrides
def post_init(self, config_entry: ConfigData):
"""Initialize the Thermostat"""