Issue #169 - Adds support for Versatile Thermostat UI Card Co-authored-by: Jean-Marc Collin <jean-marc.collin-extern@renault.com>
This commit is contained in:
@@ -213,7 +213,7 @@ switch:
|
|||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
extra_module_url:
|
extra_module_url:
|
||||||
- /config/www/community/better-thermostat-ui-card/better-thermostat-ui-card.js
|
- /config/www/community/versatile-thermostat-ui-card/versatile-thermostat-ui-card.js
|
||||||
themes:
|
themes:
|
||||||
versatile_thermostat_theme:
|
versatile_thermostat_theme:
|
||||||
state-binary_sensor-safety-on-color: "#FF0B0B"
|
state-binary_sensor-safety-on-color: "#FF0B0B"
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
"postCreateCommand": "./container dev-setup",
|
"postCreateCommand": "./container dev-setup",
|
||||||
|
|
||||||
"mounts": [
|
"mounts": [
|
||||||
"source=/Users/jmcollin/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
|
"source=/Users/jmcollin/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
|
||||||
|
// uncomment this to get the versatile-thermostat-ui-card
|
||||||
|
"source=${localEnv:HOME}/SugarSync/Projets/home-assistant/versatile-thermostat-ui-card/dist,target=/workspaces/versatile_thermostat/config/www/community/versatile-thermostat-ui-card,type=bind,consistency=cached"
|
||||||
],
|
],
|
||||||
|
|
||||||
"customizations": {
|
"customizations": {
|
||||||
@@ -22,7 +24,7 @@
|
|||||||
"ms-python.vscode-pylance"
|
"ms-python.vscode-pylance"
|
||||||
],
|
],
|
||||||
// "mounts": [
|
// "mounts": [
|
||||||
// "source=${localWorkspaceFolder}/.devcontainer/configuration.yaml,target=/home/vscode/core/config/configuration.yaml,type=bind,consistency=cached",
|
// "source=${localWorkspaceFolder}/.devcontainer/configuration.yaml,target=${localWorkspaceFolder}/config/www/community/,type=bind,consistency=cached",
|
||||||
// "source=${localWorkspaceFolder}/custom_components,target=/home/vscode/core/config/custom_components,type=bind,consistency=cached"
|
// "source=${localWorkspaceFolder}/custom_components,target=/home/vscode/core/config/custom_components,type=bind,consistency=cached"
|
||||||
// ],
|
// ],
|
||||||
"settings": {
|
"settings": {
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -107,4 +107,5 @@ dist
|
|||||||
custom_components/__init__.py
|
custom_components/__init__.py
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
config/**
|
config/**
|
||||||
|
custom_components/hacs
|
||||||
|
|||||||
@@ -621,7 +621,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
):
|
):
|
||||||
self._window_state = window_state.state
|
self._window_state = (window_state.state == STATE_ON)
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s - Window state have been retrieved: %s",
|
"%s - Window state have been retrieved: %s",
|
||||||
self,
|
self,
|
||||||
@@ -954,12 +954,12 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
return self._overpowering_state
|
return self._overpowering_state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def window_state(self) -> bool | None:
|
def window_state(self) -> str | None:
|
||||||
"""Get the window_state"""
|
"""Get the window_state"""
|
||||||
return self._window_state
|
return STATE_ON if self._window_state else STATE_OFF
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def window_auto_state(self) -> bool | None:
|
def window_auto_state(self) -> str | None:
|
||||||
"""Get the window_auto_state"""
|
"""Get the window_auto_state"""
|
||||||
return STATE_ON if self._window_auto_state else STATE_OFF
|
return STATE_ON if self._window_auto_state else STATE_OFF
|
||||||
|
|
||||||
@@ -1307,33 +1307,33 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Window delay condition is not satisfied. Ignore window event"
|
"Window delay condition is not satisfied. Ignore window event"
|
||||||
)
|
)
|
||||||
self._window_state = old_state.state
|
self._window_state = (old_state.state == STATE_ON)
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug("%s - Window delay condition is satisfied", self)
|
_LOGGER.debug("%s - Window delay condition is satisfied", self)
|
||||||
# if not self._saved_hvac_mode:
|
# if not self._saved_hvac_mode:
|
||||||
# self._saved_hvac_mode = self._hvac_mode
|
# self._saved_hvac_mode = self._hvac_mode
|
||||||
|
|
||||||
if self._window_state == new_state.state:
|
if self._window_state == (new_state.state == STATE_ON):
|
||||||
_LOGGER.debug("%s - no change in window state. Forget the event")
|
_LOGGER.debug("%s - no change in window state. Forget the event")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
self._window_state = new_state.state
|
self._window_state = (new_state.state == STATE_ON)
|
||||||
|
|
||||||
#PR - Adding Window ByPass
|
#PR - Adding Window ByPass
|
||||||
_LOGGER.debug("%s - Window ByPass is : %s", self, self._window_bypass_state)
|
_LOGGER.debug("%s - Window ByPass is : %s", self, self._window_bypass_state)
|
||||||
if self._window_bypass_state:
|
if self._window_bypass_state:
|
||||||
_LOGGER.info("%s - Window ByPass is activated. Ignore window event", self)
|
_LOGGER.info("%s - Window ByPass is activated. Ignore window event", self)
|
||||||
else:
|
else:
|
||||||
if self._window_state == STATE_OFF:
|
if not self._window_state:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"%s - Window is closed. Restoring hvac_mode '%s'",
|
"%s - Window is closed. Restoring hvac_mode '%s'",
|
||||||
self,
|
self,
|
||||||
self._saved_hvac_mode,
|
self._saved_hvac_mode,
|
||||||
)
|
)
|
||||||
await self.restore_hvac_mode(True)
|
await self.restore_hvac_mode(True)
|
||||||
elif self._window_state == STATE_ON:
|
elif self._window_state:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"%s - Window is open. Set hvac_mode to '%s'", self, HVACMode.OFF
|
"%s - Window is open. Set hvac_mode to '%s'", self, HVACMode.OFF
|
||||||
)
|
)
|
||||||
@@ -1827,7 +1827,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self._device_power,
|
self._device_power,
|
||||||
)
|
)
|
||||||
|
|
||||||
ret = self._current_power + self._device_power >= self._current_power_max
|
ret = (self._current_power + self._device_power) >= self._current_power_max
|
||||||
if not self._overpowering_state and ret and self._hvac_mode != HVACMode.OFF:
|
if not self._overpowering_state and ret and self._hvac_mode != HVACMode.OFF:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"%s - overpowering is detected. Heater preset will be set to 'power'",
|
"%s - overpowering is detected. Heater preset will be set to 'power'",
|
||||||
@@ -2124,11 +2124,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"saved_preset_mode": self._saved_preset_mode,
|
"saved_preset_mode": self._saved_preset_mode,
|
||||||
"saved_target_temp": self._saved_target_temp,
|
"saved_target_temp": self._saved_target_temp,
|
||||||
"saved_hvac_mode": self._saved_hvac_mode,
|
"saved_hvac_mode": self._saved_hvac_mode,
|
||||||
"window_state": self._window_state,
|
"window_state": self.window_state,
|
||||||
"motion_state": self._motion_state,
|
"motion_state": self._motion_state,
|
||||||
"overpowering_state": self._overpowering_state,
|
"overpowering_state": self.overpowering_state,
|
||||||
"presence_state": self._presence_state,
|
"presence_state": self._presence_state,
|
||||||
"window_auto_state": self._window_auto_state,
|
"window_auto_state": self.window_auto_state,
|
||||||
#PR - Adding Window ByPass
|
#PR - Adding Window ByPass
|
||||||
"window_bypass_state": self._window_bypass_state,
|
"window_bypass_state": self._window_bypass_state,
|
||||||
"security_delay_min": self._security_delay_min,
|
"security_delay_min": self._security_delay_min,
|
||||||
@@ -2258,11 +2258,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"""
|
"""
|
||||||
_LOGGER.info("%s - Calling service_set_window_bypass, window_bypass: %s", self, window_bypass)
|
_LOGGER.info("%s - Calling service_set_window_bypass, window_bypass: %s", self, window_bypass)
|
||||||
self._window_bypass_state = window_bypass
|
self._window_bypass_state = window_bypass
|
||||||
if not self._window_bypass_state and self._window_state == STATE_ON:
|
if not self._window_bypass_state and self._window_state:
|
||||||
_LOGGER.info("%s - Last window state was open & ByPass is now off. Set hvac_mode to '%s'", self, HVACMode.OFF)
|
_LOGGER.info("%s - Last window state was open & ByPass is now off. Set hvac_mode to '%s'", self, HVACMode.OFF)
|
||||||
self.save_hvac_mode()
|
self.save_hvac_mode()
|
||||||
await self.async_set_hvac_mode(HVACMode.OFF)
|
await self.async_set_hvac_mode(HVACMode.OFF)
|
||||||
if self._window_bypass_state and self._window_state == STATE_ON:
|
if self._window_bypass_state and self._window_state:
|
||||||
_LOGGER.info("%s - Last window state was open & ByPass is now on. Set hvac_mode to last available mode", self)
|
_LOGGER.info("%s - Last window state was open & ByPass is now on. Set hvac_mode to last available mode", self)
|
||||||
await self.restore_hvac_mode(True)
|
await self.restore_hvac_mode(True)
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ async def async_setup_entry(
|
|||||||
platform.async_register_entity_service(
|
platform.async_register_entity_service(
|
||||||
SERVICE_SET_AUTO_REGULATION_MODE,
|
SERVICE_SET_AUTO_REGULATION_MODE,
|
||||||
{
|
{
|
||||||
vol.Required("auto_regulation_mode"): vol.In(["None", "Light", "Medium", "Strong"]),
|
vol.Required("auto_regulation_mode"): vol.In(["None", "Light", "Medium", "Strong", "Slow"]),
|
||||||
},
|
},
|
||||||
"service_set_auto_regulation_mode",
|
"service_set_auto_regulation_mode",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ CONF_VALVE_3 = "valve_entity3_id"
|
|||||||
CONF_VALVE_4 = "valve_entity4_id"
|
CONF_VALVE_4 = "valve_entity4_id"
|
||||||
CONF_AUTO_REGULATION_MODE= "auto_regulation_mode"
|
CONF_AUTO_REGULATION_MODE= "auto_regulation_mode"
|
||||||
CONF_AUTO_REGULATION_NONE= "auto_regulation_none"
|
CONF_AUTO_REGULATION_NONE= "auto_regulation_none"
|
||||||
|
CONF_AUTO_REGULATION_SLOW= "auto_regulation_slow"
|
||||||
CONF_AUTO_REGULATION_LIGHT= "auto_regulation_light"
|
CONF_AUTO_REGULATION_LIGHT= "auto_regulation_light"
|
||||||
CONF_AUTO_REGULATION_MEDIUM= "auto_regulation_medium"
|
CONF_AUTO_REGULATION_MEDIUM= "auto_regulation_medium"
|
||||||
CONF_AUTO_REGULATION_STRONG= "auto_regulation_strong"
|
CONF_AUTO_REGULATION_STRONG= "auto_regulation_strong"
|
||||||
@@ -207,7 +208,7 @@ CONF_FUNCTIONS = [
|
|||||||
PROPORTIONAL_FUNCTION_TPI,
|
PROPORTIONAL_FUNCTION_TPI,
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF_AUTO_REGULATION_MODES = [CONF_AUTO_REGULATION_NONE, CONF_AUTO_REGULATION_LIGHT, CONF_AUTO_REGULATION_MEDIUM, CONF_AUTO_REGULATION_STRONG]
|
CONF_AUTO_REGULATION_MODES = [CONF_AUTO_REGULATION_NONE, CONF_AUTO_REGULATION_LIGHT, CONF_AUTO_REGULATION_MEDIUM, CONF_AUTO_REGULATION_STRONG, CONF_AUTO_REGULATION_SLOW]
|
||||||
|
|
||||||
CONF_THERMOSTAT_TYPES = [CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE, CONF_THERMOSTAT_VALVE]
|
CONF_THERMOSTAT_TYPES = [CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE, CONF_THERMOSTAT_VALVE]
|
||||||
|
|
||||||
@@ -225,6 +226,16 @@ DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1
|
|||||||
ATTR_TOTAL_ENERGY = "total_energy"
|
ATTR_TOTAL_ENERGY = "total_energy"
|
||||||
ATTR_MEAN_POWER_CYCLE = "mean_cycle_power"
|
ATTR_MEAN_POWER_CYCLE = "mean_cycle_power"
|
||||||
|
|
||||||
|
# A special regulation parameter suggested by @Maia here: https://github.com/jmcollin78/versatile_thermostat/discussions/154
|
||||||
|
class RegulationParamSlow:
|
||||||
|
""" Light parameters for slow latency regulation"""
|
||||||
|
kp:float = 0.2 # 20% of the current internal regulation offset are caused by the current difference of target temperature and room temperature
|
||||||
|
ki:float = 0.8 / 288.0 # 80% of the current internal regulation offset are caused by the average offset of the past 24 hours
|
||||||
|
k_ext:float = 1.0 / 25.0 # this will add 1°C to the offset when it's 25°C colder outdoor than indoor
|
||||||
|
offset_max:float = 2.0 # limit to a final offset of -2°C to +2°C
|
||||||
|
stabilization_threshold:float = 0.0 # this needs to be disabled as otherwise the long term accumulated error will always be reset when the temp briefly crosses from/to below/above the target
|
||||||
|
accumulated_error_threshold:float = 2.0 * 288 # this allows up to 2°C long term offset in both directions
|
||||||
|
|
||||||
class RegulationParamLight:
|
class RegulationParamLight:
|
||||||
""" Light parameters for regulation"""
|
""" Light parameters for regulation"""
|
||||||
kp:float = 0.2
|
kp:float = 0.2
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ class PITemperatureRegulator:
|
|||||||
offset = self.kp * error + self.ki * self.accumulated_error
|
offset = self.kp * error + self.ki * self.accumulated_error
|
||||||
|
|
||||||
# Calculate the exterior offset
|
# Calculate the exterior offset
|
||||||
offset_ext = self.k_ext * (self.target_temp - external_temp)
|
# For Maia tests - use the internal_temp vs external_temp and not target_temp - external_temp
|
||||||
|
offset_ext = self.k_ext * (internal_temp - external_temp)
|
||||||
|
|
||||||
# Capping of offset_ext
|
# Capping of offset_ext
|
||||||
total_offset = offset + offset_ext
|
total_offset = offset + offset_ext
|
||||||
|
|||||||
@@ -159,3 +159,4 @@ set_auto_regulation_mode:
|
|||||||
- "Light"
|
- "Light"
|
||||||
- "Medium"
|
- "Medium"
|
||||||
- "Strong"
|
- "Strong"
|
||||||
|
- "Slow"
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ from .const import (
|
|||||||
CONF_CLIMATE_4,
|
CONF_CLIMATE_4,
|
||||||
CONF_AUTO_REGULATION_MODE,
|
CONF_AUTO_REGULATION_MODE,
|
||||||
CONF_AUTO_REGULATION_NONE,
|
CONF_AUTO_REGULATION_NONE,
|
||||||
|
CONF_AUTO_REGULATION_SLOW,
|
||||||
CONF_AUTO_REGULATION_LIGHT,
|
CONF_AUTO_REGULATION_LIGHT,
|
||||||
CONF_AUTO_REGULATION_MEDIUM,
|
CONF_AUTO_REGULATION_MEDIUM,
|
||||||
CONF_AUTO_REGULATION_STRONG,
|
CONF_AUTO_REGULATION_STRONG,
|
||||||
CONF_AUTO_REGULATION_DTEMP,
|
CONF_AUTO_REGULATION_DTEMP,
|
||||||
CONF_AUTO_REGULATION_PERIOD_MIN,
|
CONF_AUTO_REGULATION_PERIOD_MIN,
|
||||||
|
RegulationParamSlow,
|
||||||
RegulationParamLight,
|
RegulationParamLight,
|
||||||
RegulationParamMedium,
|
RegulationParamMedium,
|
||||||
RegulationParamStrong
|
RegulationParamStrong
|
||||||
@@ -176,6 +178,15 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
RegulationParamStrong.offset_max,
|
RegulationParamStrong.offset_max,
|
||||||
RegulationParamStrong.stabilization_threshold,
|
RegulationParamStrong.stabilization_threshold,
|
||||||
RegulationParamStrong.accumulated_error_threshold)
|
RegulationParamStrong.accumulated_error_threshold)
|
||||||
|
elif self._auto_regulation_mode == CONF_AUTO_REGULATION_SLOW:
|
||||||
|
self._regulation_algo = PITemperatureRegulator(
|
||||||
|
self.target_temperature,
|
||||||
|
RegulationParamSlow.kp,
|
||||||
|
RegulationParamSlow.ki,
|
||||||
|
RegulationParamSlow.k_ext,
|
||||||
|
RegulationParamSlow.offset_max,
|
||||||
|
RegulationParamSlow.stabilization_threshold,
|
||||||
|
RegulationParamSlow.accumulated_error_threshold)
|
||||||
else:
|
else:
|
||||||
# A default empty algo (which does nothing)
|
# A default empty algo (which does nothing)
|
||||||
self._regulation_algo = PITemperatureRegulator(
|
self._regulation_algo = PITemperatureRegulator(
|
||||||
@@ -666,6 +677,8 @@ class ThermostatOverClimate(BaseThermostat):
|
|||||||
self.choose_auto_regulation_mode(CONF_AUTO_REGULATION_MEDIUM)
|
self.choose_auto_regulation_mode(CONF_AUTO_REGULATION_MEDIUM)
|
||||||
elif auto_regulation_mode == "Strong":
|
elif auto_regulation_mode == "Strong":
|
||||||
self.choose_auto_regulation_mode(CONF_AUTO_REGULATION_STRONG)
|
self.choose_auto_regulation_mode(CONF_AUTO_REGULATION_STRONG)
|
||||||
|
elif auto_regulation_mode == "Slow":
|
||||||
|
self.choose_auto_regulation_mode(CONF_AUTO_REGULATION_SLOW)
|
||||||
|
|
||||||
await self._send_regulated_temperature()
|
await self._send_regulated_temperature()
|
||||||
self.update_custom_attributes()
|
self.update_custom_attributes()
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ async def test_over_climate_regulation(hass: HomeAssistant, skip_hass_states_is_
|
|||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.commons.NowClass.get_now", return_value=event_timestamp
|
"custom_components.versatile_thermostat.commons.NowClass.get_now", return_value=event_timestamp
|
||||||
):
|
):
|
||||||
await send_temperature_change_event(entity, 22, event_timestamp)
|
await send_temperature_change_event(entity, 23, event_timestamp)
|
||||||
await send_ext_temperature_change_event(entity, 19, event_timestamp)
|
await send_ext_temperature_change_event(entity, 19, event_timestamp)
|
||||||
|
|
||||||
# the regulated temperature should be under
|
# the regulated temperature should be under
|
||||||
@@ -212,14 +212,14 @@ async def test_over_climate_regulation_ac_mode(hass: HomeAssistant, skip_hass_st
|
|||||||
|
|
||||||
# the regulated temperature should be under
|
# the regulated temperature should be under
|
||||||
assert entity.regulated_target_temp < entity.target_temperature
|
assert entity.regulated_target_temp < entity.target_temperature
|
||||||
assert entity.regulated_target_temp == 25-2.5 # +2.3 without round_to_nearest
|
assert entity.regulated_target_temp == 25-2 # +2.3 without round_to_nearest
|
||||||
|
|
||||||
# change temperature so that the regulated temperature should slow down
|
# change temperature so that the regulated temperature should slow down
|
||||||
event_timestamp = now - timedelta(minutes=3)
|
event_timestamp = now - timedelta(minutes=3)
|
||||||
with patch(
|
with patch(
|
||||||
"custom_components.versatile_thermostat.commons.NowClass.get_now", return_value=event_timestamp
|
"custom_components.versatile_thermostat.commons.NowClass.get_now", return_value=event_timestamp
|
||||||
):
|
):
|
||||||
await send_temperature_change_event(entity, 20, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
await send_ext_temperature_change_event(entity, 25, event_timestamp)
|
await send_ext_temperature_change_event(entity, 25, event_timestamp)
|
||||||
|
|
||||||
# the regulated temperature should be greater
|
# the regulated temperature should be greater
|
||||||
@@ -331,4 +331,4 @@ async def test_over_climate_regulation_limitations(hass: HomeAssistant, skip_has
|
|||||||
# the regulated should have been done
|
# the regulated should have been done
|
||||||
assert entity.regulated_target_temp != old_regulated_temp
|
assert entity.regulated_target_temp != old_regulated_temp
|
||||||
assert entity.regulated_target_temp > entity.target_temperature
|
assert entity.regulated_target_temp > entity.target_temperature
|
||||||
assert entity.regulated_target_temp == 17 + 1 # 0.7 without round_to_nearest
|
assert entity.regulated_target_temp == 17 + 1.5 # 0.7 without round_to_nearest
|
||||||
@@ -241,7 +241,7 @@ async def test_window_binary_sensors(
|
|||||||
await entity.async_set_preset_mode(PRESET_COMFORT)
|
await entity.async_set_preset_mode(PRESET_COMFORT)
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await send_temperature_change_event(entity, 15, now)
|
await send_temperature_change_event(entity, 15, now)
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
await window_binary_sensor.async_my_climate_changed()
|
await window_binary_sensor.async_my_climate_changed()
|
||||||
assert window_binary_sensor.state is STATE_OFF
|
assert window_binary_sensor.state is STATE_OFF
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ async def test_bug_66(
|
|||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Open the window and let the thermostat shut down
|
# Open the window and let the thermostat shut down
|
||||||
with patch(
|
with patch(
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ async def test_one_switch_cycle(
|
|||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
@@ -282,7 +282,7 @@ async def test_multiple_switchs(
|
|||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
@@ -418,7 +418,7 @@ async def test_multiple_climates(
|
|||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
@@ -443,7 +443,7 @@ async def test_multiple_climates(
|
|||||||
assert entity.hvac_mode is HVACMode.OFF
|
assert entity.hvac_mode is HVACMode.OFF
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
@@ -518,7 +518,7 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
assert entity.hvac_mode is HVACMode.HEAT
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
assert entity.preset_mode is PRESET_BOOST
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 15, event_timestamp)
|
await send_temperature_change_event(entity, 15, event_timestamp)
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ def test_pi_algorithm_basics():
|
|||||||
|
|
||||||
# to reset the accumulated error
|
# to reset the accumulated error
|
||||||
the_algo.reset_accumulated_error()
|
the_algo.reset_accumulated_error()
|
||||||
assert the_algo.calculate_regulated_temperature(18, 10) == 21.5 # +1.5
|
assert the_algo.calculate_regulated_temperature(18, 10) == 21.3 # +1.5
|
||||||
assert the_algo.calculate_regulated_temperature(18.1, 10) == 21.6 # +1.6
|
assert the_algo.calculate_regulated_temperature(18.1, 10) == 21.4 # +1.6
|
||||||
assert the_algo.calculate_regulated_temperature(18.3, 10) == 21.6 # +1.6
|
assert the_algo.calculate_regulated_temperature(18.3, 10) == 21.4 # +1.6
|
||||||
assert the_algo.calculate_regulated_temperature(18.5, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(18.5, 10) == 21.5 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(18.7, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(18.7, 10) == 21.6 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(19, 10) == 21.6 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 21.5 # +1.5
|
assert the_algo.calculate_regulated_temperature(20, 10) == 21.5 # +1.5
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8 # +0.8
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.9 # +0.8
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.7 # +0.7
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8 # +0.7
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 20.9 # +0.7
|
assert the_algo.calculate_regulated_temperature(20, 10) == 20.9 # +0.7
|
||||||
|
|
||||||
# Test temperature external
|
# Test temperature external
|
||||||
@@ -54,15 +54,15 @@ def test_pi_algorithm_light():
|
|||||||
# to reset the accumulated erro
|
# to reset the accumulated erro
|
||||||
the_algo.set_target_temp(20)
|
the_algo.set_target_temp(20)
|
||||||
|
|
||||||
assert the_algo.calculate_regulated_temperature(18, 10) == 21.5 # +1.5
|
assert the_algo.calculate_regulated_temperature(18, 10) == 21.3 # +1.5
|
||||||
assert the_algo.calculate_regulated_temperature(18.1, 10) == 21.6 # +1.6
|
assert the_algo.calculate_regulated_temperature(18.1, 10) == 21.4 # +1.6
|
||||||
assert the_algo.calculate_regulated_temperature(18.3, 10) == 21.6 # +1.6
|
assert the_algo.calculate_regulated_temperature(18.3, 10) == 21.4 # +1.6
|
||||||
assert the_algo.calculate_regulated_temperature(18.5, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(18.5, 10) == 21.5 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(18.7, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(18.7, 10) == 21.6 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 21.7 # +1.7
|
assert the_algo.calculate_regulated_temperature(19, 10) == 21.6 # +1.7
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 21.5 # +1.5
|
assert the_algo.calculate_regulated_temperature(20, 10) == 21.5 # +1.5
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8 # +0.8
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.9 # +0.8
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.7 # +0.7
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8 # +0.7
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 20.9 # +0.7
|
assert the_algo.calculate_regulated_temperature(20, 10) == 20.9 # +0.7
|
||||||
|
|
||||||
# Test temperature external
|
# Test temperature external
|
||||||
@@ -81,15 +81,15 @@ def test_pi_algorithm_medium():
|
|||||||
# to reset the accumulated erro
|
# to reset the accumulated erro
|
||||||
the_algo.set_target_temp(20)
|
the_algo.set_target_temp(20)
|
||||||
|
|
||||||
assert the_algo.calculate_regulated_temperature(18, 10) == 22.2
|
assert the_algo.calculate_regulated_temperature(18, 10) == 22.0
|
||||||
assert the_algo.calculate_regulated_temperature(18.1, 10) == 22.3
|
assert the_algo.calculate_regulated_temperature(18.1, 10) == 22.1
|
||||||
assert the_algo.calculate_regulated_temperature(18.3, 10) == 22.4
|
assert the_algo.calculate_regulated_temperature(18.3, 10) == 22.2
|
||||||
assert the_algo.calculate_regulated_temperature(18.5, 10) == 22.5
|
assert the_algo.calculate_regulated_temperature(18.5, 10) == 22.3
|
||||||
assert the_algo.calculate_regulated_temperature(18.7, 10) == 22.5
|
assert the_algo.calculate_regulated_temperature(18.7, 10) == 22.4
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 22.4
|
assert the_algo.calculate_regulated_temperature(19, 10) == 22.3
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 21.9
|
assert the_algo.calculate_regulated_temperature(20, 10) == 21.9
|
||||||
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.5
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.4
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.4
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.3
|
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 20.8
|
assert the_algo.calculate_regulated_temperature(20, 10) == 20.8
|
||||||
|
|
||||||
# Test temperature external
|
# Test temperature external
|
||||||
@@ -107,6 +107,7 @@ def test_pi_algorithm_medium():
|
|||||||
the_algo.set_target_temp(20)
|
the_algo.set_target_temp(20)
|
||||||
the_algo.reset_accumulated_error()
|
the_algo.reset_accumulated_error()
|
||||||
# Test the error acculation effect
|
# Test the error acculation effect
|
||||||
|
assert the_algo.calculate_regulated_temperature(19, 5) == 22.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 22.1
|
assert the_algo.calculate_regulated_temperature(19, 5) == 22.1
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 22.2
|
assert the_algo.calculate_regulated_temperature(19, 5) == 22.2
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 22.3
|
assert the_algo.calculate_regulated_temperature(19, 5) == 22.3
|
||||||
@@ -119,7 +120,6 @@ def test_pi_algorithm_medium():
|
|||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
||||||
assert the_algo.calculate_regulated_temperature(19, 5) == 23
|
|
||||||
|
|
||||||
def test_pi_algorithm_strong():
|
def test_pi_algorithm_strong():
|
||||||
""" Test the PI algorithm """
|
""" Test the PI algorithm """
|
||||||
@@ -131,20 +131,20 @@ def test_pi_algorithm_strong():
|
|||||||
# to reset the accumulated erro
|
# to reset the accumulated erro
|
||||||
the_algo.set_target_temp(20)
|
the_algo.set_target_temp(20)
|
||||||
|
|
||||||
assert the_algo.calculate_regulated_temperature(18, 10) == 23.6
|
assert the_algo.calculate_regulated_temperature(18, 10) == 23.2
|
||||||
assert the_algo.calculate_regulated_temperature(18.1, 10) == 23.9
|
assert the_algo.calculate_regulated_temperature(18.1, 10) == 23.5
|
||||||
assert the_algo.calculate_regulated_temperature(18.3, 10) == 24.0
|
assert the_algo.calculate_regulated_temperature(18.3, 10) == 23.8
|
||||||
assert the_algo.calculate_regulated_temperature(18.5, 10) == 24
|
assert the_algo.calculate_regulated_temperature(18.5, 10) == 24
|
||||||
assert the_algo.calculate_regulated_temperature(18.7, 10) == 24
|
assert the_algo.calculate_regulated_temperature(18.7, 10) == 24
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
||||||
assert the_algo.calculate_regulated_temperature(20, 10) == 23.9
|
assert the_algo.calculate_regulated_temperature(20, 10) == 23.9
|
||||||
|
assert the_algo.calculate_regulated_temperature(21, 10) == 21.4
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 21.2
|
assert the_algo.calculate_regulated_temperature(21, 10) == 21.2
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 21
|
assert the_algo.calculate_regulated_temperature(21, 10) == 21
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.8
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.6
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.6
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.4
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.4
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20.2
|
assert the_algo.calculate_regulated_temperature(21, 10) == 20.2
|
||||||
assert the_algo.calculate_regulated_temperature(21, 10) == 20
|
|
||||||
|
|
||||||
# Test temperature external
|
# Test temperature external
|
||||||
assert the_algo.calculate_regulated_temperature(20, 8) == 21.0
|
assert the_algo.calculate_regulated_temperature(20, 8) == 21.0
|
||||||
@@ -161,14 +161,14 @@ def test_pi_algorithm_strong():
|
|||||||
the_algo.set_target_temp(20)
|
the_algo.set_target_temp(20)
|
||||||
the_algo.reset_accumulated_error()
|
the_algo.reset_accumulated_error()
|
||||||
# Test the error acculation effect
|
# Test the error acculation effect
|
||||||
|
assert the_algo.calculate_regulated_temperature(19, 10) == 22.6
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 22.8
|
assert the_algo.calculate_regulated_temperature(19, 10) == 22.8
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 23
|
assert the_algo.calculate_regulated_temperature(19, 10) == 23.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 23.2
|
assert the_algo.calculate_regulated_temperature(19, 10) == 23.2
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 23.4
|
assert the_algo.calculate_regulated_temperature(19, 10) == 23.4
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 23.6
|
assert the_algo.calculate_regulated_temperature(19, 10) == 23.6
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 23.8
|
assert the_algo.calculate_regulated_temperature(19, 10) == 23.8
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
assert the_algo.calculate_regulated_temperature(19, 10) == 24.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
assert the_algo.calculate_regulated_temperature(19, 10) == 24.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
assert the_algo.calculate_regulated_temperature(19, 10) == 24.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
assert the_algo.calculate_regulated_temperature(19, 10) == 24.0
|
||||||
assert the_algo.calculate_regulated_temperature(19, 10) == 24
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async def test_window_management_time_not_enough(
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Open the window, but condition of time is not satisfied and check the thermostat don't turns off
|
# Open the window, but condition of time is not satisfied and check the thermostat don't turns off
|
||||||
with patch(
|
with patch(
|
||||||
@@ -152,7 +152,7 @@ async def test_window_management_time_enough(
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# change temperature to force turning on the heater
|
# change temperature to force turning on the heater
|
||||||
with patch(
|
with patch(
|
||||||
@@ -294,7 +294,7 @@ async def test_window_auto_fast(hass: HomeAssistant, skip_hass_states_is_state):
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 21
|
assert entity.target_temperature == 21
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Make the temperature down
|
# Make the temperature down
|
||||||
with patch(
|
with patch(
|
||||||
@@ -478,7 +478,7 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 21
|
assert entity.target_temperature == 21
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Make the temperature down
|
# Make the temperature down
|
||||||
with patch(
|
with patch(
|
||||||
@@ -623,7 +623,7 @@ async def test_window_auto_no_on_percent(
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 21
|
assert entity.target_temperature == 21
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Make the temperature down
|
# Make the temperature down
|
||||||
with patch(
|
with patch(
|
||||||
@@ -728,7 +728,7 @@ async def test_window_bypass(
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# change temperature to force turning on the heater
|
# change temperature to force turning on the heater
|
||||||
with patch(
|
with patch(
|
||||||
@@ -866,7 +866,7 @@ async def test_window_auto_bypass(hass: HomeAssistant, skip_hass_states_is_state
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 21
|
assert entity.target_temperature == 21
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# Make the temperature down
|
# Make the temperature down
|
||||||
with patch(
|
with patch(
|
||||||
@@ -973,7 +973,7 @@ async def test_window_bypass_reactivate(hass: HomeAssistant, skip_hass_states_is
|
|||||||
assert entity.overpowering_state is None
|
assert entity.overpowering_state is None
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
|
|
||||||
assert entity.window_state is None
|
assert entity.window_state is STATE_OFF
|
||||||
|
|
||||||
# change temperature to force turning on the heater
|
# change temperature to force turning on the heater
|
||||||
with patch(
|
with patch(
|
||||||
|
|||||||
Reference in New Issue
Block a user