Compare commits
4 Commits
6.3.0.beta
...
6.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f95ed74f4 | ||
|
|
6e42904ddf | ||
|
|
4c1fc396fb | ||
|
|
d6ec7a86be |
@@ -13,7 +13,6 @@ from homeassistant.util import dt as dt_util
|
|||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
callback,
|
callback,
|
||||||
CoreState,
|
|
||||||
Event,
|
Event,
|
||||||
State,
|
State,
|
||||||
)
|
)
|
||||||
@@ -57,7 +56,6 @@ from homeassistant.const import (
|
|||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
EVENT_HOMEASSISTANT_START,
|
|
||||||
STATE_HOME,
|
STATE_HOME,
|
||||||
STATE_NOT_HOME,
|
STATE_NOT_HOME,
|
||||||
)
|
)
|
||||||
@@ -299,7 +297,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
self._presets: dict[str, Any] = {} # presets
|
self._presets: dict[str, Any] = {} # presets
|
||||||
self._presets_away: dict[str, Any] = {} # presets_away
|
self._presets_away: dict[str, Any] = {} # presets_away
|
||||||
|
|
||||||
self._attr_preset_modes: list[str] | None
|
self._attr_preset_modes: list[str] = []
|
||||||
|
|
||||||
self._use_central_config_temperature = False
|
self._use_central_config_temperature = False
|
||||||
|
|
||||||
@@ -2183,7 +2181,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity, Generic[T]):
|
|||||||
new_central_mode,
|
new_central_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
first_init = self._last_central_mode == None
|
first_init = self._last_central_mode is None
|
||||||
|
|
||||||
self._last_central_mode = new_central_mode
|
self._last_central_mode = new_central_mode
|
||||||
|
|
||||||
|
|||||||
@@ -99,30 +99,31 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
def _init_feature_flags(self, _):
|
def _init_feature_flags(self, _):
|
||||||
"""Fix features selection depending to infos"""
|
"""Fix features selection depending to infos"""
|
||||||
is_empty: bool = False # TODO remove this not bool(infos)
|
|
||||||
is_central_config = (
|
is_central_config = (
|
||||||
self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
|
self._infos.get(CONF_THERMOSTAT_TYPE) == CONF_THERMOSTAT_CENTRAL_CONFIG
|
||||||
)
|
)
|
||||||
|
|
||||||
self._infos[CONF_USE_WINDOW_FEATURE] = (
|
self._infos[CONF_USE_WINDOW_FEATURE] = (
|
||||||
is_empty
|
self._infos.get(CONF_USE_WINDOW_CENTRAL_CONFIG)
|
||||||
or self._infos.get(CONF_WINDOW_SENSOR) is not None
|
or self._infos.get(CONF_WINDOW_SENSOR) is not None
|
||||||
or self._infos.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD) is not None
|
or self._infos.get(CONF_WINDOW_AUTO_OPEN_THRESHOLD) is not None
|
||||||
)
|
)
|
||||||
self._infos[CONF_USE_MOTION_FEATURE] = (
|
self._infos[CONF_USE_MOTION_FEATURE] = self._infos.get(
|
||||||
is_empty
|
CONF_USE_MOTION_FEATURE
|
||||||
or self._infos.get(CONF_MOTION_SENSOR) is not None
|
) and (self._infos.get(CONF_MOTION_SENSOR) is not None or is_central_config)
|
||||||
or is_central_config
|
|
||||||
)
|
self._infos[CONF_USE_POWER_FEATURE] = self._infos.get(
|
||||||
self._infos[CONF_USE_POWER_FEATURE] = is_empty or (
|
CONF_USE_POWER_CENTRAL_CONFIG
|
||||||
|
) or (
|
||||||
self._infos.get(CONF_POWER_SENSOR) is not None
|
self._infos.get(CONF_POWER_SENSOR) is not None
|
||||||
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
|
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
|
||||||
)
|
)
|
||||||
self._infos[CONF_USE_PRESENCE_FEATURE] = (
|
self._infos[CONF_USE_PRESENCE_FEATURE] = (
|
||||||
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
self._infos.get(CONF_USE_PRESENCE_CENTRAL_CONFIG)
|
||||||
|
or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] = is_empty or (
|
self._infos[CONF_USE_CENTRAL_BOILER_FEATURE] = (
|
||||||
self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV) is not None
|
self._infos.get(CONF_CENTRAL_BOILER_ACTIVATION_SRV) is not None
|
||||||
and self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV) is not None
|
and self._infos.get(CONF_CENTRAL_BOILER_DEACTIVATION_SRV) is not None
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ PROPORTIONAL_MIN_DURATION_SEC = 10
|
|||||||
FUNCTION_TYPE = [PROPORTIONAL_FUNCTION_ATAN, PROPORTIONAL_FUNCTION_LINEAR]
|
FUNCTION_TYPE = [PROPORTIONAL_FUNCTION_ATAN, PROPORTIONAL_FUNCTION_LINEAR]
|
||||||
|
|
||||||
|
|
||||||
|
def is_number(value):
|
||||||
|
return isinstance(value, (int, float))
|
||||||
|
|
||||||
|
|
||||||
class PropAlgorithm:
|
class PropAlgorithm:
|
||||||
"""This class aims to do all calculation of the Proportional alogorithm"""
|
"""This class aims to do all calculation of the Proportional alogorithm"""
|
||||||
|
|
||||||
@@ -36,6 +40,30 @@ class PropAlgorithm:
|
|||||||
cycle_min,
|
cycle_min,
|
||||||
minimal_activation_delay,
|
minimal_activation_delay,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Issue 506 - check parameters
|
||||||
|
if (
|
||||||
|
vtherm_entity_id is None
|
||||||
|
or not is_number(tpi_coef_int)
|
||||||
|
or not is_number(tpi_coef_ext)
|
||||||
|
or not is_number(cycle_min)
|
||||||
|
or not is_number(minimal_activation_delay)
|
||||||
|
or function_type != PROPORTIONAL_FUNCTION_TPI
|
||||||
|
):
|
||||||
|
_LOGGER.error(
|
||||||
|
"%s - configuration is wrong. function_type=%s, entity_id is %s, tpi_coef_int is %s, tpi_coef_ext is %s, cycle_min is %s, minimal_activation_delay is %s",
|
||||||
|
vtherm_entity_id,
|
||||||
|
function_type,
|
||||||
|
vtherm_entity_id,
|
||||||
|
tpi_coef_int,
|
||||||
|
tpi_coef_ext,
|
||||||
|
cycle_min,
|
||||||
|
minimal_activation_delay,
|
||||||
|
)
|
||||||
|
raise TypeError(
|
||||||
|
f"TPI parameters are not set correctly. VTherm will not work as expected. Please reconfigure it correctly. See previous log for values"
|
||||||
|
)
|
||||||
|
|
||||||
self._vtherm_entity_id = vtherm_entity_id
|
self._vtherm_entity_id = vtherm_entity_id
|
||||||
self._function = function_type
|
self._function = function_type
|
||||||
self._tpi_coef_int = tpi_coef_int
|
self._tpi_coef_int = tpi_coef_int
|
||||||
|
|||||||
@@ -145,6 +145,12 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
_LOGGER.debug("%s - don't send regulated temperature cause VTherm is off ")
|
_LOGGER.debug("%s - don't send regulated temperature cause VTherm is off ")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.current_temperature is None or self.target_temperature is None:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"%s - don't send regulated temperature cause VTherm current_temp (%s) or target_temp (%s) is None. This should be a temporary warning message."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"%s - Calling ThermostatClimate._send_regulated_temperature force=%s",
|
"%s - Calling ThermostatClimate._send_regulated_temperature force=%s",
|
||||||
self,
|
self,
|
||||||
@@ -172,7 +178,7 @@ class ThermostatOverClimate(BaseThermostat[UnderlyingClimate]):
|
|||||||
_LOGGER.debug("%s - usage of regulation_step: %.2f ",
|
_LOGGER.debug("%s - usage of regulation_step: %.2f ",
|
||||||
self,
|
self,
|
||||||
regulation_step)
|
regulation_step)
|
||||||
|
|
||||||
new_regulated_temp = round_to_nearest(
|
new_regulated_temp = round_to_nearest(
|
||||||
self._regulation_algo.calculate_regulated_temperature(
|
self._regulation_algo.calculate_regulated_temperature(
|
||||||
self.current_temperature, self._cur_ext_temp
|
self.current_temperature, self._cur_ext_temp
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ from homeassistant.components.climate import (
|
|||||||
SERVICE_SET_TEMPERATURE,
|
SERVICE_SET_TEMPERATURE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from homeassistant.config_entries import SOURCE_USER, ConfigEntry
|
||||||
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
|
from custom_components.versatile_thermostat.config_flow import (
|
||||||
|
VersatileThermostatBaseConfigFlow,
|
||||||
|
)
|
||||||
from .commons import *
|
from .commons import *
|
||||||
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
@@ -1013,3 +1019,72 @@ async def test_bug_508(
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_1(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
||||||
|
CONF_USE_MOTION_FEATURE: True,
|
||||||
|
CONF_MOTION_SENSOR: "sensor.theMotionSensor",
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_2(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is False
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_bug_500_3(hass: HomeAssistant, init_vtherm_api) -> None:
|
||||||
|
"""Test that the form is served with no input"""
|
||||||
|
|
||||||
|
config = {
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_USE_WINDOW_CENTRAL_CONFIG: False,
|
||||||
|
CONF_WINDOW_SENSOR: "sensor.theWindowSensor",
|
||||||
|
CONF_USE_POWER_CENTRAL_CONFIG: False,
|
||||||
|
CONF_POWER_SENSOR: "sensor.thePowerSensor",
|
||||||
|
CONF_MAX_POWER_SENSOR: "sensor.theMaxPowerSensor",
|
||||||
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
|
CONF_PRESENCE_SENSOR: "sensor.thePresenceSensor",
|
||||||
|
CONF_USE_MOTION_FEATURE: True, # motion sensor need to be checked AND a motion sensor set
|
||||||
|
CONF_MOTION_SENSOR: "sensor.theMotionSensor",
|
||||||
|
}
|
||||||
|
|
||||||
|
flow = VersatileThermostatBaseConfigFlow(config)
|
||||||
|
|
||||||
|
assert flow._infos[CONF_USE_WINDOW_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_POWER_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_PRESENCE_FEATURE] is True
|
||||||
|
assert flow._infos[CONF_USE_MOTION_FEATURE] is True
|
||||||
|
|||||||
@@ -254,6 +254,9 @@ async def test_over_switch_deactivate_preset(
|
|||||||
CONF_HEATER_KEEP_ALIVE: 0,
|
CONF_HEATER_KEEP_ALIVE: 0,
|
||||||
CONF_SECURITY_DELAY_MIN: 10,
|
CONF_SECURITY_DELAY_MIN: 10,
|
||||||
CONF_MINIMAL_ACTIVATION_DELAY: 10,
|
CONF_MINIMAL_ACTIVATION_DELAY: 10,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
CONF_TPI_COEF_INT: 0.6,
|
||||||
|
CONF_TPI_COEF_EXT: 0.01,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ async def test_add_number_for_central_config(
|
|||||||
CONF_SECURITY_MIN_ON_PERCENT: 0.5,
|
CONF_SECURITY_MIN_ON_PERCENT: 0.5,
|
||||||
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.2,
|
CONF_SECURITY_DEFAULT_ON_PERCENT: 0.2,
|
||||||
CONF_USE_CENTRAL_BOILER_FEATURE: False,
|
CONF_USE_CENTRAL_BOILER_FEATURE: False,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
}
|
}
|
||||||
| temps,
|
| temps,
|
||||||
)
|
)
|
||||||
@@ -156,6 +157,7 @@ async def test_add_number_for_central_config_without_temp(
|
|||||||
CONF_TEMP_MAX: 30,
|
CONF_TEMP_MAX: 30,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_WINDOW_DELAY: 15,
|
CONF_WINDOW_DELAY: 15,
|
||||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
||||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
||||||
@@ -250,6 +252,7 @@ async def test_add_number_for_central_config_without_temp_ac_mode(
|
|||||||
CONF_AC_MODE: True,
|
CONF_AC_MODE: True,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_WINDOW_DELAY: 15,
|
CONF_WINDOW_DELAY: 15,
|
||||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
||||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
||||||
@@ -343,6 +346,7 @@ async def test_add_number_for_central_config_without_temp_restore(
|
|||||||
CONF_AC_MODE: False,
|
CONF_AC_MODE: False,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_WINDOW_DELAY: 15,
|
CONF_WINDOW_DELAY: 15,
|
||||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
CONF_WINDOW_AUTO_OPEN_THRESHOLD: 4,
|
||||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
CONF_WINDOW_AUTO_CLOSE_THRESHOLD: 1,
|
||||||
@@ -441,6 +445,7 @@ async def test_add_number_for_over_switch_use_central(
|
|||||||
CONF_AC_MODE: False,
|
CONF_AC_MODE: False,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
||||||
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
CONF_USE_ADVANCED_CENTRAL_CONFIG: True,
|
||||||
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
CONF_USE_MAIN_CENTRAL_CONFIG: True,
|
||||||
@@ -666,6 +671,7 @@ async def test_add_number_for_over_switch_use_central_presets_and_restore(
|
|||||||
CONF_AC_MODE: False,
|
CONF_AC_MODE: False,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
CONF_HEATER: "switch.mock_switch1",
|
CONF_HEATER: "switch.mock_switch1",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
@@ -788,6 +794,7 @@ async def test_change_central_config_temperature(
|
|||||||
CONF_TEMP_MAX: 30,
|
CONF_TEMP_MAX: 30,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
@@ -823,6 +830,7 @@ async def test_change_central_config_temperature(
|
|||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
@@ -905,6 +913,7 @@ async def test_change_vtherm_temperature(
|
|||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: True,
|
||||||
@@ -939,6 +948,7 @@ async def test_change_vtherm_temperature(
|
|||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
CONF_USE_PRESENCE_CENTRAL_CONFIG: False,
|
||||||
@@ -1022,6 +1032,7 @@ async def test_change_vtherm_temperature_with_presence(
|
|||||||
CONF_TEMP_MAX: 30,
|
CONF_TEMP_MAX: 30,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
CONF_AC_MODE: True,
|
CONF_AC_MODE: True,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
@@ -1063,6 +1074,7 @@ async def test_change_vtherm_temperature_with_presence(
|
|||||||
CONF_TEMP_MAX: 30,
|
CONF_TEMP_MAX: 30,
|
||||||
CONF_TPI_COEF_INT: 0.5,
|
CONF_TPI_COEF_INT: 0.5,
|
||||||
CONF_TPI_COEF_EXT: 0.02,
|
CONF_TPI_COEF_EXT: 0.02,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
CONF_CYCLE_MIN: 5,
|
CONF_CYCLE_MIN: 5,
|
||||||
CONF_VALVE: "switch.mock_valve",
|
CONF_VALVE: "switch.mock_valve",
|
||||||
CONF_USE_PRESENCE_FEATURE: True,
|
CONF_USE_PRESENCE_FEATURE: True,
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
from homeassistant.components.climate import HVACMode
|
from homeassistant.components.climate import HVACMode
|
||||||
|
|
||||||
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
from custom_components.versatile_thermostat.base_thermostat import BaseThermostat
|
||||||
from custom_components.versatile_thermostat.prop_algorithm import PropAlgorithm
|
from custom_components.versatile_thermostat.prop_algorithm import (
|
||||||
|
PropAlgorithm,
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
)
|
||||||
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||||
|
|
||||||
|
|
||||||
@@ -121,3 +124,123 @@ async def test_tpi_calculation(
|
|||||||
assert tpi_algo.calculated_on_percent == 0
|
assert tpi_algo.calculated_on_percent == 0
|
||||||
assert tpi_algo.on_time_sec == 0
|
assert tpi_algo.on_time_sec == 0
|
||||||
assert tpi_algo.off_time_sec == 300
|
assert tpi_algo.off_time_sec == 300
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_wrong_tpi_parameters(
|
||||||
|
hass: HomeAssistant, skip_hass_states_is_state: None
|
||||||
|
): # pylint: disable=unused-argument
|
||||||
|
"""Test the wrong TPI parameters"""
|
||||||
|
|
||||||
|
# Nominal case
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
0.6,
|
||||||
|
0.01,
|
||||||
|
5,
|
||||||
|
1,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert True
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
assert False
|
||||||
|
|
||||||
|
# Test TPI function
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
"WRONG",
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test coef_int
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test coef_ext
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
0.6,
|
||||||
|
None,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test cycle_min
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
0.6,
|
||||||
|
0.00001,
|
||||||
|
None,
|
||||||
|
3,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test minimal_activation_delay
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
0.6,
|
||||||
|
0.00001,
|
||||||
|
0,
|
||||||
|
None,
|
||||||
|
"entity_id",
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Test vtherm_entity_id
|
||||||
|
try:
|
||||||
|
algo = PropAlgorithm(
|
||||||
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
0.6,
|
||||||
|
0.00001,
|
||||||
|
0,
|
||||||
|
12,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
# We should not be there
|
||||||
|
assert False
|
||||||
|
except TypeError as e:
|
||||||
|
# the normal case
|
||||||
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user