From 460281603fed3bb21b20688ec928c21496dcd027 Mon Sep 17 00:00:00 2001 From: Jean-Marc Collin Date: Sat, 4 Jan 2025 19:21:06 +0000 Subject: [PATCH] Fix overpowering is set even if other heater have on_percent = 0 --- .../versatile_thermostat/base_thermostat.py | 5 +++++ .../central_feature_power_manager.py | 12 ++++++++---- .../versatile_thermostat/thermostat_climate_valve.py | 1 + .../versatile_thermostat/thermostat_switch.py | 1 + tests/test_multiple_switch.py | 12 +++++++++--- tests/test_power.py | 7 +++++++ 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/custom_components/versatile_thermostat/base_thermostat.py b/custom_components/versatile_thermostat/base_thermostat.py index 6b31ec8..d063e9f 100644 --- a/custom_components/versatile_thermostat/base_thermostat.py +++ b/custom_components/versatile_thermostat/base_thermostat.py @@ -1971,3 +1971,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]): """Get now. The local datetime or the overloaded _set_now date This method should be replaced by the vthermAPI equivalent""" return VersatileThermostatAPI.get_vtherm_api(self._hass).now + + @property + def power_percent(self) -> float | None: + """Get the current on_percent value. valid only for Vtherm with a TPI algo""" + return None diff --git a/custom_components/versatile_thermostat/central_feature_power_manager.py b/custom_components/versatile_thermostat/central_feature_power_manager.py index 9275ee3..af1a8c9 100644 --- a/custom_components/versatile_thermostat/central_feature_power_manager.py +++ b/custom_components/versatile_thermostat/central_feature_power_manager.py @@ -182,16 +182,20 @@ class CentralFeaturePowerManager(BaseFeatureManager): for vtherm in vtherms_sorted: 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: - power_consumption_max = max( - device_power / vtherm.nb_underlying_entities, - device_power * vtherm.proportional_algorithm.on_percent, - ) + 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 _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): diff --git a/custom_components/versatile_thermostat/thermostat_climate_valve.py b/custom_components/versatile_thermostat/thermostat_climate_valve.py index 064fc08..f7aada2 100644 --- a/custom_components/versatile_thermostat/thermostat_climate_valve.py +++ b/custom_components/versatile_thermostat/thermostat_climate_valve.py @@ -263,6 +263,7 @@ 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""" diff --git a/custom_components/versatile_thermostat/thermostat_switch.py b/custom_components/versatile_thermostat/thermostat_switch.py index 6fbfda6..f7eea02 100644 --- a/custom_components/versatile_thermostat/thermostat_switch.py +++ b/custom_components/versatile_thermostat/thermostat_switch.py @@ -61,6 +61,7 @@ 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""" diff --git a/tests/test_multiple_switch.py b/tests/test_multiple_switch.py index 648afbd..f053032 100644 --- a/tests/test_multiple_switch.py +++ b/tests/test_multiple_switch.py @@ -783,6 +783,11 @@ async def test_multiple_switch_power_management( assert entity.power_manager.overpowering_state is STATE_UNKNOWN assert entity.target_temperature == 19 + # make the heater heats + await send_temperature_change_event(entity, 15, now) + await send_ext_temperature_change_event(entity, 1, now) + await hass.async_block_till_done() + # 1. Send power mesurement side_effects = SideEffects( { @@ -816,9 +821,10 @@ async def test_multiple_switch_power_management( ) as mock_heater_on, patch( "custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off" ) as mock_heater_off: - now = now + timedelta(seconds=30) VersatileThermostatAPI.get_vtherm_api()._set_now(now) + + assert entity.power_percent > 0 # 100 of the device / 4 -> 25, current power 50 so max is 75 await send_max_power_change_event(entity, 74, datetime.now()) assert entity.power_manager.is_overpowering_detected is True @@ -838,7 +844,7 @@ async def test_multiple_switch_power_management( "current_power": 50, "device_power": 100, "current_max_power": 74, - "current_power_consumption": 25.0, + "current_power_consumption": 100, }, ), ], @@ -856,7 +862,7 @@ async def test_multiple_switch_power_management( await entity.async_set_preset_mode(PRESET_ECO) assert entity.preset_mode is PRESET_ECO - # No change + # No change cause temperature is very low assert entity.power_manager.overpowering_state is STATE_ON # 4. Send hugh power max mesurement to release overpowering diff --git a/tests/test_power.py b/tests/test_power.py index 74dce38..99e40b8 100644 --- a/tests/test_power.py +++ b/tests/test_power.py @@ -487,6 +487,13 @@ async def test_power_management_hvac_on( assert entity.power_manager.overpowering_state is STATE_UNKNOWN assert entity.target_temperature == 19 + # make the heater heats + await send_temperature_change_event(entity, 15, now) + await send_ext_temperature_change_event(entity, 1, now) + await hass.async_block_till_done() + + assert entity.power_percent > 0 + # Send power mesurement side_effects = SideEffects( {