Fix too much shedding in over_climate
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -172,16 +172,17 @@ async def test_overpowering_binary_sensors(
|
||||
# Send power mesurement
|
||||
side_effects = SideEffects(
|
||||
{
|
||||
"sensor.the_power_sensor": State("sensor.the_power_sensor", 100),
|
||||
"sensor.the_max_power_sensor": State("sensor.the_max_power_sensor", 150),
|
||||
"sensor.the_power_sensor": State("sensor.the_power_sensor", 150),
|
||||
"sensor.the_max_power_sensor": State("sensor.the_max_power_sensor", 100),
|
||||
},
|
||||
State("unknown.entity_id", "unknown"),
|
||||
)
|
||||
# fmt:off
|
||||
with patch("homeassistant.core.StateMachine.get", side_effect=side_effects.get_side_effects()):
|
||||
with patch("homeassistant.core.StateMachine.get", side_effect=side_effects.get_side_effects()), \
|
||||
patch("custom_components.versatile_thermostat.thermostat_switch.ThermostatOverSwitch.is_device_active", return_value="True"):
|
||||
# fmt: on
|
||||
await send_power_change_event(entity, 100, now)
|
||||
await send_max_power_change_event(entity, 150, now)
|
||||
await send_power_change_event(entity, 150, now)
|
||||
await send_max_power_change_event(entity, 100, now)
|
||||
|
||||
assert entity.power_manager.is_overpowering_detected is True
|
||||
assert entity.power_manager.overpowering_state is STATE_ON
|
||||
|
||||
@@ -348,7 +348,7 @@ async def test_bug_407(
|
||||
await entity.async_set_preset_mode(PRESET_COMFORT)
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
assert entity.preset_mode is PRESET_COMFORT
|
||||
assert entity.power_manager.overpowering_state is STATE_OFF
|
||||
assert entity.power_manager.overpowering_state is STATE_UNKNOWN
|
||||
assert entity.target_temperature == 18
|
||||
# waits that the heater starts
|
||||
await hass.async_block_till_done()
|
||||
@@ -398,7 +398,8 @@ async def test_bug_407(
|
||||
assert entity.target_temperature == 19
|
||||
assert mock_service_call.call_count >= 1
|
||||
|
||||
# 3. if heater is stopped (is_device_active==False), then overpowering should be started
|
||||
# 3. if heater is stopped (is_device_active==False) and power is over max, then overpowering should be started
|
||||
side_effects.add_or_update_side_effect("sensor.the_power_sensor", State("sensor.the_power_sensor", 150))
|
||||
with patch(
|
||||
"homeassistant.core.ServiceRegistry.async_call"
|
||||
) as mock_service_call, patch(
|
||||
@@ -420,10 +421,10 @@ async def test_bug_407(
|
||||
# simulate a refresh for central power (not necessary)
|
||||
await do_central_power_refresh(hass)
|
||||
|
||||
assert entity.power_manager.is_overpowering_detected is True
|
||||
assert entity.power_manager.is_overpowering_detected is False
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
assert entity.preset_mode is PRESET_POWER
|
||||
assert entity.power_manager.overpowering_state is STATE_ON
|
||||
assert entity.preset_mode is PRESET_COMFORT
|
||||
assert entity.power_manager.overpowering_state is STATE_OFF
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
|
||||
@@ -273,7 +273,7 @@ async def test_central_power_manageer_find_vtherms(
|
||||
@pytest.mark.parametrize(
|
||||
"current_power, current_max_power, vtherm_configs, expected_results",
|
||||
[
|
||||
# simple nominal test (no shedding)
|
||||
# simple nominal test (initialize overpowering state in VTherm)
|
||||
(
|
||||
1000,
|
||||
5000,
|
||||
@@ -286,139 +286,32 @@ async def test_central_power_manageer_find_vtherms(
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 0,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
],
|
||||
{"vtherm1": False},
|
||||
),
|
||||
# Simple trivial shedding
|
||||
(
|
||||
1000,
|
||||
2000,
|
||||
[
|
||||
# should be overpowering
|
||||
{
|
||||
"name": "vtherm1",
|
||||
"device_power": 1100,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
# should be overpowering with many underlmying entities
|
||||
{
|
||||
"name": "vtherm2",
|
||||
"device_power": 4000,
|
||||
"is_device_active": False,
|
||||
"device_power": 10000,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 4,
|
||||
"on_percent": 0.1,
|
||||
"on_percent": 100,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
# over_climate should be overpowering
|
||||
{
|
||||
"name": "vtherm3",
|
||||
"device_power": 1000,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
# should pass but because will be also overpowering because previous was overpowering
|
||||
{
|
||||
"name": "vtherm4",
|
||||
"device_power": 800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
],
|
||||
{"vtherm1": True, "vtherm2": True, "vtherm3": True, "vtherm4": True},
|
||||
),
|
||||
# More complex shedding
|
||||
(
|
||||
1000,
|
||||
2000,
|
||||
[
|
||||
# already overpowering (non change)
|
||||
{
|
||||
"name": "vtherm1",
|
||||
"device_power": 1100,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
},
|
||||
# already overpowering and already active (can be un overpowered)
|
||||
{
|
||||
"name": "vtherm2",
|
||||
"device_power": 1100,
|
||||
"device_power": 5000,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": True,
|
||||
},
|
||||
# should terminate the overpowering
|
||||
{
|
||||
"name": "vtherm3",
|
||||
"device_power": 800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
},
|
||||
# should terminate the overpowering and active
|
||||
{
|
||||
"name": "vtherm4",
|
||||
"device_power": 3800,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
},
|
||||
],
|
||||
{"vtherm2": False, "vtherm3": False, "vtherm4": False},
|
||||
),
|
||||
# More complex shedding
|
||||
(
|
||||
1000,
|
||||
2000,
|
||||
[
|
||||
# already overpowering (non change)
|
||||
{
|
||||
"name": "vtherm1",
|
||||
"device_power": 1100,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
},
|
||||
# should be overpowering
|
||||
{
|
||||
"name": "vtherm2",
|
||||
"device_power": 1800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
# should terminate the overpowering and active but just before is overpowering
|
||||
{
|
||||
"name": "vtherm3",
|
||||
"device_power": 100,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
{"name": "vtherm4", "device_power": 1000, "is_device_active": True, "is_over_climate": True, "is_overpowering_detected": False, "overpowering_state": STATE_OFF},
|
||||
],
|
||||
{"vtherm1": False, "vtherm2": True, "vtherm3": True},
|
||||
# init vtherm1 to False
|
||||
{"vtherm3": False, "vtherm2": False, "vtherm1": False},
|
||||
),
|
||||
# Sheeding only current_power > max_power (need to gain 1000 )
|
||||
# Shedding
|
||||
(
|
||||
2000,
|
||||
1000,
|
||||
@@ -432,36 +325,31 @@ async def test_central_power_manageer_find_vtherms(
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_OFF,
|
||||
},
|
||||
# should be overpowering but is already
|
||||
# should be overpowering with many underlmying entities
|
||||
{
|
||||
"name": "vtherm2",
|
||||
"device_power": 600,
|
||||
"device_power": 400,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 4,
|
||||
"on_percent": 0.1,
|
||||
"is_overpowering_detected": True,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
# over_climate should be not overpowering (device not active)
|
||||
# over_climate should be overpowering
|
||||
{
|
||||
"name": "vtherm3",
|
||||
"device_power": 690,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
# over_climate should be overpowering (device active and not already overpowering)
|
||||
{
|
||||
"name": "vtherm4",
|
||||
"device_power": 690,
|
||||
"device_power": 100,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_OFF,
|
||||
},
|
||||
# should not overpower (keep as is)
|
||||
# should pass cause not active
|
||||
{
|
||||
"name": "vtherm5",
|
||||
"name": "vtherm4",
|
||||
"device_power": 800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
@@ -469,8 +357,98 @@ async def test_central_power_manageer_find_vtherms(
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": False,
|
||||
},
|
||||
# should be not overpowering (already overpowering)
|
||||
{
|
||||
"name": "vtherm5",
|
||||
"device_power": 400,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 4,
|
||||
"on_percent": 0.1,
|
||||
"is_overpowering_detected": True,
|
||||
"overpowering_state": STATE_ON,
|
||||
},
|
||||
# should be overpowering with many underluying entities
|
||||
{
|
||||
"name": "vtherm6",
|
||||
"device_power": 400,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 4,
|
||||
"on_percent": 0.1,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
# should not be overpowering (we have enough)
|
||||
{
|
||||
"name": "vtherm7",
|
||||
"device_power": 1000,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_UNKNOWN,
|
||||
},
|
||||
],
|
||||
{"vtherm1": True, "vtherm4": True},
|
||||
{"vtherm1": True, "vtherm2": True, "vtherm3": True, "vtherm6": True},
|
||||
),
|
||||
# Un-shedding only (will be taken in reverse order)
|
||||
(
|
||||
1000,
|
||||
2000,
|
||||
[
|
||||
# should be not unshedded (we have enough)
|
||||
{
|
||||
"name": "vtherm0",
|
||||
"device_power": 800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
"overpowering_state": STATE_ON,
|
||||
},
|
||||
# should be unshedded
|
||||
{
|
||||
"name": "vtherm1",
|
||||
"device_power": 800,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
"overpowering_state": STATE_ON,
|
||||
},
|
||||
# already stay unshedded cause already unshedded
|
||||
{
|
||||
"name": "vtherm2",
|
||||
"device_power": 1100,
|
||||
"is_device_active": True,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": False,
|
||||
"overpowering_state": STATE_OFF,
|
||||
},
|
||||
# should be unshedded
|
||||
{
|
||||
"name": "vtherm3",
|
||||
"device_power": 200,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": True,
|
||||
"is_overpowering_detected": True,
|
||||
"overpowering_state": STATE_ON,
|
||||
},
|
||||
# should be unshedded
|
||||
{
|
||||
"name": "vtherm4",
|
||||
"device_power": 300,
|
||||
"is_device_active": False,
|
||||
"is_over_climate": False,
|
||||
"nb_underlying_entities": 1,
|
||||
"on_percent": 1,
|
||||
"is_overpowering_detected": True,
|
||||
"overpowering_state": STATE_ON,
|
||||
},
|
||||
],
|
||||
{"vtherm4": False, "vtherm3": False, "vtherm1": False},
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -501,7 +479,10 @@ async def test_central_power_manageer_calculate_shedding(
|
||||
vtherm.nb_underlying_entities = vtherm_config.get("nb_underlying_entities")
|
||||
if not vtherm_config.get("is_over_climate"):
|
||||
vtherm.proportional_algorithm = MagicMock()
|
||||
vtherm.proportional_algorithm.on_percent = vtherm_config.get("on_percent")
|
||||
vtherm.on_percent = vtherm.proportional_algorithm.on_percent = vtherm_config.get("on_percent")
|
||||
else:
|
||||
vtherm.on_percent = None
|
||||
vtherm.proportional_algorithm = None
|
||||
|
||||
vtherm.power_manager = MagicMock(spec=FeaturePowerManager)
|
||||
vtherm.power_manager._vtherm = vtherm
|
||||
@@ -510,6 +491,7 @@ async def test_central_power_manageer_calculate_shedding(
|
||||
"is_overpowering_detected"
|
||||
)
|
||||
vtherm.power_manager.device_power = vtherm_config.get("device_power")
|
||||
vtherm.power_manager.overpowering_state = vtherm_config.get("overpowering_state")
|
||||
|
||||
async def mock_set_overpowering(
|
||||
overpowering, power_consumption_max=0, v=vtherm
|
||||
|
||||
@@ -812,21 +812,20 @@ async def test_multiple_switch_power_management(
|
||||
assert entity.power_manager.overpowering_state is STATE_OFF
|
||||
|
||||
# 2. Send power max mesurement too low and HVACMode is on
|
||||
side_effects.add_or_update_side_effect("sensor.the_max_power_sensor", State("sensor.the_max_power_sensor", 74))
|
||||
side_effects.add_or_update_side_effect("sensor.the_max_power_sensor", State("sensor.the_max_power_sensor", 49))
|
||||
|
||||
with patch(
|
||||
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||
) as mock_send_event, patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on"
|
||||
) as mock_heater_on, patch(
|
||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off"
|
||||
) as mock_heater_off:
|
||||
#fmt: off
|
||||
with patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
|
||||
patch("custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on") as mock_heater_on, \
|
||||
patch("custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off") as mock_heater_off, \
|
||||
patch("custom_components.versatile_thermostat.thermostat_switch.ThermostatOverSwitch.is_device_active", return_value="True"):
|
||||
#fmt: on
|
||||
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())
|
||||
await send_max_power_change_event(entity, 49, datetime.now())
|
||||
assert entity.power_manager.is_overpowering_detected is True
|
||||
# All configuration is complete and power is > power_max we switch to POWER preset
|
||||
assert entity.preset_mode is PRESET_POWER
|
||||
@@ -843,7 +842,7 @@ async def test_multiple_switch_power_management(
|
||||
"type": "start",
|
||||
"current_power": 50,
|
||||
"device_power": 100,
|
||||
"current_max_power": 74,
|
||||
"current_max_power": 49,
|
||||
"current_power_consumption": 100,
|
||||
},
|
||||
),
|
||||
|
||||
@@ -517,17 +517,18 @@ async def test_power_management_hvac_on(
|
||||
assert entity.power_manager.overpowering_state is STATE_OFF
|
||||
|
||||
# Send power max mesurement too low and HVACMode is on
|
||||
side_effects.add_or_update_side_effect("sensor.the_max_power_sensor", State("sensor.the_max_power_sensor", 149))
|
||||
side_effects.add_or_update_side_effect("sensor.the_max_power_sensor", State("sensor.the_max_power_sensor", 49))
|
||||
# fmt:off
|
||||
with patch("homeassistant.core.StateMachine.get", side_effect=side_effects.get_side_effects()), \
|
||||
patch("custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event") as mock_send_event, \
|
||||
patch("custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_on") as mock_heater_on, \
|
||||
patch("custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off") as mock_heater_off:
|
||||
patch("custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.turn_off") as mock_heater_off, \
|
||||
patch("custom_components.versatile_thermostat.thermostat_switch.ThermostatOverSwitch.is_device_active", return_value="True"):
|
||||
# fmt: on
|
||||
now = now + timedelta(seconds=30)
|
||||
VersatileThermostatAPI.get_vtherm_api()._set_now(now)
|
||||
|
||||
await send_max_power_change_event(entity, 149, datetime.now())
|
||||
await send_max_power_change_event(entity, 49, now)
|
||||
assert entity.power_manager.is_overpowering_detected is True
|
||||
# All configuration is complete and power is > power_max we switch to POWER preset
|
||||
assert entity.preset_mode is PRESET_POWER
|
||||
@@ -544,7 +545,7 @@ async def test_power_management_hvac_on(
|
||||
"type": "start",
|
||||
"current_power": 50,
|
||||
"device_power": 100,
|
||||
"current_max_power": 149,
|
||||
"current_max_power": 49,
|
||||
"current_power_consumption": 100.0,
|
||||
},
|
||||
),
|
||||
@@ -554,7 +555,7 @@ async def test_power_management_hvac_on(
|
||||
assert mock_heater_on.call_count == 0
|
||||
assert mock_heater_off.call_count == 1
|
||||
|
||||
# Send power mesurement low to unseet power preset
|
||||
# Send power mesurement low to unset power preset
|
||||
side_effects.add_or_update_side_effect("sensor.the_power_sensor", State("sensor.the_power_sensor", 48))
|
||||
# fmt:off
|
||||
with patch("homeassistant.core.StateMachine.get", side_effect=side_effects.get_side_effects()), \
|
||||
@@ -565,7 +566,7 @@ async def test_power_management_hvac_on(
|
||||
now = now + timedelta(seconds=30)
|
||||
VersatileThermostatAPI.get_vtherm_api()._set_now(now)
|
||||
|
||||
await send_power_change_event(entity, 48, datetime.now())
|
||||
await send_power_change_event(entity, 48, now)
|
||||
assert entity.power_manager.is_overpowering_detected is False
|
||||
# All configuration is complete and power is < power_max, we restore previous preset
|
||||
assert entity.preset_mode is PRESET_BOOST
|
||||
@@ -582,7 +583,7 @@ async def test_power_management_hvac_on(
|
||||
"type": "end",
|
||||
"current_power": 48,
|
||||
"device_power": 100,
|
||||
"current_max_power": 149,
|
||||
"current_max_power": 49,
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user