From 7476e7fa64f8cf70610c7c7018e8977d66a4a8d3 Mon Sep 17 00:00:00 2001 From: Jean-Marc Collin Date: Wed, 3 Jan 2024 17:52:34 +0100 Subject: [PATCH] Feature 158 central mode (#309) * Normal algo working and testu ok * Fix interaction with window * FIX complex scenario * pylint warning * Release * Issue #306 * Issue #306 --------- Co-authored-by: Jean-Marc Collin --- .devcontainer/configuration.yaml | 3 + README-fr.md | 39 +- README.md | 43 +- .../versatile_thermostat/base_thermostat.py | 145 ++- .../versatile_thermostat/config_schema.py | 1 + .../versatile_thermostat/const.py | 23 +- .../versatile_thermostat/manifest.json | 2 +- .../versatile_thermostat/prop_algorithm.py | 8 +- .../versatile_thermostat/select.py | 134 +++ .../versatile_thermostat/strings.json | 4 + .../versatile_thermostat/translations/en.json | 4 + .../versatile_thermostat/translations/fr.json | 4 + .../versatile_thermostat/underlyings.py | 6 +- .../versatile_thermostat/vtherm_api.py | 3 - images/central_mode.png | Bin 0 -> 20916 bytes images/config-main.png | Bin 40961 -> 46176 bytes images/config-main0.png | Bin 0 -> 28121 bytes images/plotly-curves.png | Bin 0 -> 51262 bytes pyrightconfig.json | 7 + tests/commons.py | 7 +- tests/const.py | 3 +- tests/test_bugs.py | 4 +- tests/test_central_mode.py | 1040 +++++++++++++++++ tests/test_config_flow.py | 2 + tests/test_security.py | 8 +- tests/test_switch_ac.py | 2 +- tests/test_valve.py | 12 + tests/test_window.py | 2 +- 28 files changed, 1451 insertions(+), 55 deletions(-) create mode 100644 custom_components/versatile_thermostat/select.py create mode 100644 images/central_mode.png create mode 100644 images/config-main0.png create mode 100644 images/plotly-curves.png create mode 100644 pyrightconfig.json create mode 100644 tests/test_central_mode.py diff --git a/.devcontainer/configuration.yaml b/.devcontainer/configuration.yaml index 455b418..0583d22 100644 --- a/.devcontainer/configuration.yaml +++ b/.devcontainer/configuration.yaml @@ -1,5 +1,8 @@ default_config: +# ffmeg +ffmpeg: + logger: default: info logs: diff --git a/README-fr.md b/README-fr.md index 8fe8dc0..d3c00fb 100644 --- a/README-fr.md +++ b/README-fr.md @@ -34,6 +34,7 @@ - [Configurer la gestion de la puissance](#configurer-la-gestion-de-la-puissance) - [Configurer la présence ou l'occupation](#configurer-la-présence-ou-loccupation) - [Configuration avancée](#configuration-avancée) + - [Le contrôle centralisé](#le-contrôle-centralisé) - [Synthèse des paramètres](#synthèse-des-paramètres) - [Exemples de réglage](#exemples-de-réglage) - [Chauffage électrique](#chauffage-électrique) @@ -74,14 +75,16 @@ Ce composant personnalisé pour Home Assistant est une mise à niveau et est une > ![Nouveau](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/new-icon.png?raw=true) _*Nouveautés*_ +> * **Release 5.2** : Ajout d'un `central_mode` permettant de piloter tous les VTherms de façon centralisée [#158](https://github.com/jmcollin78/versatile_thermostat/issues/158). +> * **Release 5.1** : Limitation des valeurs envoyées aux valves et au température envoyées au climate sous-jacent. > * **Release 5.0** : Ajout d'une configuration centrale permettant de mettre en commun les attributs qui peuvent l'être [#239](https://github.com/jmcollin78/versatile_thermostat/issues/239). > * **Release 4.3** : Ajout d'un mode auto-fan pour le type `over_climate` permettant d'activer la ventilation si l'écart de température est important [#223](https://github.com/jmcollin78/versatile_thermostat/issues/223). > * **Release 4.2** : Le calcul de la pente de la courbe de température se fait maintenant en °/heure et non plus en °/min [#242](https://github.com/jmcollin78/versatile_thermostat/issues/242). Correction de la détection automatique des ouvertures par l'ajout d'un lissage de la courbe de température . -> * **Release 4.1** : Ajout d'un mode de régulation **Expert** dans lequel l'utilisateur peut spécifier ses propres paramètres d'auto-régulation au lieu d'utiliser les pre-programmés [#194](https://github.com/jmcollin78/versatile_thermostat/issues/194). -> * **Release 4.0** : Ajout de la prise en charge de la **Versatile Thermostat UI Card**. Voir [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card). Ajout d'un mode de régulation **Slow** pour les appareils de chauffage à latence lente [#168](https://github.com/jmcollin78/versatile_thermostat/issues/168). Changement de la façon dont **la puissance est calculée** dans le cas de VTherm avec des équipements multi-sous-jacents [#146](https://github.com/jmcollin78/versatile_thermostat/issues/146). Ajout de la prise en charge de AC et Heat pour VTherm via un interrupteur également [#144](https://github.com/jmcollin78/versatile_thermostat/pull/144)
Autres versions +> * **Release 4.1** : Ajout d'un mode de régulation **Expert** dans lequel l'utilisateur peut spécifier ses propres paramètres d'auto-régulation au lieu d'utiliser les pre-programmés [#194](https://github.com/jmcollin78/versatile_thermostat/issues/194). +> * **Release 4.0** : Ajout de la prise en charge de la **Versatile Thermostat UI Card**. Voir [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card). Ajout d'un mode de régulation **Slow** pour les appareils de chauffage à latence lente [#168](https://github.com/jmcollin78/versatile_thermostat/issues/168). Changement de la façon dont **la puissance est calculée** dans le cas de VTherm avec des équipements multi-sous-jacents [#146](https://github.com/jmcollin78/versatile_thermostat/issues/146). Ajout de la prise en charge de AC et Heat pour VTherm via un interrupteur également [#144](https://github.com/jmcollin78/versatile_thermostat/pull/144) > * **Release 3.8**: Ajout d'une **fonction d'auto-régulation** pour les thermostats `over climate` dont la régulation est faite par le climate sous-jacent. Cf. [L'auto-régulation](#lauto-régulation) et [#129](https://github.com/jmcollin78/versatile_thermostat/issues/129). Ajout de la **possibilité d'inverser la commande** pour un thermostat `over switch` pour adresser les installations avec fil pilote et diode [#124](https://github.com/jmcollin78/versatile_thermostat/issues/124). > * **Release 3.7**: Ajout du type de **Versatile Thermostat `over valve`** pour piloter une vanne TRV directement ou tout autre équipement type gradateur pour le chauffage. La régulation se fait alors directement en agissant sur le pourcentage d'ouverture de l'entité sous-jacente : 0 la vanne est coupée, 100 : la vanne est ouverte à fond. Cf. [#131](https://github.com/jmcollin78/versatile_thermostat/issues/131). Ajout d'une fonction permettant le bypass de la détection d'ouverture [#138](https://github.com/jmcollin78/versatile_thermostat/issues/138). Ajout de la langue Slovaque > * **Release 3.6**: Ajout du paramètre `motion_off_delay` pour améliorer la gestion de des mouvements [#116](https://github.com/jmcollin78/versatile_thermostat/issues/116), [#128](https://github.com/jmcollin78/versatile_thermostat/issues/128). Ajout du mode AC (air conditionné) pour un VTherm over switch. Préparation du projet Github pour faciliter les contributions [#127](https://github.com/jmcollin78/versatile_thermostat/issues/127) @@ -150,7 +153,8 @@ Ce composant nommé __Versatile thermostat__ gère les cas d'utilisation suivant - Ajouter une **gestion de délestage** ou une régulation pour ne pas dépasser une puissance totale définie. Lorsque la puissance maximale est dépassée, un préréglage caché de « puissance » est défini sur l'entité climatique. Lorsque la puissance passe en dessous du maximum, le préréglage précédent est restauré. - La **gestion de la présence à domicile**. Cette fonctionnalité vous permet de modifier dynamiquement la température du préréglage en tenant compte d'un capteur de présence de votre maison. - Des **services pour interagir avec le thermostat** à partir d'autres intégrations : vous pouvez forcer la présence / la non-présence à l'aide d'un service, et vous pouvez modifier dynamiquement la température des préréglages et changer les paramètres de sécurité. -- Ajouter des capteurs pour voir les états internes du thermostat. +- Ajouter des capteurs pour voir les états internes du thermostat, +- Contrôle centralisé de tous les Versatile Thermostat pour les stopper tous, les passer tous en hors-gel, les forcer en mode Chauffage (l'hiver), les forcer en mode Climatisation (l'été). # Comment installer cet incroyable Thermostat Versatile ? @@ -187,7 +191,9 @@ Suivez ensuite les étapes de configuration comme suit : ## Choix des attributs de base -![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-main.png?raw=true) +![image](/images/config-main0.png?raw=true) + +![image](/images/config-main.png?raw=true) Donnez les principaux attributs obligatoires : 1. un nom (sera le nom de l'intégration et aussi le nom de l'entité climate) @@ -197,7 +203,8 @@ Donnez les principaux attributs obligatoires : 6. une durée de cycle en minutes. A chaque cycle, le radiateur s'allumera puis s'éteindra pendant une durée calculée afin d'atteindre la température ciblée (voir [preset](#configure-the-preset-temperature) ci-dessous). En mode ```over_climate```, le cycle ne sert qu'à faire des controles de base mais ne régule pas directement la température. C'est le ```climate``` sous-jacent qui le fait, 7. les températures minimales et maximales du thermostat, 8. une puissance de l'équipement ce qui va activer les capteurs de puissance et énergie consommée par l'appareil, -9. la liste des fonctionnalités qui seront utilisées pour ce thermostat. En fonction de vos choix, les écrans de configuration suivants s'afficheront ou pas. +9. la possibilité de controler le thermostat de façon centralisée. Cf [controle centralisé](#le-contrôle-centralisé), +10. la liste des fonctionnalités qui seront utilisées pour ce thermostat. En fonction de vos choix, les écrans de configuration suivants s'afficheront ou pas. > ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_ > 1. avec les types ```over_switch``` et ```over_valve```, les calculs sont effectués à chaque cycle. Donc en cas de changement de conditions, il faudra attendre le prochain cycle pour voir un changement. Pour cette raison, le cycle ne doit pas être trop long. **5 min est une bonne valeur**, @@ -515,6 +522,21 @@ Voir [exemple de réglages](#examples-tuning) pour avoir des exemples de réglag > 4. Pour un usage naturel, le ``security_default_on_percent`` doit être inférieur à ``security_min_on_percent``, > 5. Les thermostats de type ``thermostat_over_climate`` ne sont pas concernés par le mode security. +## Le contrôle centralisé +Depuis la release 5.2, si vous avez défini une configuration centralisée, vous avez une nouvelle entité nommée `select.central_mode` qui permet de piloter tous les VTherms avec une seule action. Pour qu'un VTherm soit contrôlable de façon centralisée, il faut que son attribut de configuration nommé `use_central_mode` soit vrai. + +Cette entité se présente sous la forme d'une liste de choix qui contient les choix suivants : +1. `Auto` : le mode 'normal' dans lequel chaque VTherm se comporte comme dans les versions précédentes, +2. `Stooped` : tous les VTherms sont mis à l'arrêt (`hvac_off`), +3. `Heat only` : tous les VTherms sont mis en mode chauffage lorsque ce mode est supporté par le VTherm, sinon il est stoppé, +3. `Cool only` : tous les VTherms sont mis en mode climatisation lorsque ce mode est supporté par le VTherm, sinon il est stoppé, +4. `Frost protection` : tous les VTherms sont mis en preset hors-gel lorsque ce preset est supporté par le VTherm, sinon il est stoppé. + +Il est donc possible de contrôler tous les VTherms (que ceux que l'on désigne explicitement) avec un seul contrôle. +Exemple de rendu : + +![central_mode](/images/central_mode.png?raw=true) + ## Synthèse des paramètres | Paramètre | Libellé | "over switch" | "over climate" | "over valve" | "configuration centrale" | @@ -527,6 +549,7 @@ Voir [exemple de réglages](#examples-tuning) pour avoir des exemples de réglag | ``temp_min`` | Température minimale permise | X | X | X | X | | ``temp_max`` | Température maximale permise | X | X | X | X | | ``device_power`` | Puissance de l'équipement | X | X | X | - | +| ``use_central_mode`` | Autorisation du contrôle centralisé | X | X | X | - | | ``use_window_feature`` | Avec détection des ouvertures | X | X | X | - | | ``use_motion_feature`` | Avec détection de mouvement | X | X | X | - | | ``use_power_feature`` | Avec gestion de la puissance | X | X | X | - | @@ -835,6 +858,8 @@ Les attributs personnalisés sont les suivants : | ``valve_open_percent`` | Le pourcentage d'ouverture de la vanne | | ``regulated_target_temperature`` | La température de consigne calculée par l'auto-régulation | | ``is_inversed`` | True si la commande est inversée (fil pilote avec diode) | +| ``is_controlled_by_central_mode`` | True si le VTherm peut être controlé de façon centrale | +| ``last_central_mode`` | Le dernier mode central utilisé (None si le VTherm n'est pas controlé en central) | # Quelques résultats @@ -1008,6 +1033,10 @@ Remplacez les valeurs entre [[ ]] par les votres. step: day ``` +Exemple de courbes obtenues avec Plotly : + +![image](/images/plotly-curves.png?raw=true) + ## Et toujours de mieux en mieux avec l'AappDaemon NOTIFIER pour notifier les évènements Cette automatisation utilise l'excellente App Daemon nommée NOTIFIER développée par Horizon Domotique que vous trouverez en démonstration [ici](https://www.youtube.com/watch?v=chJylIK0ASo&ab_channel=HorizonDomotique) et le code est [ici](https://github.com/jlpouffier/home-assistant-config/blob/master/appdaemon/apps/notifier.py). Elle permet de notifier les utilisateurs du logement lorsqu'un des évènements touchant à la sécurité survient sur un des Versatile Thermostats. diff --git a/README.md b/README.md index a5b1d99..7056b92 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ - [Configure the power management](#configure-the-power-management) - [Configure presence or occupancy](#configure-presence-or-occupancy) - [Advanced configuration](#advanced-configuration) + - [Centralized control](#centralized-control) - [Parameters synthesis](#parameters-synthesis) - [Examples tuning](#examples-tuning) - [Electrical heater](#electrical-heater) @@ -74,16 +75,18 @@ This custom component for Home Assistant is an upgrade and is a complete rewrite of the component "Awesome thermostat" (see [Github](https://github.com/dadge/awesome_thermostat)) with addition of features. >![New](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/new-icon.png?raw=true) _*News*_ +> * **Release 5.2**: Added a `central_mode` allowing all VTherms to be controlled centrally [#158](https://github.com/jmcollin78/versatile_thermostat/issues/158). +> * **Release 5.1**: Limitation of the values sent to the valves and the temperature sent to the underlying climate. > * **Release 5.0**: Added a central configuration allowing the sharing of attributes that can be shared [#239](https://github.com/jmcollin78/versatile_thermostat/issues/239). > * **Release 4.3**: Added an auto-fan mode for the `over_climate` type allowing ventilation to be activated if the temperature difference is significant [#223](https://github.com/jmcollin78/versatile_thermostat/issues/223). > * **Release 4.2**: The calculation of the slope of the temperature curve is now done in °/hour and no longer in °/min [#242](https://github.com/jmcollin78/versatile_thermostat/issues/242). Correction of automatic detection of openings by adding smoothing of the temperature curve. +
+Others releases + > * **Release 4.1**: Added an **Expert** regulation mode in which the user can specify their own auto-regulation parameters instead of using the pre-programmed ones [#194]( https://github.com/jmcollin78/versatile_thermostat/issues/194). > * **Release 4.0**: Added the support of **Versatile Thermostat UI Card**. See [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card). Added a **Slow** regulation mode for slow latency heating devices [#168](https://github.com/jmcollin78/versatile_thermostat/issues/168). Change the way **the power is calculated** in case of VTherm with multi-underlying equipements [#146](https://github.com/jmcollin78/versatile_thermostat/issues/146). Added the support of AC and Heat for VTherm over switch alse [#144](https://github.com/jmcollin78/versatile_thermostat/pull/144) > * **Release 3.8**: Added a **self-regulation function** for `over climate` thermostats whose regulation is done by the underlying climate. See [Self-regulation](#self-regulation) and [#129](https://github.com/jmcollin78/versatile_thermostat/issues/129). Added the possibility of **inverting the command** for an `over switch` thermostat to address installations with pilot wire and diode [#124](https://github.com/jmcollin78/versatile_thermostat/issues/124). > * **Release 3.7**: Addition of the **Versatile Thermostat type `over valve`** to control a TRV valve directly or any other dimmer type equipment for heating. Regulation is then done directly by acting on the opening percentage of the underlying entity: 0 the valve is cut off, 100: the valve is fully opened. See [#131](https://github.com/jmcollin78/versatile_thermostat/issues/131). Added a function allowing the bypass of opening detection [#138](https://github.com/jmcollin78/versatile_thermostat/issues/138). Added Slovak language -
-Others releases - > * **Release 3.6**: Added the `motion_off_delay` parameter to improve motion management [#116](https://github.com/jmcollin78/versatile_thermostat/issues/116), [#128](https://github.com/jmcollin78/versatile_thermostat/issues/128). Added AC (air conditioning) mode for a VTherm over switch. Preparing the Github project to facilitate contributions [#127](https://github.com/jmcollin78/versatile_thermostat/issues/127) > * **Release 3.5**: Multiple thermostats when using "thermostat over another thermostat" mode [#113](https://github.com/jmcollin78/versatile_thermostat/issues/113) > * **Release 3.4**: bug fixes and expose preset temperatures for AC mode [#103](https://github.com/jmcollin78/versatile_thermostat/issues/103) @@ -150,7 +153,8 @@ This component named __Versatile thermostat__ manage the following use cases : - Add **power shedding management** or regulation to avoid exceeding a defined total power. When max power is exceeded, a hidden 'power' preset is set on the climate entity. When power goes below the max, the previous preset is restored. - Add **home presence management**. This feature allows you to dynamically change the temperature of preset considering a occupancy sensor of your home. - Add **services to interact with the thermostat** from others integration: you can force the presence / un-presence using a service, and you can dynamically change the temperature of the presets and change dynamically the safety parameters. -- Add sensors to see the internal states of the thermostat +- Add sensors to see the internal states of the thermostat, +- Centralized control of all Versatile Thermostats to stop them all, switch them all to frost protection, force them into Heating mode (winter), force them into Cooling mode (summer). # How to install this incredible Versatile Thermostat ? @@ -185,7 +189,10 @@ The configuration can be change through the same interface. Simply select the th Then follow the configurations steps as follow: ## Minimal configuration update -![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-main.png?raw=true) + +![image](/images/config-main0.png?raw=true) + +![image](/images/config-main.png?raw=true) Give the main mandatory attributes: 1. a name (will be the name of the integration and also the name of the climate entity) @@ -195,7 +202,8 @@ Give the main mandatory attributes: 6. a cycle duration in minutes. On each cycle, the heater will cycle on and then off for a calculated time to reach the target temperature (see [preset](#configure-the-preset-temperature) below). In ```over_climate``` mode, the cycle is only used to carry out basic controls but does not directly regulate the temperature. It's the underlying climate that does it, 7. minimum and maximum thermostat temperatures, 8. the power of the l'équipement which will activate the power and energy sensors of the device, -9. the list of features that will be used for this thermostat. Depending on your choices, the following configuration screens will appear or not. +9. the possibility of controlling the thermostat centrally. Cf [centralized control](#centralized-control), +10. the list of features that will be used for this thermostat. Depending on your choices, the following configuration screens will appear or not. > ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_ > 1. With the ```thermostat_over_switch``` type, calculation are done at each cycle. So in case of conditions change, you will have to wait for the next cycle to see a change. For this reason, the cycle should not be too long. **5 min is a good value**, @@ -500,6 +508,21 @@ See [example tuning](#examples-tuning) for common tuning examples > 4. For natural usage, the ``security_default_on_percent`` should be less than ``security_min_on_percent``, > 5. Thermostat of type ``thermostat_over_climate`` are not concerned by the safety feature. +## Centralized control +Since release 5.2, if you have defined a centralized configuration, you have a new entity named `select.central_mode` which allows you to control all VTherms with a single action. For a VTherm to be centrally controllable, its configuration attribute named `use_central_mode` must be true. + +This entity is presented in the form of a list of choices which contains the following choices: +1. `Auto`: the 'normal' mode in which each VTherm behaves as in previous versions, +2. `Stooped`: all VTherms are turned off (`hvac_off`), +3. `Heat only`: all VTherms are put in heating mode when this mode is supported by the VTherm, otherwise it is stopped, +3. `Cool only`: all VTherms are put in cooling mode when this mode is supported by the VTherm, otherwise it is stopped, +4. `Frost protection`: all VTherms are put in frost protection preset when this preset is supported by the VTherm, otherwise it is stopped. + +It is therefore possible to control all VTherms (only those explicitly designated) with a single control. +Example rendering: + +![central_mode](/images/central_mode.png?raw=true) + ## Parameters synthesis | Paramètre | Libellé | "over switch" | "over climate" | "over valve" | "central configuration" | @@ -512,6 +535,7 @@ See [example tuning](#examples-tuning) for common tuning examples | ``temp_min`` | Minimal temperature allowed | X | X | X | X | | ``temp_max`` | Maximal temperature allowed | X | X | X | X | | ``device_power`` | Total device power | X | X | X | - | +| ``use_central_mode`` | Allow the centralized control | X | X | X | - | | ``use_window_feature`` | Use window detection | X | X | X | - | | ``use_motion_feature`` | Use motion detection | X | X | X | - | | ``use_power_feature`` | Use power management | X | X | X | - | @@ -819,6 +843,8 @@ Custom attributes are the following: | ``valve_open_percent`` | The opening percentage of the valve | | ``regulated_target_temperature`` | The self-regulated target temperature calculated | | ``is_inversed`` | True if the command is inversed (pilot wire with diode) | +| ``is_controlled_by_central_mode`` | True if the VTherm can be centrally controlled | +| ``last_central_mode`` | The last central mode used (None if the VTherm is not centrally controlled) | # Some results @@ -991,6 +1017,11 @@ Replace values in [[ ]] by yours. step: day ``` +Example of graph obtained with Plotly : + +![image](/images/plotly-curves.png?raw=true) + + ## And always better and better with the NOTIFIER daemon app to notify events This automation uses the excellent App Daemon named NOTIFIER developed by Horizon Domotique that you will find in demonstration [here](https://www.youtube.com/watch?v=chJylIK0ASo&ab_channel=HorizonDomotique) and the code is [here](https ://github.com/jlpouffier/home-assistant-config/blob/master/appdaemon/apps/notifier.py). It allows you to notify the users of the accommodation when one of the events affecting safety occurs on one of the Versatile Thermostats. diff --git a/custom_components/versatile_thermostat/base_thermostat.py b/custom_components/versatile_thermostat/base_thermostat.py index 23f39cc..6707e16 100644 --- a/custom_components/versatile_thermostat/base_thermostat.py +++ b/custom_components/versatile_thermostat/base_thermostat.py @@ -116,6 +116,11 @@ from .const import ( ATTR_TOTAL_ENERGY, PRESET_AC_SUFFIX, DEFAULT_SHORT_EMA_PARAMS, + CENTRAL_MODE_AUTO, + CENTRAL_MODE_STOPPED, + CENTRAL_MODE_HEAT_ONLY, + CENTRAL_MODE_COOL_ONLY, + CENTRAL_MODE_FROST_PROTECTION, ) from .config_schema import * # pylint: disable=wildcard-import, unused-wildcard-import @@ -158,6 +163,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity): frozenset( { "is_on", + "is_controlled_by_central_mode", + "last_central_mode", "type", "frost_temp", "eco_temp", @@ -273,6 +280,9 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._now = None self._attr_fan_mode = None + + self._is_central_mode = None + self._last_central_mode = None self.post_init(entry_infos) def clean_central_config_doublon(self, config_entry, central_config) -> dict: @@ -434,6 +444,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self._presence_on = self._presence_sensor_entity_id is not None if self._ac_mode: + # Added by https://github.com/jmcollin78/versatile_thermostat/pull/144 + # Some over_switch can do both heating and cooling self._hvac_list = [HVACMode.HEAT, HVACMode.COOL, HVACMode.OFF] else: self._hvac_list = [HVACMode.HEAT, HVACMode.OFF] @@ -552,6 +564,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity): short_ema_params.get("max_alpha"), ) + self._is_central_mode = not ( + entry_infos.get(CONF_USE_CENTRAL_MODE) is False + ) # Default value (None) is True + _LOGGER.debug( "%s - Creation of a new VersatileThermostat entity: unique_id=%s", self, @@ -1130,6 +1146,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity): """True if the VTherm is on (! HVAC_OFF)""" return self.hvac_mode and self.hvac_mode != HVACMode.OFF + @property + def is_controlled_by_central_mode(self) -> bool: + """Returns True if this VTherm can be controlled by the central_mode""" + return self._is_central_mode + + @property + def last_central_mode(self) -> str | None: + """Returns the last central_mode taken into account. + Is None if the VTherm is not controlled by central_mode""" + return self._last_central_mode + def underlying_entity_id(self, index=0) -> str | None: """The climate_entity_id. Added for retrocompatibility reason""" if index < self.nb_underlying_entities: @@ -1177,11 +1204,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity): ) # If AC is on maybe we have to change the temperature in force mode, but not in frost mode (there is no Frost protection possible in AC mode) - if self._ac_mode: + if self._hvac_mode == HVACMode.COOL: if self.preset_mode != PRESET_FROST_PROTECTION: await self._async_set_preset_mode_internal(self._attr_preset_mode, True) else: - await self._async_set_preset_mode_internal(PRESET_ECO, True) + await self._async_set_preset_mode_internal(PRESET_ECO, True, False) if need_control_heating and sub_need_control_heating: await self.async_control_heating(force=True) @@ -1195,12 +1222,17 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.async_write_ha_state() self.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": self._hvac_mode}) - async def async_set_preset_mode(self, preset_mode): + @overrides + async def async_set_preset_mode(self, preset_mode, overwrite_saved_preset=True): """Set new preset mode.""" - await self._async_set_preset_mode_internal(preset_mode) + await self._async_set_preset_mode_internal( + preset_mode, force=False, overwrite_saved_preset=overwrite_saved_preset + ) await self.async_control_heating(force=True) - async def _async_set_preset_mode_internal(self, preset_mode, force=False): + async def _async_set_preset_mode_internal( + self, preset_mode, force=False, overwrite_saved_preset=True + ): """Set new preset mode.""" _LOGGER.info("%s - Set preset_mode: %s force=%s", self, preset_mode, force) if ( @@ -1215,10 +1247,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity): # I don't think we need to call async_write_ha_state if we didn't change the state return - # In security mode don't change preset but memorise the new expected preset when security will be off + # In safety mode don't change preset but memorise the new expected preset when security will be off if preset_mode != PRESET_SECURITY and self._security_state: _LOGGER.debug( - "%s - is in security mode. Just memorise the new expected ", self + "%s - is in safety mode. Just memorise the new expected ", self ) if preset_mode not in HIDDEN_PRESETS: self._saved_preset_mode = preset_mode @@ -1242,7 +1274,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity): self.reset_last_temperature_time(old_preset_mode) - self.save_preset_mode() + if overwrite_saved_preset: + self.save_preset_mode() self.recalculate() self.send_event(EventType.PRESET_EVENT, {"preset": self._attr_preset_mode}) @@ -1442,16 +1475,19 @@ class BaseThermostat(ClimateEntity, RestoreEntity): else: if not self._window_state: _LOGGER.info( - "%s - Window is closed. Restoring hvac_mode '%s'", + "%s - Window is closed. Restoring hvac_mode '%s' if central_mode is not STOPPED", self, self._saved_hvac_mode, ) - await self.restore_hvac_mode(True) + if self.last_central_mode != CENTRAL_MODE_STOPPED: + await self.restore_hvac_mode(True) elif self._window_state: _LOGGER.info( "%s - Window is open. Set hvac_mode to '%s'", self, HVACMode.OFF ) - self.save_hvac_mode() + if self.last_central_mode in [CENTRAL_MODE_AUTO, None]: + self.save_hvac_mode() + await self.async_set_hvac_mode(HVACMode.OFF) self.update_custom_attributes() @@ -1604,7 +1640,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): state.last_changed.astimezone(self._current_tz), ) - # try to restart if we were in security mode + # try to restart if we were in safety mode if self._security_state: await self.check_security() @@ -1631,7 +1667,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): state.last_changed.astimezone(self._current_tz), ) - # try to restart if we were in security mode + # try to restart if we were in safety mode if self._security_state: await self.check_security() except ValueError as ex: @@ -1998,6 +2034,67 @@ class BaseThermostat(ClimateEntity, RestoreEntity): return self._overpowering_state + async def check_central_mode(self, new_central_mode, old_central_mode) -> None: + """Take into account a central mode change""" + if not self.is_controlled_by_central_mode: + self._last_central_mode = None + return + + _LOGGER.info( + "%s - Central mode have change from %s to %s", + self, + old_central_mode, + new_central_mode, + ) + + self._last_central_mode = new_central_mode + + def save_all(): + """save preset and hvac_mode""" + self.save_preset_mode() + self.save_hvac_mode() + + if new_central_mode == CENTRAL_MODE_AUTO: + if self.window_state is not STATE_ON: + await self.restore_hvac_mode() + await self.restore_preset_mode() + + return + + if old_central_mode == CENTRAL_MODE_AUTO and self.window_state is not STATE_ON: + save_all() + + if new_central_mode == CENTRAL_MODE_STOPPED: + await self.async_set_hvac_mode(HVACMode.OFF) + return + + if new_central_mode == CENTRAL_MODE_COOL_ONLY: + if HVACMode.COOL in self.hvac_modes: + await self.async_set_hvac_mode(HVACMode.COOL) + else: + await self.async_set_hvac_mode(HVACMode.OFF) + return + + if new_central_mode == CENTRAL_MODE_HEAT_ONLY: + if HVACMode.HEAT in self.hvac_modes: + await self.async_set_hvac_mode(HVACMode.HEAT) + else: + await self.async_set_hvac_mode(HVACMode.OFF) + return + + if new_central_mode == CENTRAL_MODE_FROST_PROTECTION: + if ( + PRESET_FROST_PROTECTION in self.preset_modes + and HVACMode.HEAT in self.hvac_modes + ): + await self.async_set_hvac_mode(HVACMode.HEAT) + await self.async_set_preset_mode( + PRESET_FROST_PROTECTION, overwrite_saved_preset=False + ) + else: + await self.async_set_hvac_mode(HVACMode.OFF) + return + def _set_now(self, now: datetime): """Set the now timestamp. This is only for tests purpose""" self._now = now @@ -2064,7 +2161,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): if shouldStartSecurity: if shouldClimateBeInSecurity: _LOGGER.warning( - "%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and underlying climate is %s. Set it into security mode", + "%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and underlying climate is %s. Setting it into safety mode", self, self._security_delay_min, delta_temp, @@ -2073,13 +2170,13 @@ class BaseThermostat(ClimateEntity, RestoreEntity): ) elif shouldSwitchBeInSecurity: _LOGGER.warning( - "%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and on_percent (%.2f) is over defined value (%.2f). Set it into security mode", + "%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and on_percent (%.2f %%) is over defined value (%.2f %%). Set it into safety mode", self, self._security_delay_min, delta_temp, delta_ext_temp, - self._prop_algorithm.on_percent, - self._security_min_on_percent, + self._prop_algorithm.on_percent * 100, + self._security_min_on_percent * 100, ) self.send_event( @@ -2097,7 +2194,7 @@ class BaseThermostat(ClimateEntity, RestoreEntity): }, ) - # Start security mode + # Start safety mode if shouldStartSecurity: self._security_state = True self.save_hvac_mode() @@ -2125,10 +2222,10 @@ class BaseThermostat(ClimateEntity, RestoreEntity): }, ) - # Stop security mode + # Stop safety mode if shouldStopSecurity: _LOGGER.warning( - "%s - End of security mode. restoring hvac_mode to %s and preset_mode to %s", + "%s - End of safety mode. restoring hvac_mode to %s and preset_mode to %s", self, self._saved_hvac_mode, self._saved_preset_mode, @@ -2239,6 +2336,8 @@ class BaseThermostat(ClimateEntity, RestoreEntity): "hvac_mode": self.hvac_mode, "preset_mode": self.preset_mode, "type": self._thermostat_type, + "is_controlled_by_central_mode": self.is_controlled_by_central_mode, + "last_central_mode": self.last_central_mode, "frost_temp": self._presets[PRESET_FROST_PROTECTION], "eco_temp": self._presets[PRESET_ECO], "boost_temp": self._presets[PRESET_BOOST], @@ -2374,11 +2473,11 @@ class BaseThermostat(ClimateEntity, RestoreEntity): entity_id: climate.thermostat_2 """ _LOGGER.info( - "%s - Calling service_set_security, delay_min: %s, min_on_percent: %s, default_on_percent: %s", + "%s - Calling service_set_security, delay_min: %s, min_on_percent: %s %%, default_on_percent: %s %%", self, delay_min, - min_on_percent, - default_on_percent, + min_on_percent*100, + default_on_percent*100, ) if delay_min: self._security_delay_min = delay_min diff --git a/custom_components/versatile_thermostat/config_schema.py b/custom_components/versatile_thermostat/config_schema.py index 4450ee3..5971e29 100644 --- a/custom_components/versatile_thermostat/config_schema.py +++ b/custom_components/versatile_thermostat/config_schema.py @@ -42,6 +42,7 @@ STEP_MAIN_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name ), vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int, vol.Optional(CONF_DEVICE_POWER, default="1"): vol.Coerce(float), + vol.Optional(CONF_USE_CENTRAL_MODE, default=True): cv.boolean, vol.Optional(CONF_USE_WINDOW_FEATURE, default=False): cv.boolean, vol.Optional(CONF_USE_MOTION_FEATURE, default=False): cv.boolean, vol.Optional(CONF_USE_POWER_FEATURE, default=False): cv.boolean, diff --git a/custom_components/versatile_thermostat/const.py b/custom_components/versatile_thermostat/const.py index e5236fb..794d70d 100644 --- a/custom_components/versatile_thermostat/const.py +++ b/custom_components/versatile_thermostat/const.py @@ -35,7 +35,12 @@ HIDDEN_PRESETS = [PRESET_POWER, PRESET_SECURITY] DOMAIN = "versatile_thermostat" -PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.BINARY_SENSOR, Platform.SENSOR] +PLATFORMS: list[Platform] = [ + Platform.CLIMATE, + Platform.BINARY_SENSOR, + Platform.SENSOR, + Platform.SELECT, +] CONF_HEATER = "heater_entity_id" CONF_HEATER_2 = "heater_entity2_id" @@ -113,6 +118,8 @@ CONF_USE_PRESENCE_CENTRAL_CONFIG = "use_presence_central_config" CONF_USE_PRESETS_CENTRAL_CONFIG = "use_presets_central_config" CONF_USE_ADVANCED_CENTRAL_CONFIG = "use_advanced_central_config" +CONF_USE_CENTRAL_MODE = "use_central_mode" + DEFAULT_SHORT_EMA_PARAMS = { "max_alpha": 0.5, # In sec @@ -242,6 +249,7 @@ ALL_CONF = ( CONF_USE_POWER_CENTRAL_CONFIG, CONF_USE_PRESENCE_CENTRAL_CONFIG, CONF_USE_ADVANCED_CENTRAL_CONFIG, + CONF_USE_CENTRAL_MODE, ] + CONF_PRESETS_VALUES + CONF_PRESETS_AWAY_VALUES @@ -297,6 +305,19 @@ AUTO_FAN_DEACTIVATED_MODES = ["mute", "auto", "low"] CENTRAL_CONFIG_NAME = "Central configuration" +CENTRAL_MODE_AUTO = "Auto" +CENTRAL_MODE_STOPPED = "Stopped" +CENTRAL_MODE_HEAT_ONLY = "Heat only" +CENTRAL_MODE_COOL_ONLY = "Cool only" +CENTRAL_MODE_FROST_PROTECTION = "Frost protection" +CENTRAL_MODES = [ + CENTRAL_MODE_AUTO, + CENTRAL_MODE_STOPPED, + CENTRAL_MODE_HEAT_ONLY, + CENTRAL_MODE_COOL_ONLY, + CENTRAL_MODE_FROST_PROTECTION, +] + # A special regulation parameter suggested by @Maia here: https://github.com/jmcollin78/versatile_thermostat/discussions/154 class RegulationParamSlow: diff --git a/custom_components/versatile_thermostat/manifest.json b/custom_components/versatile_thermostat/manifest.json index 324ea0f..76798cc 100644 --- a/custom_components/versatile_thermostat/manifest.json +++ b/custom_components/versatile_thermostat/manifest.json @@ -14,6 +14,6 @@ "quality_scale": "silver", "requirements": [], "ssdp": [], - "version": "4.3.0", + "version": "5.2.0", "zeroconf": [] } \ No newline at end of file diff --git a/custom_components/versatile_thermostat/prop_algorithm.py b/custom_components/versatile_thermostat/prop_algorithm.py index e595dbc..2a8cc38 100644 --- a/custom_components/versatile_thermostat/prop_algorithm.py +++ b/custom_components/versatile_thermostat/prop_algorithm.py @@ -140,27 +140,27 @@ class PropAlgorithm: self._off_time_sec = self._cycle_min * 60 - self._on_time_sec def set_security(self, default_on_percent: float): - """Set a default value for on_percent (used for security mode)""" + """Set a default value for on_percent (used for safety mode)""" self._security = True self._default_on_percent = default_on_percent self._calculate_internal() def unset_security(self): - """Unset the security mode""" + """Unset the safety mode""" self._security = False self._calculate_internal() @property def on_percent(self) -> float: """Returns the percentage the heater must be ON - In security mode this value is overriden with the _default_on_percent + In safety mode this value is overriden with the _default_on_percent (1 means the heater will be always on, 0 never on)""" # pylint: disable=line-too-long return round(self._on_percent, 2) @property def calculated_on_percent(self) -> float: """Returns the calculated percentage the heater must be ON - Calculated means NOT overriden even in security mode + Calculated means NOT overriden even in safety mode (1 means the heater will be always on, 0 never on)""" # pylint: disable=line-too-long return round(self._calculated_on_percent, 2) diff --git a/custom_components/versatile_thermostat/select.py b/custom_components/versatile_thermostat/select.py new file mode 100644 index 0000000..8c77ec6 --- /dev/null +++ b/custom_components/versatile_thermostat/select.py @@ -0,0 +1,134 @@ +# pylint: disable=unused-argument + +""" Implements the VersatileThermostat select component """ +import logging + +from homeassistant.const import EVENT_HOMEASSISTANT_START +from homeassistant.core import HomeAssistant, CoreState, callback + +from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN +from homeassistant.components.select import SelectEntity +from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType +from homeassistant.config_entries import ConfigEntry +from homeassistant.helpers.restore_state import RestoreEntity +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.entity_component import EntityComponent + + +from custom_components.versatile_thermostat.base_thermostat import BaseThermostat +from .const import ( + DOMAIN, + DEVICE_MANUFACTURER, + CONF_NAME, + CONF_THERMOSTAT_TYPE, + CONF_THERMOSTAT_CENTRAL_CONFIG, + CENTRAL_MODE_AUTO, + CENTRAL_MODES, + overrides, +) + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the VersatileThermostat selects with config flow.""" + _LOGGER.debug( + "Calling async_setup_entry entry=%s, data=%s", entry.entry_id, entry.data + ) + + unique_id = entry.entry_id + name = entry.data.get(CONF_NAME) + vt_type = entry.data.get(CONF_THERMOSTAT_TYPE) + + if vt_type != CONF_THERMOSTAT_CENTRAL_CONFIG: + return + + entities = [ + CentralModeSelect(hass, unique_id, name, entry.data), + ] + + async_add_entities(entities, True) + + +class CentralModeSelect(SelectEntity, RestoreEntity): + """Representation of a Energy sensor which exposes the energy""" + + def __init__(self, hass: HomeAssistant, unique_id, name, entry_infos) -> None: + """Initialize the energy sensor""" + self._config_id = unique_id + self._device_name = entry_infos.get(CONF_NAME) + self._attr_name = "Central Mode" + self._attr_unique_id = "central_mode" + self._attr_options = CENTRAL_MODES + self._attr_current_option = CENTRAL_MODE_AUTO + + @property + def icon(self) -> str | None: + return "mdi:form-select" + + @property + def device_info(self) -> DeviceInfo: + """Return the device info.""" + return DeviceInfo( + entry_type=DeviceEntryType.SERVICE, + identifiers={(DOMAIN, self._config_id)}, + name=self._device_name, + manufacturer=DEVICE_MANUFACTURER, + model=DOMAIN, + ) + + @overrides + async def async_added_to_hass(self) -> None: + await super().async_added_to_hass() + + old_state = await self.async_get_last_state() + _LOGGER.debug( + "%s - Calling async_added_to_hass old_state is %s", self, old_state + ) + if old_state is not None: + self._attr_current_option = old_state.state + + @callback + async def _async_startup_internal(*_): + _LOGGER.debug("%s - Calling async_startup_internal", self) + await self.notify_central_mode_change() + + if self.hass.state == CoreState.running: + await _async_startup_internal() + else: + self.hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_START, _async_startup_internal + ) + + @overrides + async def async_select_option(self, option: str) -> None: + """Change the selected option.""" + old_option = self._attr_current_option + + if option == old_option: + return + + if option in CENTRAL_MODES: + self._attr_current_option = option + await self.notify_central_mode_change(old_central_mode=old_option) + + async def notify_central_mode_change(self, old_central_mode=None): + """Notify all VTherm that the central_mode have change""" + # Update all VTherm states + component: EntityComponent[ClimateEntity] = self.hass.data[CLIMATE_DOMAIN] + for entity in component.entities: + if isinstance(entity, BaseThermostat): + _LOGGER.debug( + "Changing the central_mode. We have find %s to update", + entity.name, + ) + await entity.check_central_mode( + self._attr_current_option, old_central_mode + ) + + def __str__(self): + return f"VersatileThermostat-{self.name}" diff --git a/custom_components/versatile_thermostat/strings.json b/custom_components/versatile_thermostat/strings.json index 0a7188d..4a000a5 100644 --- a/custom_components/versatile_thermostat/strings.json +++ b/custom_components/versatile_thermostat/strings.json @@ -24,6 +24,7 @@ "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", "device_power": "Device power", + "use_central_mode": "Enable the control by central mode ('central_mode')", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", @@ -31,6 +32,7 @@ "use_main_central_config": "Use central main configuration" }, "data_description": { + "use_central_mode": "Check to enable the control of the VTherm with the select central_mode entities", "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific main configuration for this VTherm", "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } @@ -254,6 +256,7 @@ "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", "device_power": "Device power", + "use_central_mode": "Enable the control by central mode ('central_mode')", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", @@ -261,6 +264,7 @@ "use_main_central_config": "Use central main configuration" }, "data_description": { + "use_central_mode": "Check to enable the control of the VTherm with the select central_mode entities", "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific configuration for this VTherm", "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } diff --git a/custom_components/versatile_thermostat/translations/en.json b/custom_components/versatile_thermostat/translations/en.json index 0a7188d..4a000a5 100644 --- a/custom_components/versatile_thermostat/translations/en.json +++ b/custom_components/versatile_thermostat/translations/en.json @@ -24,6 +24,7 @@ "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", "device_power": "Device power", + "use_central_mode": "Enable the control by central mode ('central_mode')", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", @@ -31,6 +32,7 @@ "use_main_central_config": "Use central main configuration" }, "data_description": { + "use_central_mode": "Check to enable the control of the VTherm with the select central_mode entities", "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific main configuration for this VTherm", "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } @@ -254,6 +256,7 @@ "temp_min": "Minimal temperature allowed", "temp_max": "Maximal temperature allowed", "device_power": "Device power", + "use_central_mode": "Enable the control by central mode ('central_mode')", "use_window_feature": "Use window detection", "use_motion_feature": "Use motion detection", "use_power_feature": "Use power management", @@ -261,6 +264,7 @@ "use_main_central_config": "Use central main configuration" }, "data_description": { + "use_central_mode": "Check to enable the control of the VTherm with the select central_mode entities", "use_main_central_config": "Check to use the central main configuration. Uncheck to use a specific configuration for this VTherm", "external_temperature_sensor_entity_id": "Outdoor temperature sensor entity id. Not used if central configuration is selected" } diff --git a/custom_components/versatile_thermostat/translations/fr.json b/custom_components/versatile_thermostat/translations/fr.json index 15ce526..09b4125 100644 --- a/custom_components/versatile_thermostat/translations/fr.json +++ b/custom_components/versatile_thermostat/translations/fr.json @@ -24,6 +24,7 @@ "temp_min": "Température minimale permise", "temp_max": "Température maximale permise", "device_power": "Puissance de l'équipement", + "use_central_mode": "Autoriser le controle par le mode central ('central_mode`)", "use_window_feature": "Avec détection des ouvertures", "use_motion_feature": "Avec détection de mouvement", "use_power_feature": "Avec gestion de la puissance", @@ -31,6 +32,7 @@ "use_main_central_config": "Utiliser la configuration centrale principale" }, "data_description": { + "use_central_mode": "Cochez pour autoriser le contrôle du VTherm par la liste déroulante 'central_mode' de l'entité configuration centrale", "external_temperature_sensor_entity_id": "Entity id du capteur de température extérieure. N'est pas utilisé si la configuration centrale est utilisée", "use_main_central_config": "Cochez pour utiliser la configuration centrale principale. Décochez et saisissez les attributs pour utiliser une configuration spécifique principale" } @@ -254,6 +256,7 @@ "temp_min": "Température minimale permise", "temp_max": "Température maximale permise", "device_power": "Puissance de l'équipement", + "use_central_mode": "Autoriser le controle par le mode central ('central_mode`)", "use_window_feature": "Avec détection des ouvertures", "use_motion_feature": "Avec détection de mouvement", "use_power_feature": "Avec gestion de la puissance", @@ -261,6 +264,7 @@ "use_main_central_config": "Utiliser la configuration centrale" }, "data_description": { + "use_central_mode": "Cochez pour autoriser le contrôle du VTherm par la liste déroulante 'central_mode' de l'entité configuration centrale", "use_main_central_config": "Cochez pour utiliser la configuration centrale. Décochez et saisissez les attributs pour utiliser une configuration spécifique", "external_temperature_sensor_entity_id": "Entity id du capteur de température extérieure. N'est pas utilisé si la configuration centrale est utilisée" } diff --git a/custom_components/versatile_thermostat/underlyings.py b/custom_components/versatile_thermostat/underlyings.py index ec2bb92..b82e6a8 100644 --- a/custom_components/versatile_thermostat/underlyings.py +++ b/custom_components/versatile_thermostat/underlyings.py @@ -141,8 +141,9 @@ class UnderlyingEntity: await self.set_hvac_mode(hvac_mode) elif hvac_mode != HVACMode.OFF and not self.is_device_active: _LOGGER.warning( - "%s - The hvac mode is ON, but the underlying device is not ON. Turning on device %s", + "%s - The hvac mode is %s, but the underlying device is not ON. Turning on device %s if needed", self, + hvac_mode, self._entity_id, ) await self.set_hvac_mode(hvac_mode) @@ -354,7 +355,7 @@ class UnderlyingSwitch(UnderlyingEntity): if await self._thermostat.check_overpowering(): _LOGGER.debug("%s - End of cycle (3)", self) return - # Security mode could have change the on_time percent + # safety mode could have change the on_time percent await self._thermostat.check_security() time = self._on_time_sec @@ -790,6 +791,7 @@ class UnderlyingValve(UnderlyingEntity): ): """We use this function to change the on_percent""" if force: + self._percent_open = self.cap_sent_value(self._percent_open) await self.send_percent_open() @overrides diff --git a/custom_components/versatile_thermostat/vtherm_api.py b/custom_components/versatile_thermostat/vtherm_api.py index 9d93935..964e790 100644 --- a/custom_components/versatile_thermostat/vtherm_api.py +++ b/custom_components/versatile_thermostat/vtherm_api.py @@ -20,7 +20,6 @@ class VersatileThermostatAPI(dict): """The VersatileThermostatAPI""" _hass: HomeAssistant = None - # _entries: Dict(str, ConfigEntry) @classmethod def get_vtherm_api(cls, hass=None): @@ -64,14 +63,12 @@ class VersatileThermostatAPI(dict): def add_entry(self, entry: ConfigEntry): """Add a new entry""" _LOGGER.debug("Add the entry %s", entry.entry_id) - # self._entries[entry.entry_id] = entry # Add the entry in hass.data VersatileThermostatAPI._hass.data[DOMAIN][entry.entry_id] = entry def remove_entry(self, entry: ConfigEntry): """Remove an entry""" _LOGGER.debug("Remove the entry %s", entry.entry_id) - # self._entries.pop(entry.entry_id) VersatileThermostatAPI._hass.data[DOMAIN].pop(entry.entry_id) # If not more entries are preset, remove the API if len(self) == 0: diff --git a/images/central_mode.png b/images/central_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0f1a3f843787d81129100035236a45b6d1f01c GIT binary patch literal 20916 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 literal 0 HcmV?d00001 diff --git a/images/config-main.png b/images/config-main.png index 87e7ad1df255d07e4ac2a50cc1bd217a2cbba9fe..bb97337aafa7f20404c81bdfb217f6333d5423ac 100644 GIT binary patch literal 46176 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�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

U_BISznEdOfVo7d|xUC&To%C|q=-}f}spCel z4Jm8wPTwvNnG2KtxOHn6k-RHZfAH!-_;1oZ(KcCaZS~?-<>veVnTB4>*_#O2Zp=Bv zmKSg$Cs>zl*i@@gq>^XH&uxcsw_VIY9*DhHpan&a+5@%}ip5hDCT}pLRC$NGEHfLi zDc6n5?b%^T#O#YCas_3VDE{|F9GmvD4#8FqFb-PmPJ-tI^Py0Afc+5OI%i!j7mOt% z#)mB0kPRGpoL_G?KI`tqYbE!3vZ=jYO(L0^tK+@An$I@wP=Lr?pw{WT-Xqat_B~8R zK7LNx=|~TQ7zqK$-IV~lyEk4<){E5;#Vs>aHE%PXd2oxvjPey6({|KpOR2I#C(iR!xsdK%z73wp2=VS!`byD@}}p9c!MM&YFCO;%8PmzR?tJ(xG?D=$eFS;XC%N zU!ma5iFNK1{$lM_owaxMDOzq!U$y#!+v8O4FpSAJ%i{eGLf?#MF_2mZEOP|YM#p{r zExUd7c-}9ZiIYt1^d4}D0b69vQZaFS@-pL16J#B3mvU~emEF7L=&JUQq}aRzesQaH z8KmR(GalgFYOHffAqmYA50Owt9H1q@F)(B%I3@^Lic z?Q$sv$L69@D)c!UO-ubJy{qD??+&R3daWE)2GXs(o+#SgqCOa<-Y#h1w2>$rDnQ_YJAKe7&Fp!Xqhpjwz1aonn)X1r_AHGAFJ16BiQ5^u zJ#&2OX+YDylubC5|6Ar3mQj%Oq!&^7 z6_x=*Z=9Fd)2)o|C9|!M@tIR;{#^RZTN{%!QZj#o>UEMSzN(%+&el@hZ7#MvC7dQ8 zwO)jQckyo*L)RS3tAr~PD>}OBG9_ZI3ZzuhtiJVyY$S6AVr*7I^3T+Z$Ha01DP^`rMIR_k#xY#nTW}w3M(HXe^G?Nnl+n)K zeZ@&{-alQqy)oR$wt72X>_&B~S6#uBzmQSI^MzXrCt+@4?!|6BV+WtgKTf(A6?CfE zjLsuE%YP?IjUh_$#H@c^b1Zr^kpsf;h06t-VfCF|^HnS}EA-a|D-=%fsIFgwZz{xg z=89j*LFfhlU7*zxDBa^c^|aH&WP4ZN@ldEpC4Wz}DX)jtQjc0w?XJtoZuQt9!>GXy zQ$14e==W#Qbjf&Be2>f;Us}m+LVu)&-09RB z`>dXR9WK}odhK(CGMPdxbdrrPL`37;nU$FJ{%#PEKEC=RaU+wez{uKuSA6`QlVy-i zdEHW){&uoZ`IFVWC_h4~eck-MbRUQ2@FW$5oUe!tv|n*KPdd3PkMK8{cSLuJxwAeNz2O zYpm?spZN2|dEpFknQE8 z(dOO6KfZ}eKQu;yEsC-{>szjkM($|1eew-6WW7Qg=r`>=Upt8a&XCx2~deX_amzq$>X;V{x=seEqFtxoElsc}>dp z+zX4>+cA0>mmgLE7%tdx`rO5Fsc<7&=Hbcfb)IPI!dsw9V835-h_$yg%c6%d)Ub!& znYGv2r}(`FX};)o^{p<9IDNjcrXaGS(1~j;%ms_5Vn*)6OoR!d?t<YHd0ZG#(V`|#}1uf?$S zo7zq}RD^|F{UZwf@Ib?5BrQxgq$^e_wdT9*T2e?|6a5w4EjTi z#ocg!rSg#b!-L#jn;Kl;boJ^b-3CC!1u?9Jk6H`oW-S%~x5LXjPYFJYf4g~eNdJ*n zYxpaJ+Dl;h7+6SeJ--UtMgm+AVV2|mCHE=Wte?7~Z zc3FCGanL&PFkQvO$eT$5VnZ-ZYFzQ&s}|#{KulXdkw-6Ck*O9vQ_i!|2e|e(io(eH!;*_-?mb)*ee1K ztk^s<=(b)SN{S9&=Fa7p4+ZwK2Y6rvF{iQySrs0@adCnad!osGps({%QP7kxk~K&C E3w8}Vd;kCd literal 0 HcmV?d00001 diff --git a/images/plotly-curves.png b/images/plotly-curves.png new file mode 100644 index 0000000000000000000000000000000000000000..bba6666d4c857c2aed13796de0eafa2487f2fc27 GIT binary patch literal 51262 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 u~$F6{UJfg5D=?h$y!9V<0T2 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 literal 0 HcmV?d00001 diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..e9662b8 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,7 @@ +{ + "include": [ + "custom_components/versatile_thermostat/**", + "homeassistant/**" + ], + "reportShadowedImports": false +} \ No newline at end of file diff --git a/tests/commons.py b/tests/commons.py index c7ef56f..6a30a56 100644 --- a/tests/commons.py +++ b/tests/commons.py @@ -185,6 +185,7 @@ class MockClimate(ClimateEntity): hvac_mode: HVACMode = HVACMode.OFF, hvac_action: HVACAction = HVACAction.OFF, fan_modes: list[str] = None, + hvac_modes: list[str] = None, ) -> None: """Initialize the thermostat.""" @@ -200,7 +201,11 @@ class MockClimate(ClimateEntity): HVACAction.OFF if hvac_mode == HVACMode.OFF else HVACAction.HEATING ) self._attr_hvac_mode = hvac_mode - self._attr_hvac_modes = [HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT] + self._attr_hvac_modes = ( + hvac_modes + if hvac_modes is not None + else [HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT] + ) self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_target_temperature = 20 self._attr_current_temperature = 15 diff --git a/tests/const.py b/tests/const.py index 3552a5b..bb19197 100644 --- a/tests/const.py +++ b/tests/const.py @@ -50,7 +50,8 @@ MOCK_TH_OVER_CLIMATE_MAIN_CONFIG = { CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", CONF_CYCLE_MIN: 5, CONF_DEVICE_POWER: 1, - CONF_USE_MAIN_CENTRAL_CONFIG: False + CONF_USE_MAIN_CENTRAL_CONFIG: False, + CONF_USE_CENTRAL_MODE: True # Keep default values which are False } diff --git a/tests/test_bugs.py b/tests/test_bugs.py index 376291c..4bc9715 100644 --- a/tests/test_bugs.py +++ b/tests/test_bugs.py @@ -358,7 +358,7 @@ async def test_bug_82( skip_turn_on_off_heater, skip_send_event, ): - """Test that when a underlying climate is not available the VTherm doesn't go into security mode""" + """Test that when a underlying climate is not available the VTherm doesn't go into safety mode""" tz = get_tz(hass) # pylint: disable=invalid-name now: datetime = datetime.now(tz=tz) @@ -427,7 +427,7 @@ async def test_bug_82( assert mock_find_climate.mock_calls[0] == call() mock_find_climate.assert_has_calls([call.find_underlying_entity()]) - # Force security mode + # Force safety mode assert entity._last_ext_temperature_measure is not None assert entity._last_temperature_measure is not None assert ( diff --git a/tests/test_central_mode.py b/tests/test_central_mode.py new file mode 100644 index 0000000..bcb8ec2 --- /dev/null +++ b/tests/test_central_mode.py @@ -0,0 +1,1040 @@ +# pylint: disable=wildcard-import, unused-wildcard-import, protected-access, unused-argument, line-too-long, too-many-lines + +""" Test the central_configuration """ +from unittest.mock import patch, call + +from datetime import datetime, timedelta + +from homeassistant.core import HomeAssistant + +from homeassistant.components.climate import HVACMode + +# from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.components.select import DOMAIN as SELECT_DOMAIN + +from pytest_homeassistant_custom_component.common import MockConfigEntry + +from custom_components.versatile_thermostat.thermostat_switch import ( + ThermostatOverSwitch, +) + +from .commons import * # pylint: disable=wildcard-import, unused-wildcard-import +from .const import * # pylint: disable=wildcard-import, unused-wildcard-import + + +# @pytest.mark.parametrize("expected_lingering_tasks", [True]) +# @pytest.mark.parametrize("expected_lingering_timers", [True]) +async def test_config_with_central_mode_true( + hass: HomeAssistant, skip_hass_states_is_state +): + """A config with central_mode True""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverSwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverswitchmockname" + ) + assert entity + assert entity.name == "TheOverSwitchMockName" + assert entity.is_over_switch + assert entity.is_controlled_by_central_mode + assert entity.last_central_mode is None # cause no central config exists + + +@pytest.mark.parametrize("expected_lingering_timers", [True]) +async def test_config_with_central_mode_false( + hass: HomeAssistant, skip_hass_states_is_state +): + """A config with central_mode False""" + + # Add a Climate VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverClimateMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverClimateMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: False, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_CLIMATE: "climate.mock_climate", + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverclimatemockname" + ) + assert entity + assert entity.name == "TheOverClimateMockName" + assert entity.is_over_climate + assert entity.is_controlled_by_central_mode is False + assert entity.last_central_mode is None # cause no central config exists + + +@pytest.mark.parametrize("expected_lingering_timers", [True]) +async def test_config_with_central_mode_none( + hass: HomeAssistant, skip_hass_states_is_state +): + """A config with central_mode is None""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverValveMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverValveMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_VALVE, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_VALVE: "number.mock_valve", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theovervalvemockname" + ) + assert entity + assert entity.name == "TheOverValveMockName" + assert entity.is_over_valve + assert entity.is_controlled_by_central_mode + assert entity.last_central_mode is None # cause no central config exists + + +async def test_switch_change_central_mode_true( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_switch config with central_mode True are + taken into account""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverSwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + # 1 initialize entity and find select entity + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverswitchmockname" + ) + assert entity + assert entity.is_controlled_by_central_mode + assert entity.last_central_mode is None + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity + await entity.async_set_hvac_mode(HVACMode.HEAT) + await entity.async_set_preset_mode(PRESET_BOOST) + + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_BOOST + + # 2 change central_mode to STOPPED + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_STOPPED) + + assert entity.last_central_mode is CENTRAL_MODE_STOPPED + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_BOOST + + # 3 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await entity.async_set_preset_mode(PRESET_COMFORT) + assert entity.preset_mode == PRESET_COMFORT + + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored as before the STOP and preset should be restored with the last choosen preset (COMFORT here) + assert entity.last_central_mode is CENTRAL_MODE_AUTO + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 4 change central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + # hvac_mode should be set to OFF because there is no COOL mode for this VTherm + assert entity.last_central_mode is CENTRAL_MODE_COOL_ONLY + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_COMFORT + + # 5 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to HEAT + assert entity.last_central_mode is CENTRAL_MODE_AUTO + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 6 change central_mode to HEAT_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) + + # hvac_mode should stay in HEAT mode + assert entity.last_central_mode is CENTRAL_MODE_HEAT_ONLY + assert entity.hvac_mode == HVACMode.HEAT + # No change + assert entity.preset_mode == PRESET_COMFORT + + # 7 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to HEAT + assert entity.last_central_mode is CENTRAL_MODE_AUTO + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 8 change central_mode to FROST_PROTECTION + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) + + # hvac_mode should stay in HEAT mode + assert entity.last_central_mode is CENTRAL_MODE_FROST_PROTECTION + assert entity.hvac_mode == HVACMode.HEAT + # change to Frost + assert entity.preset_mode == PRESET_FROST_PROTECTION + + # 9 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to HEAT + assert entity.last_central_mode is CENTRAL_MODE_AUTO + assert entity.hvac_mode == HVACMode.HEAT + # preset restored to COMFORT + assert entity.preset_mode == PRESET_COMFORT + + +async def test_switch_ac_change_central_mode_true( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_switch config with central_mode True are + taken into account""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverSwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + CONF_AC_MODE: True, + }, + ) + + # 1 initialize entity and find select entity + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverswitchmockname" + ) + assert entity + assert entity.is_controlled_by_central_mode + assert entity.ac_mode is True + assert entity.hvac_modes == [HVACMode.HEAT, HVACMode.COOL, HVACMode.OFF] + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity in cooling mode + await entity.async_set_hvac_mode(HVACMode.COOL) + await entity.async_set_preset_mode(PRESET_BOOST) + + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_BOOST + + # 2 change central_mode to STOPPED + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_STOPPED) + + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_BOOST + + # 3 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await entity.async_set_preset_mode(PRESET_COMFORT) + assert entity.preset_mode == PRESET_COMFORT + + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored as before the STOP and preset should be restored with the last choosen preset (COMFORT here) + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 4 change central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + # hvac_mode should be set to OFF because there is no COOL mode for this VTherm + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 5 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to HEAT + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 6 change central_mode to HEAT_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) + + # hvac_mode should stay in HEAT mode + assert entity.hvac_mode == HVACMode.HEAT + # No change + assert entity.preset_mode == PRESET_COMFORT + + # 7 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to COOL + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 8 change central_mode to FROST_PROTECTION + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) + + # hvac_mode should stay in COOL mode + assert entity.hvac_mode == HVACMode.HEAT + # change to Frost + assert entity.preset_mode == PRESET_FROST_PROTECTION + + # 9 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # hvac_mode should be restored to COOL + assert entity.hvac_mode == HVACMode.COOL + # preset restored to COMFORT + assert entity.preset_mode == PRESET_COMFORT + + +async def test_climate_ac_change_central_mode_false( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_climate config with central_mode False are + not taken into account""" + + fake_underlying_climate = MockClimate(hass, "mockUniqueId", "MockClimateName", {}) + + # Add a Climate VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverClimateMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverClimateMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: False, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_CLIMATE: "climate.mock_climate", + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + with patch("homeassistant.core.ServiceRegistry.async_call"), patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate", + return_value=fake_underlying_climate, + ): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverclimatemockname" + ) + assert entity + assert entity.name == "TheOverClimateMockName" + assert entity.is_over_climate + assert entity.is_controlled_by_central_mode is False + assert entity.hvac_modes == [HVACMode.OFF, HVACMode.COOL, HVACMode.HEAT] + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity in Heating mode + await entity.async_set_hvac_mode(HVACMode.HEAT) + await entity.async_set_preset_mode(PRESET_BOOST) + + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_BOOST + + # 2 change central_mode to STOPPED + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_STOPPED) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_BOOST + + # 3 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await entity.async_set_preset_mode(PRESET_COMFORT) + assert entity.preset_mode == PRESET_COMFORT + + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 4 change central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 5 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 6 change central_mode to HEAT_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 7 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 8 change central_mode to FROST_PROTECTION + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + # 9 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_COMFORT + + +async def test_climate_ac_only_change_central_mode_true( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_climate with AC only config with central_mode True are + taken into account + Test also switching from central_mode without coming to AUTO each time""" + + fake_underlying_climate = MockClimate( + hass, + "mockUniqueId", + "MockClimateName", + entry_infos={}, + hvac_modes=[HVACMode.OFF, HVACMode.COOL], + ) + + # Add a Climate VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverClimateMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverClimateMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_CLIMATE, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: False, + CONF_USE_MOTION_FEATURE: False, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_CLIMATE: "climate.mock_climate", + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + }, + ) + + with patch("homeassistant.core.ServiceRegistry.async_call"), patch( + "custom_components.versatile_thermostat.underlyings.UnderlyingClimate.find_underlying_climate", + return_value=fake_underlying_climate, + ): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverclimatemockname" + ) + assert entity + assert entity.name == "TheOverClimateMockName" + assert entity.is_over_climate + assert entity.is_controlled_by_central_mode is True + assert entity.hvac_modes == [HVACMode.OFF, HVACMode.COOL] + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity in Cooling mode + await entity.async_set_hvac_mode(HVACMode.COOL) + await entity.async_set_preset_mode(PRESET_ECO) + + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_ECO + + # 2 change central_mode to STOPPED + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_STOPPED) + + # No change + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ECO + + # 3 change central_mode to HEAT ONLY after switching to COMFORT preset + with patch("homeassistant.core.ServiceRegistry.async_call"): + await entity.async_set_preset_mode(PRESET_COMFORT) + assert entity.preset_mode == PRESET_COMFORT + + await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) + + # Stay in OFF because HEAT is not permitted + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_COMFORT + + # 4 change central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + # switch back to COOL restoring the preset + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 5 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 6 change central_mode to FROST_PROTECTION + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) + + # No change + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_COMFORT + + # 7 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + # 8 change central_mode to FROST_PROTECTION + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_FROST_PROTECTION) + + # No change + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_COMFORT + + # 9 change back central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + # No change + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_COMFORT + + await entity.async_set_preset_mode(PRESET_ECO) + # 10 change back central_mode to HEAT_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_HEAT_ONLY) + + # Shutdown cause no HEAT + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ECO + + # 11 change back central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + # No change + assert entity.hvac_mode == HVACMode.COOL + assert entity.preset_mode == PRESET_ECO + + +async def test_switch_change_central_mode_true_with_window( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_switch config with central_mode True are + taken into account""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverSwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: True, + CONF_USE_MOTION_FEATURE: True, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + CONF_WINDOW_SENSOR: "binary_sensor.window_sensor", + CONF_WINDOW_DELAY: 0, # To be not obliged to wait + CONF_MOTION_SENSOR: "input_boolean.motion_sensor", + CONF_MOTION_DELAY: 10, + CONF_MOTION_OFF_DELAY: 30, + CONF_MOTION_PRESET: PRESET_BOOST, + CONF_NO_MOTION_PRESET: PRESET_ECO, + }, + ) + + tz = get_tz(hass) # pylint: disable=invalid-name + event_timestamp = datetime.now(tz) + + # 1 initialize entity and find select entity + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverswitchmockname" + ) + assert entity + assert entity.is_controlled_by_central_mode + assert entity.last_central_mode is None + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity + await entity.async_set_hvac_mode(HVACMode.HEAT) + await entity.async_set_preset_mode(PRESET_ACTIVITY) + + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_OFF + + # 2 Open the window + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "homeassistant.helpers.condition.state", return_value=True + ): + event_timestamp = event_timestamp + timedelta(minutes=1) + try_function = await send_window_change_event( + entity, True, False, event_timestamp + ) + + await try_function(None) + + assert mock_send_event.call_count == 1 + mock_send_event.assert_has_calls( + [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.OFF})] + ) + + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_ON + + # 3 Change central_mode to STOPPED + with patch("homeassistant.core.ServiceRegistry.async_call"): + event_timestamp = event_timestamp + timedelta(minutes=1) + entity._set_now(event_timestamp) + + await select_entity.async_select_option(CENTRAL_MODE_STOPPED) + + assert entity.last_central_mode is CENTRAL_MODE_STOPPED + # No change + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + + # 4 Close the window + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "homeassistant.helpers.condition.state", return_value=True + ): + event_timestamp = event_timestamp + timedelta(minutes=1) + try_function = await send_window_change_event( + entity, False, True, event_timestamp + ) + + await try_function(None) + + # No hvac_mode change cause the central mode is STOPPED + assert mock_send_event.call_count == 0 + + # We should stay off because central is STOPPED + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_OFF + + # 5 Back to Auto + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event: + event_timestamp = event_timestamp + timedelta(minutes=1) + + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + assert mock_send_event.call_count == 1 + mock_send_event.assert_has_calls( + [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.HEAT})] + ) + + # We should switch back to HEAT + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_OFF + + +async def test_switch_change_central_mode_true_with_cool_only_and_window( + hass: HomeAssistant, skip_hass_states_is_state, init_central_config +): + """test that changes with over_switch config with central_mode True are + taken into account""" + + # Add a Switch VTherm + entry = MockConfigEntry( + domain=DOMAIN, + title="TheOverSwitchMockName", + unique_id="uniqueId", + data={ + CONF_NAME: "TheOverSwitchMockName", + CONF_THERMOSTAT_TYPE: CONF_THERMOSTAT_SWITCH, + CONF_TEMP_SENSOR: "sensor.mock_temp_sensor", + CONF_EXTERNAL_TEMP_SENSOR: "sensor.mock_ext_temp_sensor", + CONF_USE_CENTRAL_MODE: True, + CONF_CYCLE_MIN: 5, + CONF_TEMP_MIN: 8, + CONF_TEMP_MAX: 18, + "frost_temp": 10, + "eco_temp": 17, + "comfort_temp": 18, + "boost_temp": 21, + CONF_USE_WINDOW_FEATURE: True, + CONF_USE_MOTION_FEATURE: True, + CONF_USE_POWER_FEATURE: False, + CONF_USE_PRESENCE_FEATURE: False, + CONF_HEATER: "switch.mock_switch", + CONF_PROP_FUNCTION: PROPORTIONAL_FUNCTION_TPI, + CONF_TPI_COEF_INT: 0.3, + CONF_TPI_COEF_EXT: 0.01, + CONF_MINIMAL_ACTIVATION_DELAY: 30, + CONF_SECURITY_DELAY_MIN: 5, + CONF_SECURITY_MIN_ON_PERCENT: 0.3, + CONF_SECURITY_DEFAULT_ON_PERCENT: 0.1, + CONF_WINDOW_SENSOR: "binary_sensor.window_sensor", + CONF_WINDOW_DELAY: 0, # To be not obliged to wait + CONF_MOTION_SENSOR: "input_boolean.motion_sensor", + CONF_MOTION_DELAY: 10, + CONF_MOTION_OFF_DELAY: 30, + CONF_MOTION_PRESET: PRESET_BOOST, + CONF_NO_MOTION_PRESET: PRESET_ECO, + }, + ) + + tz = get_tz(hass) # pylint: disable=invalid-name + event_timestamp = datetime.now(tz) + + # 1 initialize entity and find select entity + with patch("homeassistant.core.ServiceRegistry.async_call"): + entity: ThermostatOverSwitch = await create_thermostat( + hass, entry, "climate.theoverswitchmockname" + ) + assert entity + assert entity.is_controlled_by_central_mode + assert entity.last_central_mode is None + + # Find the select entity + select_entity = search_entity(hass, "select.central_mode", SELECT_DOMAIN) + + assert select_entity + assert select_entity.current_option == CENTRAL_MODE_AUTO + assert select_entity.options == CENTRAL_MODES + + # start entity + await entity.async_set_hvac_mode(HVACMode.HEAT) + await entity.async_set_preset_mode(PRESET_ACTIVITY) + + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_OFF + + # 2 Change central_mode to COOL_ONLY + with patch("homeassistant.core.ServiceRegistry.async_call"): + event_timestamp = event_timestamp + timedelta(minutes=1) + entity._set_now(event_timestamp) + + await select_entity.async_select_option(CENTRAL_MODE_COOL_ONLY) + + assert entity.last_central_mode is CENTRAL_MODE_COOL_ONLY + await entity.async_set_hvac_mode(HVACMode.OFF) + await entity.async_set_preset_mode(PRESET_ACTIVITY) + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + + # 3 Open the window + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "homeassistant.helpers.condition.state", return_value=True + ): + event_timestamp = event_timestamp + timedelta(minutes=1) + try_function = await send_window_change_event( + entity, True, False, event_timestamp + ) + + await try_function(None) + + assert mock_send_event.call_count == 1 + mock_send_event.assert_has_calls( + [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.OFF})] + ) + + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_ON + + # 4 Change central_mode to AUTO + with patch("homeassistant.core.ServiceRegistry.async_call"): + event_timestamp = event_timestamp + timedelta(minutes=1) + entity._set_now(event_timestamp) + + await select_entity.async_select_option(CENTRAL_MODE_AUTO) + + assert entity.last_central_mode is CENTRAL_MODE_AUTO + # No change + assert entity.hvac_mode == HVACMode.OFF + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + + # 5 Close the window + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "homeassistant.helpers.condition.state", return_value=True + ): + event_timestamp = event_timestamp + timedelta(minutes=1) + try_function = await send_window_change_event( + entity, False, True, event_timestamp + ) + + await try_function(None) + + # hvac_mode change to HEAT + assert mock_send_event.call_count == 1 + mock_send_event.assert_has_calls( + [call.send_event(EventType.HVAC_MODE_EVENT, {"hvac_mode": HVACMode.HEAT})] + ) + + # We should stay off because central is STOPPED + assert entity.hvac_mode == HVACMode.HEAT + assert entity.preset_mode == PRESET_ACTIVITY + assert entity._saved_hvac_mode == HVACMode.HEAT + assert entity._saved_preset_mode == PRESET_ACTIVITY + assert entity.window_state is STATE_OFF diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py index ff37153..d04f613 100644 --- a/tests/test_config_flow.py +++ b/tests/test_config_flow.py @@ -363,6 +363,7 @@ async def test_user_config_flow_window_auto_ok( CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_WINDOW_DELAY: 30, # the default value is added + CONF_USE_CENTRAL_MODE: True, # True is the defaulf value } | MOCK_TH_OVER_SWITCH_TYPE_CONFIG | MOCK_TH_OVER_SWITCH_TPI_CONFIG | MOCK_WINDOW_AUTO_CONFIG | { CONF_USE_MAIN_CENTRAL_CONFIG: True, CONF_USE_TPI_CENTRAL_CONFIG: False, @@ -510,6 +511,7 @@ async def test_user_config_flow_over_4_switches( CONF_USE_POWER_FEATURE: False, CONF_USE_PRESENCE_FEATURE: False, CONF_USE_MAIN_CENTRAL_CONFIG: True, + CONF_USE_CENTRAL_MODE: False, } TYPE_CONFIG = { # pylint: disable=wildcard-import, invalid-name diff --git a/tests/test_security.py b/tests/test_security.py index 9165198..1d37b19 100644 --- a/tests/test_security.py +++ b/tests/test_security.py @@ -288,7 +288,7 @@ async def test_security_feature_back_on_percent( assert entity.security_state is False assert mock_send_event.call_count == 0 - # 3. Set security mode with a preset change + # 3. Set safety mode with a preset change with patch( "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" ) as mock_send_event, patch( @@ -400,7 +400,7 @@ async def test_security_over_climate( skip_turn_on_off_heater, skip_send_event, ): - """Test that when a underlying climate is not available the VTherm doesn't go into security mode""" + """Test that when a underlying climate is not available the VTherm doesn't go into safety mode""" tz = get_tz(hass) # pylint: disable=invalid-name now: datetime = datetime.now(tz=tz) @@ -471,7 +471,7 @@ async def test_security_over_climate( assert mock_find_climate.mock_calls[0] == call() mock_find_climate.assert_has_calls([call.find_underlying_entity()]) - # Force security mode + # Force safety mode assert entity._last_ext_temperature_measure is not None assert entity._last_temperature_measure is not None assert ( @@ -505,7 +505,7 @@ async def test_security_over_climate( event_timestamp = now - timedelta(minutes=6) await send_temperature_change_event(entity, 15, event_timestamp) - # Should stay False because a climate is never in security mode + # Should stay False because a climate is never in safety mode assert entity.security_state is False assert entity.preset_mode == "none" assert entity._saved_preset_mode == "none" diff --git a/tests/test_switch_ac.py b/tests/test_switch_ac.py index 3d4bb12..bd98257 100644 --- a/tests/test_switch_ac.py +++ b/tests/test_switch_ac.py @@ -129,7 +129,7 @@ async def test_over_switch_ac_full_start( assert entity.hvac_mode is HVACMode.OFF assert entity.hvac_action is HVACAction.OFF - assert entity.target_temperature == 16 # eco_ac_away + assert entity.target_temperature == 27 # eco_ac_away (no change) # Close a window with patch("homeassistant.helpers.condition.state", return_value=True): diff --git a/tests/test_valve.py b/tests/test_valve.py index 2807e0e..47593fc 100644 --- a/tests/test_valve.py +++ b/tests/test_valve.py @@ -283,6 +283,18 @@ async def test_over_valve_full_start( assert entity.is_device_active is True assert entity.hvac_action == HVACAction.HEATING + # Test window open/close (with a normal min/max so that is_device_active is False when open_percent is 0) + expected_state = State( + entity_id="number.mock_valve", state="0", attributes={"min": 0, "max": 99} + ) + + with patch( + "custom_components.versatile_thermostat.base_thermostat.BaseThermostat.send_event" + ) as mock_send_event, patch( + "homeassistant.core.ServiceRegistry.async_call" + ) as mock_service_call, patch( + "homeassistant.core.StateMachine.get", return_value=expected_state + ): # Open a window with patch("homeassistant.helpers.condition.state", return_value=True): event_timestamp = now - timedelta(minutes=1) diff --git a/tests/test_window.py b/tests/test_window.py index 4bb6477..3fc67e0 100644 --- a/tests/test_window.py +++ b/tests/test_window.py @@ -1,4 +1,4 @@ -# pylint: disable=unused-argument, line-too-long, protected-access +# pylint: disable=unused-argument, line-too-long, protected-access, too-many-lines """ Test the Window management """ import asyncio import logging