Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 382f6f99c6 | |||
| 95c4aa8ae9 | |||
| a6a47fde53 | |||
| e08f51b4f2 |
@@ -21,7 +21,9 @@
|
|||||||
"ms-python.python",
|
"ms-python.python",
|
||||||
"github.vscode-pull-request-github",
|
"github.vscode-pull-request-github",
|
||||||
"ryanluker.vscode-coverage-gutters",
|
"ryanluker.vscode-coverage-gutters",
|
||||||
"ms-python.vscode-pylance"
|
"ms-python.black-formatter",
|
||||||
|
"ms-python.pylint",
|
||||||
|
"ferrierbenjamin.fold-unfold-all-icone"
|
||||||
],
|
],
|
||||||
// "mounts": [
|
// "mounts": [
|
||||||
// "source=${localWorkspaceFolder}/.devcontainer/configuration.yaml,target=${localWorkspaceFolder}/config/www/community/,type=bind,consistency=cached",
|
// "source=${localWorkspaceFolder}/.devcontainer/configuration.yaml,target=${localWorkspaceFolder}/config/www/community/,type=bind,consistency=cached",
|
||||||
@@ -40,8 +42,7 @@
|
|||||||
// "terminal.integrated.shell.linux": "/bin/bash",
|
// "terminal.integrated.shell.linux": "/bin/bash",
|
||||||
"python.pythonPath": "/usr/bin/python3",
|
"python.pythonPath": "/usr/bin/python3",
|
||||||
"python.analysis.autoSearchPaths": true,
|
"python.analysis.autoSearchPaths": true,
|
||||||
"python.linting.pylintEnabled": true,
|
"pylint.lintOnChange": false,
|
||||||
"python.linting.enabled": true,
|
|
||||||
"python.formatting.provider": "black",
|
"python.formatting.provider": "black",
|
||||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||||
"editor.formatOnPaste": false,
|
"editor.formatOnPaste": false,
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.defaultFormatter": "ms-python.python"
|
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||||
|
"editor.formatOnSave": true
|
||||||
},
|
},
|
||||||
"python.linting.pylintEnabled": true,
|
"pylint.lintOnChange": false,
|
||||||
"python.linting.enabled": true,
|
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"*.yaml": "home-assistant"
|
"*.yaml": "home-assistant"
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-2
@@ -51,7 +51,7 @@
|
|||||||
- [Attributs personnalisés](#attributs-personnalisés)
|
- [Attributs personnalisés](#attributs-personnalisés)
|
||||||
- [Quelques résultats](#quelques-résultats)
|
- [Quelques résultats](#quelques-résultats)
|
||||||
- [Encore mieux](#encore-mieux)
|
- [Encore mieux](#encore-mieux)
|
||||||
- [Bien mieux avec le Veersatile Thermostat UI Card](#bien-mieux-avec-le-veersatile-thermostat-ui-card)
|
- [Bien mieux avec le Versatile Thermostat UI Card](#bien-mieux-avec-le-versatile-thermostat-ui-card)
|
||||||
- [Encore mieux avec le composant Scheduler !](#encore-mieux-avec-le-composant-scheduler-)
|
- [Encore mieux avec le composant Scheduler !](#encore-mieux-avec-le-composant-scheduler-)
|
||||||
- [Encore bien mieux avec la custom:simple-thermostat front integration](#encore-bien-mieux-avec-la-customsimple-thermostat-front-integration)
|
- [Encore bien mieux avec la custom:simple-thermostat front integration](#encore-bien-mieux-avec-la-customsimple-thermostat-front-integration)
|
||||||
- [Toujours mieux avec Apex-chart pour régler votre thermostat](#toujours-mieux-avec-apex-chart-pour-régler-votre-thermostat)
|
- [Toujours mieux avec Apex-chart pour régler votre thermostat](#toujours-mieux-avec-apex-chart-pour-régler-votre-thermostat)
|
||||||
@@ -735,7 +735,7 @@ Enjoy !
|
|||||||
|
|
||||||
# Encore mieux
|
# Encore mieux
|
||||||
|
|
||||||
## Bien mieux avec le Veersatile Thermostat UI Card
|
## Bien mieux avec le Versatile Thermostat UI Card
|
||||||
Une carte spéciale pour le Versatile Thermostat a été développée (sur la base du Better Thermostat). Elle est dispo ici [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card) et propose une vision moderne de tous les status du VTherm :
|
Une carte spéciale pour le Versatile Thermostat a été développée (sur la base du Better Thermostat). Elle est dispo ici [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card) et propose une vision moderne de tous les status du VTherm :
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -130,47 +130,50 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
_motion_state: bool
|
_motion_state: bool
|
||||||
_presence_state: bool
|
_presence_state: bool
|
||||||
_window_auto_state: bool
|
_window_auto_state: bool
|
||||||
#PR - Adding Window ByPass
|
|
||||||
_window_bypass_state: bool
|
_window_bypass_state: bool
|
||||||
_underlyings: list[UnderlyingEntity]
|
_underlyings: list[UnderlyingEntity]
|
||||||
_last_change_time: datetime
|
_last_change_time: datetime
|
||||||
|
|
||||||
_entity_component_unrecorded_attributes = ClimateEntity._entity_component_unrecorded_attributes.union(frozenset(
|
_entity_component_unrecorded_attributes = (
|
||||||
{
|
ClimateEntity._entity_component_unrecorded_attributes.union(
|
||||||
"type",
|
frozenset(
|
||||||
"eco_temp",
|
{
|
||||||
"boost_temp",
|
"type",
|
||||||
"comfort_temp",
|
"eco_temp",
|
||||||
"eco_away_temp",
|
"boost_temp",
|
||||||
"boost_away_temp",
|
"comfort_temp",
|
||||||
"comfort_away_temp",
|
"eco_away_temp",
|
||||||
"power_temp",
|
"boost_away_temp",
|
||||||
"ac_mode",
|
"comfort_away_temp",
|
||||||
"current_power_max",
|
"power_temp",
|
||||||
"saved_preset_mode",
|
"ac_mode",
|
||||||
"saved_target_temp",
|
"current_power_max",
|
||||||
"saved_hvac_mode",
|
"saved_preset_mode",
|
||||||
"security_delay_min",
|
"saved_target_temp",
|
||||||
"security_min_on_percent",
|
"saved_hvac_mode",
|
||||||
"security_default_on_percent",
|
"security_delay_min",
|
||||||
"last_temperature_datetime",
|
"security_min_on_percent",
|
||||||
"last_ext_temperature_datetime",
|
"security_default_on_percent",
|
||||||
"minimal_activation_delay_sec",
|
"last_temperature_datetime",
|
||||||
"device_power",
|
"last_ext_temperature_datetime",
|
||||||
"mean_cycle_power",
|
"minimal_activation_delay_sec",
|
||||||
"last_update_datetime",
|
"device_power",
|
||||||
"timezone",
|
"mean_cycle_power",
|
||||||
"window_sensor_entity_id",
|
"last_update_datetime",
|
||||||
"window_delay_sec",
|
"timezone",
|
||||||
"window_auto_open_threshold",
|
"window_sensor_entity_id",
|
||||||
"window_auto_close_threshold",
|
"window_delay_sec",
|
||||||
"window_auto_max_duration",
|
"window_auto_open_threshold",
|
||||||
"motion_sensor_entity_id",
|
"window_auto_close_threshold",
|
||||||
"presence_sensor_entity_id",
|
"window_auto_max_duration",
|
||||||
"power_sensor_entity_id",
|
"motion_sensor_entity_id",
|
||||||
"max_power_sensor_entity_id",
|
"presence_sensor_entity_id",
|
||||||
}
|
"power_sensor_entity_id",
|
||||||
))
|
"max_power_sensor_entity_id",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None:
|
||||||
"""Initialize the thermostat."""
|
"""Initialize the thermostat."""
|
||||||
@@ -621,7 +624,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
STATE_UNKNOWN,
|
STATE_UNKNOWN,
|
||||||
):
|
):
|
||||||
self._window_state = (window_state.state == STATE_ON)
|
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,
|
||||||
@@ -762,17 +765,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_climate(self) -> bool:
|
def is_over_climate(self) -> bool:
|
||||||
""" True if the Thermostat is over_climate"""
|
"""True if the Thermostat is over_climate"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_switch(self) -> bool:
|
def is_over_switch(self) -> bool:
|
||||||
""" True if the Thermostat is over_switch"""
|
"""True if the Thermostat is over_switch"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_over_valve(self) -> bool:
|
def is_over_valve(self) -> bool:
|
||||||
""" True if the Thermostat is over_valve"""
|
"""True if the Thermostat is over_valve"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -933,10 +936,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if not self._device_power:
|
if not self._device_power:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return float(
|
return float(self._device_power * self._prop_algorithm.on_percent)
|
||||||
self._device_power
|
|
||||||
* self._prop_algorithm.on_percent
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_energy(self) -> float | None:
|
def total_energy(self) -> float | None:
|
||||||
@@ -963,7 +963,6 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"""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
|
||||||
|
|
||||||
#PR - Adding Window ByPass
|
|
||||||
@property
|
@property
|
||||||
def window_bypass_state(self) -> bool | None:
|
def window_bypass_state(self) -> bool | None:
|
||||||
"""Get the Window Bypass"""
|
"""Get the Window Bypass"""
|
||||||
@@ -1219,7 +1218,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
|
|
||||||
async def _async_internal_set_temperature(self, temperature):
|
async def _async_internal_set_temperature(self, temperature):
|
||||||
"""Set the target temperature and the target temperature of underlying climate if any
|
"""Set the target temperature and the target temperature of underlying climate if any
|
||||||
For testing purpose you can pass an event_timestamp.
|
For testing purpose you can pass an event_timestamp.
|
||||||
"""
|
"""
|
||||||
self._target_temp = temperature
|
self._target_temp = temperature
|
||||||
return
|
return
|
||||||
@@ -1307,7 +1306,7 @@ 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 == STATE_ON)
|
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)
|
||||||
@@ -1318,13 +1317,14 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
_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 == STATE_ON
|
||||||
|
|
||||||
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 not self._window_state:
|
if not self._window_state:
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
@@ -1827,7 +1827,15 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
self._device_power,
|
self._device_power,
|
||||||
)
|
)
|
||||||
|
|
||||||
ret = (self._current_power + self._device_power) >= self._current_power_max
|
if self.is_over_climate:
|
||||||
|
power_consumption_max = self._device_power
|
||||||
|
else:
|
||||||
|
power_consumption_max = max(
|
||||||
|
self._device_power / self.nb_underlying_entities,
|
||||||
|
self._device_power * self._prop_algorithm.on_percent,
|
||||||
|
)
|
||||||
|
|
||||||
|
ret = (self._current_power + power_consumption_max) >= 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'",
|
||||||
@@ -1845,6 +1853,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"current_power": self._current_power,
|
"current_power": self._current_power,
|
||||||
"device_power": self._device_power,
|
"device_power": self._device_power,
|
||||||
"current_power_max": self._current_power_max,
|
"current_power_max": self._current_power_max,
|
||||||
|
"current_power_consumption": power_consumption_max,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2129,7 +2138,6 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
"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
|
|
||||||
"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,
|
||||||
"security_min_on_percent": self._security_min_on_percent,
|
"security_min_on_percent": self._security_min_on_percent,
|
||||||
@@ -2256,14 +2264,25 @@ class BaseThermostat(ClimateEntity, RestoreEntity):
|
|||||||
target:
|
target:
|
||||||
entity_id: climate.thermostat_1
|
entity_id: climate.thermostat_1
|
||||||
"""
|
"""
|
||||||
_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:
|
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:
|
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()
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,7 @@
|
|||||||
},
|
},
|
||||||
"auto_regulation_mode": {
|
"auto_regulation_mode": {
|
||||||
"options": {
|
"options": {
|
||||||
|
"auto_regulation_slow": "Slow",
|
||||||
"auto_regulation_strong": "Strong",
|
"auto_regulation_strong": "Strong",
|
||||||
"auto_regulation_medium": "Medium",
|
"auto_regulation_medium": "Medium",
|
||||||
"auto_regulation_light": "Light",
|
"auto_regulation_light": "Light",
|
||||||
|
|||||||
@@ -348,6 +348,7 @@
|
|||||||
},
|
},
|
||||||
"auto_regulation_mode": {
|
"auto_regulation_mode": {
|
||||||
"options": {
|
"options": {
|
||||||
|
"auto_regulation_slow": "Slow",
|
||||||
"auto_regulation_strong": "Strong",
|
"auto_regulation_strong": "Strong",
|
||||||
"auto_regulation_medium": "Medium",
|
"auto_regulation_medium": "Medium",
|
||||||
"auto_regulation_light": "Light",
|
"auto_regulation_light": "Light",
|
||||||
|
|||||||
@@ -349,6 +349,7 @@
|
|||||||
},
|
},
|
||||||
"auto_regulation_mode": {
|
"auto_regulation_mode": {
|
||||||
"options": {
|
"options": {
|
||||||
|
"auto_regulation_slow": "Lente",
|
||||||
"auto_regulation_strong": "Forte",
|
"auto_regulation_strong": "Forte",
|
||||||
"auto_regulation_medium": "Moyenne",
|
"auto_regulation_medium": "Moyenne",
|
||||||
"auto_regulation_light": "Légère",
|
"auto_regulation_light": "Légère",
|
||||||
|
|||||||
@@ -30,15 +30,15 @@
|
|||||||
"heater_entity3_id": "Terzo riscaldatore",
|
"heater_entity3_id": "Terzo riscaldatore",
|
||||||
"heater_entity4_id": "Quarto riscaldatore",
|
"heater_entity4_id": "Quarto riscaldatore",
|
||||||
"proportional_function": "Algoritmo",
|
"proportional_function": "Algoritmo",
|
||||||
"climate_entity_id": "Termostato sottostante",
|
"climate_entity_id": "Primo termostato",
|
||||||
"climate_entity2_id": "Secundo termostato sottostante",
|
"climate_entity2_id": "Secondo termostato",
|
||||||
"climate_entity3_id": "Terzo termostato sottostante",
|
"climate_entity3_id": "Terzo termostato",
|
||||||
"climate_entity4_id": "Quarto termostato sottostante",
|
"climate_entity4_id": "Quarto termostato",
|
||||||
"ac_mode": "AC mode ?",
|
"ac_mode": "AC mode ?",
|
||||||
"valve_entity_id": "Primo valvola numero",
|
"valve_entity_id": "Prima valvola",
|
||||||
"valve_entity2_id": "Secondo valvola numero",
|
"valve_entity2_id": "Seconda valvolao",
|
||||||
"valve_entity3_id": "Terzo valvola numero",
|
"valve_entity3_id": "Terza valvola",
|
||||||
"valve_entity4_id": "Quarto valvola numero",
|
"valve_entity4_id": "Quarta valvola",
|
||||||
"auto_regulation_mode": "Autoregolamentazione",
|
"auto_regulation_mode": "Autoregolamentazione",
|
||||||
"inverse_switch_command": "Comando inverso"
|
"inverse_switch_command": "Comando inverso"
|
||||||
},
|
},
|
||||||
@@ -48,15 +48,15 @@
|
|||||||
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||||
"climate_entity_id": "Entity id del termostato sottostante",
|
"climate_entity_id": "Entity id del primo termostato",
|
||||||
"climate_entity2_id": "Entity id del secundo termostato sottostante",
|
"climate_entity2_id": "Entity id del secondo termostato",
|
||||||
"climate_entity3_id": "Entity id del terzo termostato sottostante",
|
"climate_entity3_id": "Entity id del terzo termostato",
|
||||||
"climate_entity4_id": "Entity id del quarto termostato sottostante",
|
"climate_entity4_id": "Entity id del quarto termostato",
|
||||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?",
|
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?",
|
||||||
"valve_entity_id": "Entity id del primo valvola numero",
|
"valve_entity_id": "Entity id della prima valvola",
|
||||||
"valve_entity2_id": "Entity id del secondo valvola numero",
|
"valve_entity2_id": "Entity id della seconda valvola",
|
||||||
"valve_entity3_id": "Entity id del terzo valvola numero",
|
"valve_entity3_id": "Entity id della terza valvola",
|
||||||
"valve_entity4_id": "Entity id del quarto valvola numero",
|
"valve_entity4_id": "Entity id della quarta valvola",
|
||||||
"auto_regulation_mode": "Regolazione automatica della temperatura target",
|
"auto_regulation_mode": "Regolazione automatica della temperatura target",
|
||||||
"inverse_switch_command": "Inverte il controllo dell'interruttore per un'installazione con filo pilota e diodo"
|
"inverse_switch_command": "Inverte il controllo dell'interruttore per un'installazione con filo pilota e diodo"
|
||||||
}
|
}
|
||||||
@@ -188,15 +188,15 @@
|
|||||||
"heater_entity3_id": "Terzo riscaldatore",
|
"heater_entity3_id": "Terzo riscaldatore",
|
||||||
"heater_entity4_id": "Quarto riscaldatore",
|
"heater_entity4_id": "Quarto riscaldatore",
|
||||||
"proportional_function": "Algoritmo",
|
"proportional_function": "Algoritmo",
|
||||||
"climate_entity_id": "Termostato sottostante",
|
"climate_entity_id": "Primo termostato",
|
||||||
"climate_entity2_id": "Secundo termostato sottostante",
|
"climate_entity2_id": "Secondo termostato",
|
||||||
"climate_entity3_id": "Terzo termostato sottostante",
|
"climate_entity3_id": "Terzo termostato",
|
||||||
"climate_entity4_id": "Quarto termostato sottostante",
|
"climate_entity4_id": "Quarto termostato",
|
||||||
"ac_mode": "AC mode ?",
|
"ac_mode": "AC mode ?",
|
||||||
"valve_entity_id": "Primo valvola numero",
|
"valve_entity_id": "Prima valvola",
|
||||||
"valve_entity2_id": "Secondo valvola numero",
|
"valve_entity2_id": "Seconda valvola",
|
||||||
"valve_entity3_id": "Terzo valvola numero",
|
"valve_entity3_id": "Terza valvola",
|
||||||
"valve_entity4_id": "Quarto valvola numero",
|
"valve_entity4_id": "Quarta valvola",
|
||||||
"auto_regulation_mode": "Autoregolamentazione",
|
"auto_regulation_mode": "Autoregolamentazione",
|
||||||
"inverse_switch_command": "Comando inverso"
|
"inverse_switch_command": "Comando inverso"
|
||||||
},
|
},
|
||||||
@@ -206,15 +206,15 @@
|
|||||||
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||||
"climate_entity_id": "Entity id del termostato sottostante",
|
"climate_entity_id": "Entity id del primo termostato",
|
||||||
"climate_entity2_id": "Entity id del secundo termostato sottostante",
|
"climate_entity2_id": "Entity id del secondo termostato",
|
||||||
"climate_entity3_id": "Entity id del terzo termostato sottostante",
|
"climate_entity3_id": "Entity id del terzo termostato",
|
||||||
"climate_entity4_id": "Entity id del quarto termostato sottostante",
|
"climate_entity4_id": "Entity id del quarto termostato",
|
||||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?",
|
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?",
|
||||||
"valve_entity_id": "Entity id del primo valvola numero",
|
"valve_entity_id": "Entity id della prima valvola",
|
||||||
"valve_entity2_id": "Entity id del secondo valvola numero",
|
"valve_entity2_id": "Entity id della seconda valvola",
|
||||||
"valve_entity3_id": "Entity id del terzo valvola numero",
|
"valve_entity3_id": "Entity id della terza valvola",
|
||||||
"valve_entity4_id": "Entity id del quarto valvola numero",
|
"valve_entity4_id": "Entity id della quarta valvola",
|
||||||
"auto_regulation_mode": "Autoregolamentazione",
|
"auto_regulation_mode": "Autoregolamentazione",
|
||||||
"inverse_switch_command": "Inverte il controllo dell'interruttore per un'installazione con filo pilota e diodo"
|
"inverse_switch_command": "Inverte il controllo dell'interruttore per un'installazione con filo pilota e diodo"
|
||||||
}
|
}
|
||||||
@@ -252,9 +252,9 @@
|
|||||||
"data_description": {
|
"data_description": {
|
||||||
"window_sensor_entity_id": "Lasciare vuoto se non deve essere utilizzato alcun sensore finestra",
|
"window_sensor_entity_id": "Lasciare vuoto se non deve essere utilizzato alcun sensore finestra",
|
||||||
"window_delay": "Ritardo in secondi prima che il rilevamento del sensore sia preso in considerazione",
|
"window_delay": "Ritardo in secondi prima che il rilevamento del sensore sia preso in considerazione",
|
||||||
"window_auto_open_threshold": "Valore consigliato: tra 0.05 e 0.1. Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato",
|
"window_auto_open_threshold": "Valore consigliato: tra 0.05 e 0.1 - Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato",
|
||||||
"window_auto_close_threshold": "Valore consigliato: 0. Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato",
|
"window_auto_close_threshold": "Valore consigliato: 0 - Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato",
|
||||||
"window_auto_max_duration": "Valore consigliato: 60 (un'ora). Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato"
|
"window_auto_max_duration": "Valore consigliato: 60 minuti. Lasciare vuoto se il rilevamento automatico della finestra aperta non è utilizzato"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"motion": {
|
"motion": {
|
||||||
@@ -320,12 +320,13 @@
|
|||||||
"thermostat_type": {
|
"thermostat_type": {
|
||||||
"options": {
|
"options": {
|
||||||
"thermostat_over_switch": "Termostato su un interruttore",
|
"thermostat_over_switch": "Termostato su un interruttore",
|
||||||
"thermostat_over_climate": "Termostato sopra un altro termostato",
|
"thermostat_over_climate": "Termostato su un climatizzatore",
|
||||||
"thermostat_over_valve": "Thermostato su una valvola"
|
"thermostat_over_valve": "Termostato su una valvola"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auto_regulation_mode": {
|
"auto_regulation_mode": {
|
||||||
"options": {
|
"options": {
|
||||||
|
"auto_regulation_slow": "Lento",
|
||||||
"auto_regulation_strong": "Forte",
|
"auto_regulation_strong": "Forte",
|
||||||
"auto_regulation_medium": "Media",
|
"auto_regulation_medium": "Media",
|
||||||
"auto_regulation_light": "Leggera",
|
"auto_regulation_light": "Leggera",
|
||||||
|
|||||||
@@ -348,6 +348,7 @@
|
|||||||
},
|
},
|
||||||
"auto_regulation_mode": {
|
"auto_regulation_mode": {
|
||||||
"options": {
|
"options": {
|
||||||
|
"auto_regulation_slow": "Slow",
|
||||||
"auto_regulation_strong": "Strong",
|
"auto_regulation_strong": "Strong",
|
||||||
"auto_regulation_medium": "Medium",
|
"auto_regulation_medium": "Medium",
|
||||||
"auto_regulation_light": "Light",
|
"auto_regulation_light": "Light",
|
||||||
|
|||||||
@@ -163,7 +163,9 @@ async def test_one_switch_cycle(
|
|||||||
# assert entity.underlying_entity(0)._should_relaunch_control_heating is True
|
# assert entity.underlying_entity(0)._should_relaunch_control_heating is True
|
||||||
|
|
||||||
# Simulate the relaunch
|
# Simulate the relaunch
|
||||||
await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access
|
await entity.underlying_entity(
|
||||||
|
0
|
||||||
|
)._turn_on_later( # pylint: disable=protected-access
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
# wait restart
|
# wait restart
|
||||||
@@ -184,7 +186,9 @@ async def test_one_switch_cycle(
|
|||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
) as mock_device_active:
|
) as mock_device_active:
|
||||||
await entity.underlying_entity(0)._turn_off_later( # pylint: disable=protected-access
|
await entity.underlying_entity(
|
||||||
|
0
|
||||||
|
)._turn_off_later( # pylint: disable=protected-access
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -207,7 +211,9 @@ async def test_one_switch_cycle(
|
|||||||
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
"custom_components.versatile_thermostat.underlyings.UnderlyingSwitch.is_device_active",
|
||||||
return_value=True,
|
return_value=True,
|
||||||
) as mock_device_active:
|
) as mock_device_active:
|
||||||
await entity.underlying_entity(0)._turn_on_later( # pylint: disable=protected-access
|
await entity.underlying_entity(
|
||||||
|
0
|
||||||
|
)._turn_on_later( # pylint: disable=protected-access
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -591,3 +597,139 @@ async def test_multiple_climates_underlying_changes(
|
|||||||
assert entity.hvac_mode == HVACMode.HEAT
|
assert entity.hvac_mode == HVACMode.HEAT
|
||||||
assert entity.hvac_action == HVACAction.IDLE
|
assert entity.hvac_action == HVACAction.IDLE
|
||||||
assert entity.is_device_active is False # pylint: disable=protected-access
|
assert entity.is_device_active is False # pylint: disable=protected-access
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
@pytest.mark.parametrize("expected_lingering_timers", [True])
|
||||||
|
async def test_multiple_switch_power_management(
|
||||||
|
hass: HomeAssistant, skip_hass_states_is_state
|
||||||
|
):
|
||||||
|
"""Test the Power management"""
|
||||||
|
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
title="TheOverSwitchMockName",
|
||||||
|
unique_id="uniqueId",
|
||||||
|
data={
|
||||||
|
CONF_NAME: "TheOver4SwitchMockName",
|
||||||
|
CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH,
|
||||||
|
CONF_TEMP_SENSOR: "sensor.mock_temp_sensor",
|
||||||
|
CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor",
|
||||||
|
CONF_CYCLE_MIN: 8,
|
||||||
|
CONF_TEMP_MIN: 15,
|
||||||
|
CONF_TEMP_MAX: 30,
|
||||||
|
"eco_temp": 17,
|
||||||
|
"comfort_temp": 18,
|
||||||
|
"boost_temp": 19,
|
||||||
|
CONF_USE_WINDOW_FEATURE: False,
|
||||||
|
CONF_USE_MOTION_FEATURE: False,
|
||||||
|
CONF_USE_POWER_FEATURE: True,
|
||||||
|
CONF_USE_PRESENCE_FEATURE: False,
|
||||||
|
CONF_HEATER: "switch.mock_switch1",
|
||||||
|
CONF_HEATER_2: "switch.mock_switch2",
|
||||||
|
CONF_HEATER_3: "switch.mock_switch3",
|
||||||
|
CONF_HEATER_4: "switch.mock_switch4",
|
||||||
|
CONF_MINIMAL_ACTIVATION_DELAY: 30,
|
||||||
|
CONF_SECURITY_DELAY_MIN: 5,
|
||||||
|
CONF_SECURITY_MIN_ON_PERCENT: 0.3,
|
||||||
|
CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI,
|
||||||
|
CONF_TPI_COEF_INT: 0.3,
|
||||||
|
CONF_TPI_COEF_EXT: 0.01,
|
||||||
|
CONF_POWER_SENSOR: "sensor.mock_power_sensor",
|
||||||
|
CONF_MAX_POWER_SENSOR: "sensor.mock_power_max_sensor",
|
||||||
|
CONF_DEVICE_POWER: 100,
|
||||||
|
CONF_PRESET_POWER: 12,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
entity: BaseThermostat = await create_thermostat(
|
||||||
|
hass, entry, "climate.theover4switchmockname"
|
||||||
|
)
|
||||||
|
assert entity
|
||||||
|
assert entity.is_over_climate is False
|
||||||
|
assert entity.nb_underlying_entities == 4
|
||||||
|
|
||||||
|
tpi_algo = entity._prop_algorithm
|
||||||
|
assert tpi_algo
|
||||||
|
|
||||||
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
|
await entity.async_set_preset_mode(PRESET_BOOST)
|
||||||
|
assert entity.hvac_mode is HVACMode.HEAT
|
||||||
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
|
assert entity.overpowering_state is None
|
||||||
|
assert entity.target_temperature == 19
|
||||||
|
|
||||||
|
# 1. Send power mesurement
|
||||||
|
await send_power_change_event(entity, 50, datetime.now())
|
||||||
|
# Send power max mesurement
|
||||||
|
await send_max_power_change_event(entity, 300, datetime.now())
|
||||||
|
assert await entity.check_overpowering() is False
|
||||||
|
# All configuration is complete and power is < power_max
|
||||||
|
assert entity.preset_mode is PRESET_BOOST
|
||||||
|
assert entity.overpowering_state is False
|
||||||
|
|
||||||
|
# 2. Send power max mesurement too low and HVACMode is on
|
||||||
|
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:
|
||||||
|
# 100 of the device / 4 -> 25, current power 50 so max is 75
|
||||||
|
await send_max_power_change_event(entity, 74, datetime.now())
|
||||||
|
assert await entity.check_overpowering() is True
|
||||||
|
# All configuration is complete and power is > power_max we switch to POWER preset
|
||||||
|
assert entity.preset_mode is PRESET_POWER
|
||||||
|
assert entity.overpowering_state is True
|
||||||
|
assert entity.target_temperature == 12
|
||||||
|
|
||||||
|
assert mock_send_event.call_count == 2
|
||||||
|
mock_send_event.assert_has_calls(
|
||||||
|
[
|
||||||
|
call.send_event(EventType.PRESET_EVENT, {"preset": PRESET_POWER}),
|
||||||
|
call.send_event(
|
||||||
|
EventType.POWER_EVENT,
|
||||||
|
{
|
||||||
|
"type": "start",
|
||||||
|
"current_power": 50,
|
||||||
|
"device_power": 100,
|
||||||
|
"current_power_max": 74,
|
||||||
|
"current_power_consumption": 25.0,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
any_order=True,
|
||||||
|
)
|
||||||
|
assert mock_heater_on.call_count == 0
|
||||||
|
assert mock_heater_off.call_count == 4 # The fourth are shutdown
|
||||||
|
|
||||||
|
# 3. change PRESET
|
||||||
|
with patch(
|
||||||
|
"custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event"
|
||||||
|
) as mock_send_event:
|
||||||
|
await entity.async_set_preset_mode(PRESET_ECO)
|
||||||
|
assert entity.preset_mode is PRESET_ECO
|
||||||
|
# No change
|
||||||
|
assert entity.overpowering_state is True
|
||||||
|
|
||||||
|
# 4. Send hugh power max mesurement to release overpowering
|
||||||
|
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:
|
||||||
|
# 100 of the device / 4 -> 25, current power 50 so max is 75. With 150 no overheating
|
||||||
|
await send_max_power_change_event(entity, 150, datetime.now())
|
||||||
|
assert await entity.check_overpowering() is False
|
||||||
|
# All configuration is complete and power is > power_max we switch to POWER preset
|
||||||
|
assert entity.preset_mode is PRESET_ECO
|
||||||
|
assert entity.overpowering_state is False
|
||||||
|
assert entity.target_temperature == 17
|
||||||
|
|
||||||
|
assert (
|
||||||
|
mock_heater_on.call_count == 0
|
||||||
|
) # The fourth are not restarted because temperature is enought
|
||||||
|
assert mock_heater_off.call_count == 0
|
||||||
|
|||||||
+5
-1
@@ -4,8 +4,11 @@ from unittest.mock import patch, call
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from custom_components.versatile_thermostat.thermostat_switch import ThermostatOverSwitch
|
from custom_components.versatile_thermostat.thermostat_switch import (
|
||||||
|
ThermostatOverSwitch,
|
||||||
|
)
|
||||||
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import
|
||||||
|
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
@@ -185,6 +188,7 @@ async def test_power_management_hvac_on(hass: HomeAssistant, skip_hass_states_is
|
|||||||
"current_power": 50,
|
"current_power": 50,
|
||||||
"device_power": 100,
|
"device_power": 100,
|
||||||
"current_power_max": 149,
|
"current_power_max": 149,
|
||||||
|
"current_power_consumption": 100.0,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user