Compare commits

...

23 Commits

Author SHA1 Message Date
Jean-Marc Collin
7dbdcf0ee4 Fix security modes corner cases 2023-02-11 12:38:14 +01:00
Jean-Marc Collin
ade1ee4365 Missing translations for preset mode Power and Security #46
Set preset internal #45
Notify (send event messages) when something important happens #43
Enhancing Security mode #42
Rename None preset to Manual #3
2023-02-11 10:34:45 +01:00
adi90x
7b57f7da28 Minimal security threeshold (#44)
* Add SECURITY_MIN_ON_PERCENT
2023-02-10 19:13:57 +01:00
Jean-Marc Collin
9fe307ba1e FIX Issue #38 Support Fahrenheit 2023-02-09 00:05:51 +01:00
Jean-Marc Collin
717c893c75 Reset security mode when preset or hvac_mode change #41 2023-02-07 07:47:07 +01:00
Jean-Marc Collin
5b8fb81053 Documentation update for release 2.0.0 2023-02-03 23:17:09 +01:00
Jean-Marc Collin
8b77d9d75f Some switch are not visible in the list of radiators #40 2023-02-03 22:30:33 +01:00
Jean-Marc Collin
3d977c4981 Failure to initialize #39 2023-02-01 10:43:21 +01:00
Jean-Marc Collin
115df52f67 Issue#36 - Error at initialisation
Issue#32 - Error with Fan Modes on thermostat over climate type
2023-01-31 22:19:43 +01:00
Jean-Marc Collin
3371197594 Fix issue#32 Error with Fan Modes on thermostat over climate type 2023-01-31 09:35:27 +01:00
Jean-Marc Collin
7e63c9aa79 Heater can restart after HVAC_MODE_OFF 2023-01-30 07:09:43 +01:00
Jean-Marc Collin
100cfaeac9 Add binary sensors for window sensors 2023-01-30 06:49:39 +01:00
Jean-Marc Collin
77631e94d9 FIX feature selection 2023-01-29 23:21:51 +01:00
Jean-Marc Collin
49c85eeb2b Try to fix const import 2023-01-29 22:01:05 +01:00
Jean-Marc Collin
bb2c1d328b FIX selectors 2023-01-29 21:39:08 +01:00
Jean-Marc Collin
b607fb1075 2.0.0-beta1
Issue #30 - security mode
Issue #26 - upodate entity on config change
Issue #21 - check box to select feature
Issue #16 - Suggest/select entity in a list on the configuration screens
Issue #5  - Thermostat over climate type
2023-01-29 19:53:49 +01:00
Jean-Marc Collin
4786949aeb Add availability to choose entity in Config Flow 2023-01-25 23:08:20 +01:00
Jean-Marc Collin
162b2d1a1b Typo README 2023-01-21 19:25:30 +01:00
Jean-Marc Collin
c762c91eb9 Documentation update 2023-01-21 19:23:53 +01:00
Jean-Marc Collin
62425bb91f FIX don't trigger cycle calculation at each power event 2023-01-21 17:34:28 +01:00
Jean-Marc Collin
952d6d5e97 Issue #13 - After reconfiguration of the thermostat we need to reload the integration
Issue #22 - Change preset to "security" when the Thermostat goes in security mode
Issue #30 - When shutting of a thermostat after it has been in security mode, the thermostat can start up alone
2023-01-21 13:38:37 +01:00
Jean-Marc Collin
638e007c21 Add min_temp and max_temp in configuration #17
Mise en sécurité du thermostat si pas de changement de température #18
Add a configurable minimal delay of activation #19
2023-01-18 23:40:55 +01:00
Jean-Marc Collin
c520d7fad5 FIX services.yaml error 2023-01-15 22:40:00 +01:00
26 changed files with 2720 additions and 695 deletions

6
.bashrc Normal file
View File

@@ -0,0 +1,6 @@
echo "Sourcing .bashrc"
alias ll='ls -l'
export HA='/home/vscode/core'
cd $HA
source venv/bin/activate

View File

@@ -7,6 +7,9 @@ logger:
# If you need to debug uncommment the line below (doc: https://www.home-assistant.io/integrations/debugpy/)
debugpy:
start: true
wait: false
port: 5678
input_number:
fake_temperature_sensor1:
@@ -15,25 +18,28 @@ input_number:
max: 35
step: .1
icon: mdi:thermometer
unit_of_measurement: °C
fake_external_temperature_sensor1:
name: Ext Temperature
min: -10
max: 35
step: .1
icon: mdi:home-thermometer
unit_of_measurement: °C
fake_current_power:
name: Current power
min: 0
max: 1000
step: 10
icon: mdi:flash
unit_of_measurement: kW
fake_current_power_max:
name: Current power max threshold
min: 0
max: 1000
step: 10
icon: mdi:flash
unit_of_measurement: kW
input_boolean:
# input_boolean to simulate the windows entity. Only for development environment.
@@ -58,3 +64,77 @@ input_boolean:
fake_presence_sensor1:
name: Presence Sensor 1
icon: mdi:home
climate:
- platform: generic_thermostat
name: Underlying thermostat1
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat2
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat3
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat4
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat5
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat6
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat7
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat8
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
- platform: generic_thermostat
name: Underlying thermostat9
heater: input_boolean.fake_heater_switch3
target_sensor: input_number.fake_temperature_sensor1
recorder:
include:
domains:
- input_boolean
- input_number
- switch
- climate
- sensor
template:
- binary_sensor:
- name: maison_occupee
unique_id: maison_occupee
state: "{{is_state('person.jmc', 'home') }}"
device_class: occupancy
switch:
- platform: template
switches:
pilote_sdb_rdc:
friendly_name: "Pilote chauffage SDB RDC"
value_template: "{{ is_state_attr('switch_seche_serviettes_sdb_rdc', 'sensor_state', 'on') }}"
turn_on:
service: select.select_option
data:
option: comfort
target:
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
turn_off:
service: select.select_option
data:
option: comfort-2
target:
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode

View File

@@ -1,18 +1,25 @@
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
// "image": "ghcr.io/ludeeus/devcontainer/integration:latest",
{
"image": "ghcr.io/ludeeus/devcontainer/integration:latest",
"image": "mcr.microsoft.com/vscode/devcontainers/python:0-3.10",
"name": "Versatile Thermostat integration",
"context": "..",
"appPort": [
"9123:8123"
],
"postCreateCommand": "container install",
// "postCreateCommand": "container install",
"postCreateCommand": "./container install",
"extensions": [
"ms-python.python",
"github.vscode-pull-request-github",
"ryanluker.vscode-coverage-gutters",
"ms-python.vscode-pylance"
],
"mounts": [
"source=/Users/jmcollin/SugarSync/Projets/home-assistant/core,target=/home/vscode/core,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/.devcontainer/configuration.yaml,target=/home/vscode/core/config/configuration.yaml,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/custom_components,target=/home/vscode/core/config/custom_components,type=bind,consistency=cached"
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 4,
@@ -25,7 +32,7 @@
"terminal.integrated.defaultProfile.linux": "Bash Profile",
// "terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/bin/python3",
"python.analysis.autoSearchPaths": false,
"python.analysis.autoSearchPaths": true,
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",

8
.vscode/launch.json vendored
View File

@@ -11,9 +11,13 @@
"host": "localhost",
"justMyCode": false,
"pathMappings": [
// {
// "localRoot": "${workspaceFolder}",
// "remoteRoot": "."
//},
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
"localRoot": "${workspaceFolder}/../core",
"remoteRoot": "/home/vscode/core"
}
]
},

View File

@@ -4,5 +4,9 @@
"python.pythonPath": "/usr/local/bin/python",
"files.associations": {
"*.yaml": "home-assistant"
}
},
"python.analysis.extraPaths": [
"/home/vscode/core",
"/workspaces/versatile_thermostat"
]
}

26
.vscode/tasks.json vendored
View File

@@ -4,25 +4,43 @@
{
"label": "Run Home Assistant on port 9123",
"type": "shell",
"command": "container start",
"command": "./container start",
"problemMatcher": []
},
{
"label": "Restart Home Assistant on port 9123",
"type": "shell",
"command": "./container restart",
"problemMatcher": []
},
{
"label": "Home Assistant translations update",
"type": "shell",
"command": "./container translations",
"problemMatcher": []
},
{
"label": "Home Assistant hassfest",
"type": "shell",
"command": "./container hassfest",
"problemMatcher": []
},
{
"label": "Run Home Assistant configuration against /config",
"type": "shell",
"command": "container check-config",
"command": "./container check-config",
"problemMatcher": []
},
{
"label": "Upgrade Home Assistant to latest dev",
"type": "shell",
"command": "container install",
"command": "./container install",
"problemMatcher": []
},
{
"label": "Install a specific version of Home Assistant",
"type": "shell",
"command": "container set-version",
"command": "./container set-version",
"problemMatcher": []
}
]

527
README-fr.md Normal file
View File

@@ -0,0 +1,527 @@
[![GitHub Release][releases-shield]][releases]
[![GitHub Activity][commits-shield]][commits]
[![License][license-shield]](LICENSE)
[![hacs][hacs_badge]][hacs]
![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/icon.png?raw=true)
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true?raw=true) Cette intégration de thermostat vise à simplifier considérablement vos automatisations autour de la gestion du chauffage. Parce que tous les événements autour du chauffage classiques sont gérés nativement par le thermostat (personne à la maison ?, activité détectée dans une pièce ?, fenêtre ouverte ?, délestage de courant ?), vous n'avez pas à vous encombrer de scripts et d'automatismes compliqués pour gérer vos climats. ;-).
- [Quand l'utiliser et ne pas l'utiliser](#quand-lutiliser-et-ne-pas-lutiliser)
- [Pourquoi une nouvelle implémentation du thermostat ?](#pourquoi-une-nouvelle-implémentation-du-thermostat-)
- [Comment installer cet incroyable Thermostat Versatile ?](#comment-installer-cet-incroyable-thermostat-versatile-)
- [HACS installation (recommendé)](#hacs-installation-recommendé)
- [Installation manuelle](#installation-manuelle)
- [Configuration](#configuration)
- [Choix des attributs de base](#choix-des-attributs-de-base)
- [Sélectionnez l'entité pilotée](#sélectionnez-lentité-pilotée)
- [Configurez les coefficients de l'algorithme TPI](#configurez-les-coefficients-de-lalgorithme-tpi)
- [Configurer la température préréglée](#configurer-la-température-préréglée)
- [Configurer les portes/fenêtres en allumant/éteignant les thermostats](#configurer-les-portesfenêtres-en-allumantéteignant-les-thermostats)
- [Configurer le mode d'activité ou la détection de mouvement](#configurer-le-mode-dactivité-ou-la-détection-de-mouvement)
- [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)
- [Exemples de réglage](#exemples-de-réglage)
- [Chauffage électrique](#chauffage-électrique)
- [Chauffage central (chauffage gaz ou fuel)](#chauffage-central-chauffage-gaz-ou-fuel)
- [Le capteur de température sera alimenté par batterie](#le-capteur-de-température-sera-alimenté-par-batterie)
- [Capteur de température réactif](#capteur-de-température-réactif)
- [Ma configuration prédéfinie](#ma-configuration-prédéfinie)
- [Algorithme](#algorithme)
- [Algorithme TPI](#algorithme-tpi)
- [Services](#services)
- [Forcer la présence/occupation](#forcer-la-présenceoccupation)
- [Modifier la température des préréglages](#modifier-la-température-des-préréglages)
- [Attributs personnalisés](#attributs-personnalisés)
- [Quelques résultats](#quelques-résultats)
- [Encore mieux](#encore-mieux)
- [Encore mieux avec le composant Scheduler !](#encore-mieux-avec-le-composant-scheduler-)
- [Encore bien mieux avec la custom:simple-thermostat front integration](#encore-bien-mieux-avec-la-customsimple-thermostat-front-integration)
- [Toujours mieux avec Apex-chart pour régler votre thermostat](#toujours-mieux-avec-apex-chart-pour-régler-votre-thermostat)
- [Les contributions sont les bienvenues !](#les-contributions-sont-les-bienvenues)
_Composant développé à l'aide de l'incroyable modèle de développement [[blueprint](https://github.com/custom-components/integration_blueprint)]._
Ce composant personnalisé pour Home Assistant est une mise à niveau et est une réécriture complète du composant "Awesome thermostat" (voir [Github](https://github.com/dadge/awesome_thermostat)) avec l'ajout de fonctionnalités.
# Quand l'utiliser et ne pas l'utiliser
Ce thermostat peut piloter 2 types d'équipement:
1. un radiateur qui ne fonctionne qu'en mode marche/arrêt (nommé ```thermostat_over_switch```). La configuration minimale nécessaire pour utiliser ce type thermostat est :
a. un équipement comme un radiateur (un ```switch``` ou équivalent),
b. une sonde de température pour la pièce (ou un input_number),
c. un capteur de température externe (pensez à l'intégration météo si vous n'en avez pas)
2. un autre thermostat qui a ses propres modes de fonctionnement (nommé ```thermostat_over_climate```). Pour ce type de thermostat la configuration minimale nécessite :
a. un équipement comme une climatisation qui est pilotée par sa propre entity de type ```climate```,
b. une sonde de température pour la pièce (ou un input_number),
c. un capteur de température externe (pensez à l'intégration météo si vous n'en avez pas)
Le type ```thermostat_over_climate``` permet d'ajouter à votre équipement existant toutes les fonctionnalités fournies par VersatileThermostat. L'entité climate VersatileThermostat pilotera votre entité climate, en la coupant si les fenêtres sont ouvertes, la passant en mode Eco si personne n'est présent, etc. Cf. [ici](#pourquoi-une-nouvelle-implémentation-du-thermostat). Pour ce type de thermostat, les cycles éventuels de chauffe sont pilotés par l'entité climate sous-jacente et pas par le Versatile Thermostat lui-même.
Parce que cette intégration vise à commander le radiateur en tenant compte du préréglage configuré (preset) et de la température ambiante, ces informations sont obligatoires.
# Pourquoi une nouvelle implémentation du thermostat ?
Pour mon usage personnel, j'avais besoin d'ajouter quelques fonctionnalités et aussi de mettre à jour le comportement implémenté dans le composant précédent "Awesome thermostat".
Ce composant nommé __Versatile thermostat__ gère les cas d'utilisation suivants :
- Configuration via l'interface graphique d'intégration standard (à l'aide du flux Config Entry),
- Utilisations complètes du **mode préréglages**,
- Désactiver le mode préréglé lorsque la température est **définie manuellement** sur un thermostat,
- Éteindre/allumer un thermostat lorsqu'une **porte ou des fenêtres sont ouvertes/fermées** après un certain délai,
- Changer de preset lorsqu'une **activité est détectée** ou non dans une pièce pendant un temps défini,
- Utiliser un algorithme **TPI (Time Proportional Interval)** grâce à l'algorithme [[Argonaute](https://forum.hacf.fr/u/argonaute/summary)] ,
- Ajoutez 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é.
- Ajouter 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.
- Ajoutez 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.
# Comment installer cet incroyable Thermostat Versatile ?
## HACS installation (recommendé)
1. Installez [HACS](https://hacs.xyz/). De cette façon, vous obtenez automatiquement les mises à jour.
2. Ajoutez ce repository Github en tant que repository personnalisé dans les paramètres HACS.
3. recherchez et installez "Versatile Thermostat" dans HACS et cliquez sur "installer".
4. Redémarrez Home Assistant.
5. Ensuite, vous pouvez ajouter une intégration de Versatile Thermostat dans la page d'intégration. Vous ajoutez autant de thermostats dont vous avez besoin (généralement un par radiateur qui doit être géré ou par pompe dans le cas d'un chauffage centralisé)
## Installation manuelle
1. À l'aide de l'outil de votre choix, ouvrez le répertoire (dossier) de votre configuration HA (où vous trouverez `configuration.yaml`).
2. Si vous n'avez pas de répertoire (dossier) `custom_components`, vous devez le créer.
3. Dans le répertoire (dossier) `custom_components`, créez un nouveau dossier appelé `versatile_thermostat`.
4. Téléchargez _tous_ les fichiers du répertoire `custom_components/versatile_thermostat/` (dossier) dans ce référentiel.
5. Placez les fichiers que vous avez téléchargés dans le nouveau répertoire (dossier) que vous avez créé.
6. Redémarrez l'assistant domestique
7. Configurer la nouvelle intégration du Versatile Thermostat
# Configuration
Note: aucune configuration dans configuration.yaml n'est nécessaire car toute la configuration est effectuée via l'interface graphique standard lors de l'ajout de l'intégration.
Cliquez sur le bouton Ajouter une intégration dans la page d'intégration
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/add-an-integration.png?raw=true)
La configuration peut être modifiée via la même interface. Sélectionnez simplement le thermostat à modifier, appuyez sur "Configurer" et vous pourrez modifier certains paramètres ou la configuration.
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)
Donnez les principaux attributs obligatoires :
1. un nom (sera le nom de l'intégration et aussi le nom de l'entité climate)
2. le type de thermostat ```thermostat_over_switch``` pour piloter un radiateur commandé par un switch ou ```thermostat_over_climate``` pour piloter un autre thermostat. Cf. [ci-dessus](#pourquoi-une-nouvelle-implémentation-du-thermostat)
4. un identifiant d'entité de capteur de température qui donne la température de la pièce dans laquelle le radiateur est installé,
5. une entité capteur de température donnant la température extérieure. Si vous n'avez pas de capteur externe, vous pouvez utiliser l'intégration météo locale
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),
7. les températures minimales et maximales du thermostat,
8. 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 le type ```thermostat_over_swutch```, 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**,
2. si le cycle est trop court, le radiateur ne pourra jamais atteindre la température cible en effet pour le radiateur à accumulation et il sera sollicité inutilement
## Sélectionnez l'entité pilotée
En fonction de votre choix sur le type de thermostat, vous devrez choisir une entité de type switch ou une entité de type climate. Seules les entités compatibles sont présentées.
Pour un thermostat de type ```thermostat_over_switch```:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-linked-entity.png?raw=true)
L'algorithme à utiliser est aujourd'hui limité à TPI est disponible. Voir [algorithme](#algorithme)
Pour un thermostat de type ```thermostat_over_climate```:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-linked-entity2.png?raw=true)
## Configurez les coefficients de l'algorithme TPI
Si vous avez choisi un thermostat de type ```thermostat_over_switch``` vous arriverez sur cette page :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-tpi.png?raw=true)
Vous devez donner :
1. le coefficient coef_int de l'algorithme TPI,
2. le coefficient coef_ext de l'algorithme TPI
Pour plus d'informations sur l'algorithme TPI et son réglage, veuillez vous référer à [algorithm](#algorithm).
## Configurer la température préréglée
Cliquez sur 'Valider' sur la page précédente et vous y arriverez :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-presets.png?raw=true)
Le mode préréglé (preset) vous permet de préconfigurer la température ciblée. Utilisé en conjonction avec Scheduler (voir [scheduler](#even-better-with-scheduler-component) vous aurez un moyen puissant et simple d'optimiser la température par rapport à la consommation électrique de votre maison. Les préréglages gérés sont les suivants :
- **Eco** : l'appareil est en mode d'économie d'énergie
- **Confort** : l'appareil est en mode confort
- **Boost** : l'appareil tourne toutes les vannes à fond
**Aucun** est toujours ajouté dans la liste des modes, car c'est un moyen de ne pas utiliser les preset mais une **température manuelle** à la place.
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. En modifiant manuellement la température cible, réglez le préréglage sur Aucun (pas de préréglage). De cette façon, vous pouvez toujours définir une température cible même si aucun préréglage n'est disponible.
2. Le préréglage standard ``Away`` est un préréglage caché qui n'est pas directement sélectionnable. Versatile Thermostat utilise la gestion de présence ou la gestion de mouvement pour régler automatiquement et dynamiquement la température cible en fonction d'une présence dans le logement ou d'une activité dans la pièce. Voir [gestion de la présence](#configure-the-presence-management).
3. Si vous utilisez la gestion du délestage, vous verrez un préréglage caché nommé ``power``. Le préréglage de l'élément chauffant est réglé sur « puissance » lorsque des conditions de surpuissance sont rencontrées et que le délestage est actif pour cet élément chauffant. Voir [gestion de l'alimentation](#configure-the-power-management).
4. si vous utilisez la configuration avancée, vous verrez le préréglage défini sur ``sécurité`` si la température n'a pas pu être récupérée après un certain délai
5. Si vous ne souhaitez pas utiliser le préréglage, indiquez 0 comme température. Le préréglage sera alors ignoré et ne s'affichera pas dans le composant front
## Configurer les portes/fenêtres en allumant/éteignant les thermostats
Si vous avez choisi la fonctionnalité ```Avec détection des ouvertures```, cliquez sur 'Valider' sur la page précédente et vous y arriverez :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-window.png?raw=true)
Donnez les attributs suivants :
1. un identifiant d'entité d'un **capteur de fenêtre/porte**. Cela devrait être un binary_sensor ou un input_boolean. L'état de l'entité doit être 'on' lorsque la fenêtre est ouverte ou 'off' lorsqu'elle est fermée
2. un **délai en secondes** avant tout changement. Cela permet d'ouvrir rapidement une fenêtre sans arrêter le chauffage.
Et c'est tout ! votre thermostat s'éteindra lorsque les fenêtres seront ouvertes et se rallumera lorsqu'il sera fermé après le délai.
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. Si vous souhaitez utiliser **plusieurs capteurs de porte/fenêtre** pour automatiser votre thermostat, créez simplement un groupe avec le comportement habituel (https://www.home-assistant.io/integrations/binary_sensor.group/)
2. Si vous n'avez pas de capteur de fenêtre/porte dans votre chambre, laissez simplement l'identifiant de l'entité du capteur vide
## Configurer le mode d'activité ou la détection de mouvement
Si vous avez choisi la fonctionnalité ```Avec détection de mouvement```, cliquez sur 'Valider' sur la page précédente et vous y arriverez :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-motion.png?raw=true)
Nous allons maintenant voir comment configurer le nouveau mode Activité.
Ce dont nous avons besoin:
- un **capteur de mouvement**. ID d'entité d'un capteur de mouvement. Les états du capteur de mouvement doivent être « on » (mouvement détecté) ou « off » (aucun mouvement détecté)
- une durée de **délai de mouvement** (en secondes) définissant combien de temps nous attendons la confirmation du mouvement avant de considérer le mouvement
- un **préréglage de "mouvement" **. Nous utiliserons la température de ce préréglage lorsqu'une activité sera détectée.
- un **préréglage "pas de mouvement"**. Nous utiliserons la température de ce deuxième préréglage lorsqu'aucune activité n'est détectée.
Alors imaginons que nous voulions avoir le comportement suivant :
- nous avons une pièce avec un thermostat réglé en mode activité, le mode "mouvement" choisi est confort (21.5C), le mode "pas de mouvement" choisi est Eco (18.5C) et la temporisation du mouvement est de 5 min.
- la pièce est vide depuis un moment (aucune activité détectée), la température de cette pièce est de 18,5 C
- quelqu'un entre dans la pièce, une activité est détectée la température est fixée à 21,5 C
- la personne quitte la chambre, au bout de 5 min la température est ramenée à 18,5 C
Pour que cela fonctionne, le thermostat climatique doit être en mode préréglé « Activité ».
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. Sachez que comme pour les autres modes prédéfinis, ``Activity`` ne sera proposé que s'il est correctement configuré. En d'autres termes, les 4 clés de configuration doivent être définies si vous souhaitez voir l'activité dans l'interface de l'assistant domestique
## Configurer la gestion de la puissance
Si vous avez choisi la fonctionnalité ```Avec détection de la puissance```, cliquez sur 'Valider' sur la page précédente et vous arriverez ici :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-power.png?raw=true)
Cette fonction vous permet de réguler la consommation électrique de vos radiateurs. Connue sous le nom de délestage, cette fonction vous permet de limiter la consommation électrique de votre appareil de chauffage si des conditions de surpuissance sont détectées. Donnez un **capteur à la consommation électrique actuelle de votre maison**, un **capteur à la puissance max** qu'il ne faut pas dépasser, la **consommation électrique de votre chauffage** et l'algorithme ne démarrera pas un radiateur si la puissance maximale sera dépassée après le démarrage du radiateur.
Notez que toutes les valeurs de puissance doivent avoir les mêmes unités (kW ou W par exemple).
Cela vous permet de modifier la puissance maximale au fil du temps à l'aide d'un planificateur ou de ce que vous voulez.
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. En cas de délestage, le radiateur est réglé sur le préréglage nommé ```power```. Il s'agit d'un préréglage caché, vous ne pouvez pas le sélectionner manuellement.
2. Je l'utilise pour éviter de dépasser la limite de mon contrat d'électricité lorsqu'un véhicule électrique est en charge. Cela crée une sorte d'autorégulation.
3. Gardez toujours une marge, car la puissance max peut être brièvement dépassée en attendant le calcul du prochain cycle typiquement ou par des équipements non régulés.
4. Si vous ne souhaitez pas utiliser cette fonctionnalité, laissez simplement l'identifiant des entités vide
## Configurer la présence ou l'occupation
Si sélectionnée en première page, cette fonction vous permet de modifier dynamiquement la température de tous les préréglages du thermostat configurés lorsque personne n'est à la maison ou lorsque quelqu'un rentre à la maison. Pour cela, vous devez configurer la température qui sera utilisée pour chaque préréglage lorsque la présence est désactivée. Lorsque le capteur de présence s'éteint, ces températures seront utilisées. Lorsqu'il se rallume, la température "normale" configurée pour le préréglage est utilisée. Voir [gestion des préréglages](#configure-the-preset-temperature).
Pour configurer la présence remplissez ce formulaire :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-presence.png?raw=true)
Pour cela, vous devez configurer :
1. Un **capteur d'occupation** dont l'état doit être 'on' ou 'home' si quelqu'un est présent ou 'off' ou 'not_home' sinon,
2. La **température utilisée en Eco** prédéfinie en cas d'absence,
3. La **température utilisée en Confort** préréglée en cas d'absence,
4. La **température utilisée en Boost** préréglée en cas d'absence
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. le changement de température est immédiat et se répercute sur le volet avant. Le calcul prendra en compte la nouvelle température cible au prochain calcul du cycle,
2. vous pouvez utiliser le capteur direct person.xxxx ou un groupe de capteurs de Home Assistant. Le capteur de présence gère les états ``on`` ou ``home`` comme présents et les états ``off`` ou ``not_home`` comme absents.
## Configuration avancée
Ces paramètres permettent d'affiner le réglage du thermostat.
Le formulaire de configuration avancée est le suivant :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-advanced.png?raw=true)
Le premier délai (minimal_activation_delay_sec) en sec dans le délai minimum acceptable pour allumer le chauffage. Lorsque le calcul donne un délai de mise sous tension inférieur à cette valeur, le chauffage reste éteint.
Le deuxième délai (security_delay_min) est le délai maximal entre deux mesures de température avant de régler le préréglage sur ``security`` et d'éteindre le thermostat. Si le capteur de température ne donne plus de mesures de température, le thermostat et le radiateur s'éteindront après ce délai et le préréglage du thermostat sera réglé sur ``security``. Ceci est utile pour éviter une surchauffe si la batterie de votre capteur de température est trop faible.
Le troisième paramétre (security_min_on_percent) est la valeur minimal de on_percent en dessous de laquelle le préréglage sécurité ne sera pas activé.
Mettre ce paramètre à ``0.00`` déclenchera le préréglage sécurité quelque soit la dernière consigne de chauffage, à l'inverse ``1.00`` ne déclenchera jamais le préréglage sécurité.
Voir [exemple de réglages](#examples-tuning) pour avoir des exemples de réglage communs
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. Le préréglage ``security`` est un préréglage caché. Vous ne pouvez pas le sélectionner manuellement ou par le service prédéfini,
2. Lorsque le capteur de température viendra à vivre et renverra les températures, le préréglage sera restauré à sa valeur précédente,
3. Attention, deux températures sont nécessaires : la température interne et la température externe et chacune doit donner la température, sinon le thermostat sera en préréglage "security".
# Exemples de réglage
## Chauffage électrique
- cycle : entre 5 et 10 minutes,
- minimal_activation_delay_sec : 30 secondes
## Chauffage central (chauffage gaz ou fuel)
- cycle : entre 30 et 60 min,
- minimal_activation_delay_sec : 300 secondes (à cause du temps de réponse)
## Le capteur de température sera alimenté par batterie
- security_delay_min : 60 min (parce que ces capteurs sont paresseux)
## Capteur de température réactif
- security_delay_min : 15 min
## Ma configuration prédéfinie
Ceci est juste un exemple de la façon dont j'utilise le préréglage. A vous de vous adapter à votre configuration mais cela peut être utile pour comprendre son fonctionnement.
``Éco`` : 17
``Confort`` : 19
``Boost`` : 20
Lorsque la présence est désactivée :
``Éco`` : 16,5
``Confort`` : 17
``Boost`` : 18
Le détecteur de mouvement de mon bureau est configuré pour utiliser ``Boost`` lorsqu'un mouvement est détecté et ``Eco`` sinon.
# Algorithme
Cette intégration utilise un algorithme proportionnel. Un algorithme proportionnel est utile pour éviter l'oscillation autour de la température cible. Cet algorithme est basé sur un cycle qui alterne le chauffage et l'arrêt du chauffage. La proportion de chauffage par rapport à l'absence de chauffage est déterminée par la différence entre la température et la température cible. Plus grande est la différence et plus grande est la proportion de chauffage à l'intérieur du cycle.
Cet algorithme fait converger la température et arrête d'osciller.
## Algorithme TPI
L'algorithme TPI consiste à calculer à chaque cycle un pourcentage d'état On vs Off pour le radiateur en utilisant la température cible, la température actuelle dans la pièce et la température extérieure actuelle.
Le pourcentage est calculé avec cette formule :
on_percent = coef_int * (température cible - température actuelle) + coef_ext * (température cible - température extérieure)
Ensuite, faites 0 <= on_percent <= 1
Les valeurs par défaut pour coef_int et coef_ext sont respectivement : ``0.6`` et ``0.01``. Ces valeurs par défaut conviennent à une pièce standard bien isolée.
Pour régler ces coefficients, gardez à l'esprit que :
1. **si la température cible n'est pas atteinte** après une situation stable, vous devez augmenter le ``coef_ext`` (le ``on_percent`` est trop élevé),
2. **si la température cible est dépassée** après une situation stable, vous devez diminuer le ``coef_ext`` (le ``on_percent`` est trop bas),
3. **si l'atteinte de la température cible est trop lente**, vous pouvez augmenter le ``coef_int`` pour donner plus de puissance au réchauffeur,
4. **si l'atteinte de la température cible est trop rapide et que des oscillations apparaissent** autour de la cible, vous pouvez diminuer le ``coef_int`` pour donner moins de puissance au radiateur
Voir quelques situations à [examples](#some-results).
# Services
Cette implémentation personnalisée offre des services spécifiques pour faciliter l'intégration avec d'autres composants Home Assistant.
## Forcer la présence/occupation
Ce service permet de forcer l'état de présence indépendamment du capteur de présence. Cela peut être utile si vous souhaitez gérer la présence via un service et non via un capteur. Par exemple, vous pouvez utiliser votre réveil pour forcer l'absence lorsqu'il est allumé.
Le code pour appeler ce service est le suivant :
```
service : thermostat_polyvalent.set_presence
Les données:
présence : "off"
cible:
entity_id : climate.my_thermostat
```
## Modifier la température des préréglages
Ce service est utile si vous souhaitez modifier dynamiquement la température préréglée. Au lieu de changer de préréglage, certains cas d'utilisation doivent modifier la température du préréglage. Ainsi, vous pouvez garder le Programmateur inchangé pour gérer le préréglage et ajuster la température du préréglage.
Si le préréglage modifié est actuellement sélectionné, la modification de la température cible est immédiate et sera prise en compte au prochain cycle de calcul.
Vous pouvez modifier l'une ou les deux températures (lorsqu'elles sont présentes ou absentes) de chaque préréglage.
Utilisez le code suivant pour régler la température du préréglage :
```
service : thermostat_polyvalent.set_preset_temperature
date:
prest : boost
temperature : 17,8
temperature_away : 15
target:
entity_id : climate.my_thermostat
```
> ![Astuce](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
- après un redémarrage, les préréglages sont réinitialisés à la température configurée. Si vous souhaitez que votre changement soit permanent, vous devez modifier le préréglage de la température dans la configuration de l'intégration.
# Attributs personnalisés
Pour régler l'algorithme, vous avez accès à tout le contexte vu et calculé par le thermostat via des attributs dédiés. Vous pouvez voir (et utiliser) ces attributs dans l'IHM "Outils de développement / états" de HA. Entrez votre thermostat et vous verrez quelque chose comme ceci :
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/dev-tools-climate.png?raw=true)
Les attributs personnalisés sont les suivants :
| Attribut | Signification |
| ----------| --------|
| ``hvac_modes`` | La liste des modes supportés par le thermostat |
| ``temp_min`` | La température minimale |
| ``temp_max`` | La température maximale |
| ``preset_modes`` | Les préréglages visibles pour ce thermostat. Les préréglages cachés ne sont pas affichés ici |
| ``temperature_actuelle`` | La température actuelle telle que rapportée par le capteur |
| ``temperature`` | La température cible |
| ``action_hvac`` | L'action en cours d'exécution par le réchauffeur. Peut être inactif, chauffage |
| ``preset_mode`` | Le préréglage actuellement sélectionné. Peut être l'un des 'preset_modes' ou un préréglage caché comme power |
| ``[eco/confort/boost]_temp`` | La température configurée pour le préréglage xxx |
| ``[eco/confort/boost]_away_temp`` | La température configurée pour le préréglage xxx lorsque la présence est désactivée ou not_home |
| ``temp_power`` | La température utilisée lors de la détection de la perte |
| ``on_percent`` | Le pourcentage sur calculé par l'algorithme TPI |
| ``on_time_sec`` | La période On en sec. Doit être ```on_percent * cycle_min``` |
| ``off_time_sec`` | La période d'arrêt en sec. Doit être ```(1 - on_percent) * cycle_min``` |
| ``cycle_min`` | Le cycle de calcul en minutes |
| ``function`` | L'algorithme utilisé pour le calcul du cycle |
| ``tpi_coef_int`` | Le ``coef_int`` de l'algorithme TPI |
| ``tpi_coef_ext`` | Le ``coef_ext`` de l'algorithme TPI |
| ``saved_preset_mode`` | Le dernier preset utilisé avant le basculement automatique du preset |
| ``saved_target_temp`` | La dernière température utilisée avant la commutation automatique |
| ``window_state`` | Le dernier état connu du capteur de fenêtre. Aucun si la fenêtre n'est pas configurée |
| ``motion_state`` | Le dernier état connu du capteur de mouvement. Aucun si le mouvement n'est pas configuré |
| ``overpowering_state`` | Le dernier état connu du capteur surpuissant. Aucun si la gestion de l'alimentation n'est pas configurée |
| ``presence_state`` | Le dernier état connu du capteur de présence. Aucun si la gestion de présence n'est pas configurée |
| ``security_delay_min`` | Le délai avant de régler le mode de sécurité lorsque le capteur de température est éteint |
| ``security_min_on_percent`` | Seuil en dessous duquel le thermostat ne passera pas en sécurité |
| ``last_temperature_datetime`` | La date et l'heure au format ISO8866 de la dernière réception de température interne |
| ``last_ext_temperature_datetime`` | La date et l'heure au format ISO8866 de la dernière réception de température extérieure |
| ``**état_sécurité**`` | L'état de sécurité. vrai ou faux |
| ``minimal_activation_delay_sec`` | Le délai d'activation minimal en secondes |
| ``last_update_datetime`` | La date et l'heure au format ISO8866 de cet état |
| ``friendly_name`` | Le nom du thermostat |
| ``supported_features`` | Une combinaison de toutes les fonctionnalités prises en charge par ce thermostat. Voir la documentation officielle sur l'intégration climatique pour plus d'informations |
# Quelques résultats
**Convergence de la température vers la cible configurée par preset:**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-1.png?raw=true)
[Cycle de marche/arrêt calculé par l'intégration :](https://)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-2.png?raw=true)
**Coef_int trop élevé (oscillations autour de la cible)**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-3.png?raw=true)
**Évolution du calcul de l'algorithme**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-4.png?raw=true)
Voir le code de ce composant [[ci-dessous](#even-better-with-apex-chart-to-tune-your-thermostat)]
**Thermostat finement réglé**
Merci [impuR_Shozz](https://forum.hacf.fr/u/impur_shozz/summary) !
On peut voir une stabilité autour de la température cible (consigne) et lorsqu'à cible le on_percent (puissance) est proche de 0,3 ce qui semble une très bonne valeur.
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-fine-tuned.png?raw=true)
Enjoy !
# Encore mieux
## Encore mieux avec le composant Scheduler !
Afin de profiter de toute la puissance du Versatile Thermostat, je vous invite à l'utiliser avec https://github.com/nielsfaber/scheduler-component
En effet, le composant scheduler propose une gestion de la base climatique sur les modes prédéfinis. Cette fonctionnalité a un intérêt limité avec le thermostat générique mais elle devient très puissante avec le thermostat Awesome :
À partir d'ici, je suppose que vous avez installé Awesome Thermostat et Scheduler Component.
Dans Scheduler, ajoutez un planning :
![image](https://user-images.githubusercontent.com/1717155/119146454-ee1a9d80-ba4a-11eb-80ae-3074c3511830.png)
Choisissez le groupe "climat", choisissez une (ou plusieurs) entité(s), sélectionnez "MAKE SCHEME" et cliquez sur suivant :
(il est possible de choisir "SET PRESET", mais je préfère utiliser "MAKE SCHEME")
![image](https://user-images.githubusercontent.com/1717155/119147210-aa746380-ba4b-11eb-8def-479a741c0ba7.png)
Définissez votre schéma de mode et enregistrez :
![image](https://user-images.githubusercontent.com/1717155/119147784-2f5f7d00-ba4c-11eb-9de4-5e62ff5e71a8.png)
Dans cet exemple, j'ai réglé le mode ECO pendant la nuit et le jour lorsqu'il n'y a personne à la maison BOOST le matin et CONFORT le soir.
J'espère que cet exemple vous aidera, n'hésitez pas à me faire part de vos retours !
## Encore bien mieux avec la custom:simple-thermostat front integration
Le ``custom:simple-thermostat`` [ici](https://github.com/nervetattoo/simple-thermostat) est une excellente intégration qui permet une certaine personnalisation qui s'adapte bien à ce thermostat.
Vous pouvez avoir quelque chose comme ça très facilement ![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/simple-thermostat.png?raw=true)
Exemple de configuration :
```
type: custom:simple-thermostat
entity: climate.thermostat_sam2
layout:
step: row
label:
temperature: T°
state: Etat
hide:
state: false
control:
hvac:
_name: Mode
preset:
_name: Preset
sensors:
- entity: sensor.total_puissance_radiateur_sam2
icon: mdi:lightning-bolt-outline
header:
toggle:
entity: input_boolean.etat_ouverture_porte_sam
name: Porte sam
```
## Toujours mieux avec Apex-chart pour régler votre thermostat
Vous pouvez obtenir une courbe comme celle présentée dans [some results](#some-results) avec une sorte de configuration de graphique Apex uniquement en utilisant les attributs personnalisés du thermostat décrits [ici](#custom-attributes) :
```
type: custom:apexcharts-card
header:
show: true
title: Tuning chauffage
show_states: true
colorize_states: true
update_interval: 60sec
graph_span: 4h
yaxis:
- id: left
show: true
decimals: 2
- id: right
decimals: 2
show: true
opposite: true
series:
- entity: climate.thermostat_mythermostat
attribute: temperature
type: line
name: Target temp
curve: smooth
yaxis_id: left
- entity: climate.thermostat_mythermostat
attribute: current_temperature
name: Current temp
curve: smooth
yaxis_id: left
- entity: climate.thermostat_mythermostat
attribute: on_percent
name: Power percent
curve: stepline
yaxis_id: right
```
# Les contributions sont les bienvenues !
Si vous souhaitez contribuer, veuillez lire les [directives de contribution](CONTRIBUTING.md)
***
[integration_blueprint]: https://github.com/custom-components/integration_blueprint
[versatile_thermostat]: https://github.com/jmcollin78/versatile_thermostat
[commits-shield]: https://img.shields.io/github/commit-activity/y/jmcollin78/versatile_thermostat.svg?style=for-the-badge
[commits]: https://github.com/jmcollin78/versatile_thermostat/commits/master
[hacs]: https://github.com/custom-components/hacs
[hacs_badge]: https://img.shields.io/badge/HACS-Custom-41BDF5.svg?style=for-the-badge
[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg?style=for-the-badge
[forum]: https://community.home-assistant.io/
[license-shield]: https://img.shields.io/github/license/jmcollin78/versatile_thermostat.svg?style=for-the-badge
[maintenance-shield]: https://img.shields.io/badge/maintainer-Joakim%20Sørensen%20%40ludeeus-blue.svg?style=for-the-badge
[releases-shield]: https://img.shields.io/github/release/jmcollin78/versatile_thermostat.svg?style=for-the-badge
[releases]: https://github.com/jmcollin78/versatile_thermostat/releases

181
README.md
View File

@@ -3,7 +3,9 @@
[![License][license-shield]](LICENSE)
[![hacs][hacs_badge]][hacs]
> ![Tip](images/tips.png) This thermostat integration aims to drastically simplify your automations around climate management. Because all classical events in climate are natively handled by the thermostat (nobody at home ?, activity detected in a room ?, window open ?, power shedding ?), you don't have to build over complicated scripts and automations to manage your climates ;-).
![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/icon.png?raw=true)
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true?raw=true) This thermostat integration aims to drastically simplify your automations around climate management. Because all classical events in climate are natively handled by the thermostat (nobody at home ?, activity detected in a room ?, window open ?, power shedding ?), you don't have to build over complicated scripts and automations to manage your climates ;-).
- [When to use / not use](#when-to-use--not-use)
- [Why another thermostat implementation ?](#why-another-thermostat-implementation-)
@@ -12,12 +14,20 @@
- [Manual installation](#manual-installation)
- [Configuration](#configuration)
- [Minimal configuration update](#minimal-configuration-update)
- [Select the driven entity](#select-the-driven-entity)
- [Configure the TPI algorithm coefficients](#configure-the-tpi-algorithm-coefficients)
- [Configure the preset temperature](#configure-the-preset-temperature)
- [Configure the doors/windows turning on/off the thermostats](#configure-the-doorswindows-turning-onoff-the-thermostats)
- [Configure the activity mode or motion detection](#configure-the-activity-mode-or-motion-detection)
- [Configure the power management](#configure-the-power-management)
- [Configure the presence or occupancy](#configure-the-presence-or-occupancy)
- [Advanced configuration](#advanced-configuration)
- [Examples tuning](#examples-tuning)
- [Electrical heater](#electrical-heater)
- [Central heating (gaz or fuel heating system)](#central-heating-gaz-or-fuel-heating-system)
- [Temperature sensor will battery](#temperature-sensor-will-battery)
- [Reponsive temperature sensor](#reponsive-temperature-sensor)
- [My preset configuration](#my-preset-configuration)
- [Algorithm](#algorithm)
- [TPI algorithm](#tpi-algorithm)
- [Services](#services)
@@ -36,12 +46,17 @@ _Component developed by using the amazing development template [[blueprint](http
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.
# When to use / not use
This thermostat aims to command a heater which works only in on/off mode. The minimal needed configuration to use this thermostat is:
1. an equipement like a heater (a switch),
2. a temperature sensor for the room (or an input_number),
3. an external temperature sensor (think of the meteo integration if you don't have one)
This thermostat can control 2 types of equipment:
1. a heater that only works in on/off mode (named ```thermostat_over_switch```). The minimum configuration required to use this type of thermostat is:
has. equipment such as a radiator (a ```switch``` or equivalent),
b. a temperature probe for the room (or an input_number),
vs. an external temperature sensor (think about weather integration if you don't have one)
2. another thermostat that has its own operating modes (named ```thermostat_over_climate```). For this type of thermostat, the minimum configuration requires:
has. equipment such as air conditioning which is controlled by its own ```climate``` type entity,
b. a temperature probe for the room (or an input_number),
vs. an external temperature sensor (think about weather integration if you don't have one)
Because this integration aims to command the heater considering the preset configured and the room temperature, those informations are mandatory.
The ```thermostat_over_climate``` type allows you to add all the functionality provided by VersatileThermostat to your existing equipment. The climate VersatileThermostat entity will control your climate entity, turning it off if the windows are open, switching it to Eco mode if no one is present, etc. See [here](#why-a-new-implementation-of-the-thermostat). For this type of thermostat, any heating cycles are controlled by the underlying climate entity and not by the Versatile Thermostat itself.
# Why another thermostat implementation ?
@@ -83,36 +98,47 @@ This component named __Versatile thermostat__ manage the following use cases :
Note: no configuration in configuration.yaml is needed because all configuration is done through the standard GUI when adding the integration.
Click on Add integration button in the integration page
![image](images/add-an-integration.png?raw=true)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/add-an-integration.png?raw=true)
The configuration can be change through the same interface. Simply select the thermostat to change, hit "Configure" and you will be able to change some parameters or configuration. Don't forget to reload (dot menu / reload) to take the new configuration into account.
The configuration can be change through the same interface. Simply select the thermostat to change, hit "Configure" and you will be able to change some parameters or configuration.
Then follow the configurations steps as follow:
## Minimal configuration update
![image](images/config-main.png?raw=true)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-main.png?raw=true)
Give the main mandatory attributes:
1. a name (will be the integration name and also the climate entity name)
2. an equipment entity id which represent the heater. This equipment should be able to switch on or off,
3. a temporature sensor entity id which gives the temperature of the room in which the heater is installed,
4. a temperature sensor entity giving the external temperature. If don't have any external sensor, you can use the local meteo integration
5. a cycle duration in minutes. At each cycle, the heater will be turned on then off for a calculated period in order to reach the targeted temperature (see [preset](#configure-the-preset-temperature) below),
6. Algorithm to use. Today only the TPI algorithm is available. See [algorithm](#algorithm)
1. a name (will be the name of the integration and also the name of the climate entity)
2. the type of thermostat ```thermostat_over_switch``` to control a radiator controlled by a switch or ```thermostat_over_climate``` to control another thermostat. Cf. [above](#why-a-new-thermostat-implementation)
4. a temperature sensor entity identifier which gives the temperature of the room in which the radiator is installed,
5. a temperature sensor entity giving the outside temperature. If you don't have an external sensor, you can use local weather integration
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),
7. minimum and maximum thermostat temperatures,
8. the list of features that will be used for this thermostat. Depending on your choices, the following configuration screens will appear or not.
> ![Tip](images/tips.png) _*Notes*_
1. 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**,
> ![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**,
2. if the cycle is too short, the heater could never reach the target temperature indeed for heater with accumulation features and it will be unnecessary solicited
## Select the driven entity
Depending on your choice on the type of thermostat, you will have to choose a switch type entity or a climate type entity. Only compatible entities are shown.
For a ```thermostat_over_switch``` thermostat:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-linked-entity.png?raw=true)
The algorithm to be used today is limited to TPI is available. See [algorithm](#algorithm)
For a ```thermostat_over_climate``` thermostat:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-linked-entity2.png?raw=true)
## Configure the TPI algorithm coefficients
Click on 'Validate' on the previous page and you will get there:
![image](images/config-tpi.png?raw=true)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-tpi.png?raw=true)
For more informations on the TPI algorithm and tuned please refer to [algorithm](#algorithm).
## Configure the preset temperature
Click on 'Validate' on the previous page and you will get there:
![image](images/config-presets.png?raw=true)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-presets.png?raw=true)
The preset mode allows you to pre-configurate targeted temperature. Used in conjonction with Scheduler (see [scheduler](#even-better-with-scheduler-component) you will have a powerfull and simple way to optimize the temperature vs electrical consumption of your hous. Preset handled are the following :
- **Eco** : device is running an energy-saving mode
@@ -121,15 +147,16 @@ The preset mode allows you to pre-configurate targeted temperature. Used in conj
**None** is always added in the list of modes, as it is a way to not use the presets modes but a **manual temperature** instead.
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. Changing manually the target temperature, set the preset to None (no preset). This way you can always set a target temperature even if no preset are available.
2. standard **Away** preset is a hidden preset which is not directly selectable. Versatile Thermostat uses the presence management or movement management to set automatically and dynamically the target temperature depending on a presence in the home or an activity in the room. See [presence management](#configure-the-presence-management).
3. if you uses the power shedding management, you will see a hidden preset named **power**. The heater preset is set to **power** when overpowering conditions are encountered and shedding is active for this heater. See [power management](#configure-the-power-management).
4. If you don't want to use the preseet, give 0 as temperature. The preset will then been ignored and will not displayed in the front component
2. standard ``Away`` preset is a hidden preset which is not directly selectable. Versatile Thermostat uses the presence management or movement management to set automatically and dynamically the target temperature depending on a presence in the home or an activity in the room. See [presence management](#configure-the-presence-management).
3. if you uses the power shedding management, you will see a hidden preset named ``power``. The heater preset is set to ``power`` when overpowering conditions are encountered and shedding is active for this heater. See [power management](#configure-the-power-management).
4. if you uses the advanced configuration you will see the preset set to ``security`` if the temperature could not be retrieved after a certain delay
5. ff you don't want to use the preseet, give 0 as temperature. The preset will then been ignored and will not displayed in the front component
## Configure the doors/windows turning on/off the thermostats
Click on 'Validate' on the previous page and you will get there:
![image](images/config-window.png?raw=true)
If you choose the ```Window management``` feature, click on 'Validate' on the previous page and you will get there:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-window.png?raw=true)
Give the following attributes:
1. an entity id of a **window/door sensor**. This should be a binary_sensor or a input_boolean. The state of the entity should be 'on' when the window is open or 'off' when closed
@@ -137,13 +164,13 @@ Give the following attributes:
And that's it ! your thermostat will turn off when the windows is open and be turned back on when it's closed afer the delay.
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. If you want to use **several door/windows sensors** to automatize your thermostat, just create a group with the regular behavior (https://www.home-assistant.io/integrations/binary_sensor.group/)
2. If you don't have any window/door sensor in your room, just leave the sensor entity id empty
## Configure the activity mode or motion detection
Click on 'Validate' on the previous page and you will get there:
![image](images/config-motion.png?raw=true)
If you choose the ```Motion management``` feature, lick on 'Validate' on the previous page and you will get there:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-motion.png?raw=true)
We will now see how to configure the new Activity mode.
What we need:
@@ -160,27 +187,31 @@ So imagine we want to have the following behavior :
For this to work, the climate thermostat should be in ``Activity`` preset mode.
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. Be aware that as for the others preset modes, ``Activity`` will only be proposed if it's correctly configure. In other words, the 4 configuration keys have to be set if you want to see Activity in home assistant Interface
## Configure the power management
Click on 'Validate' on the previous page and you will get there:
If you choose the ```Power management``` feature, click on 'Validate' on the previous page and you will get there:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-power.png?raw=true)
This feature allows you to regulate the power consumption of your radiators. Known as shedding, this feature allows you to limit the electrical power consumption of your heater if overpowering conditions are detected. Give a **sensor to the current power consumption of your house**, a **sensor to the max power** that should not be exceeded, the **power consumption of your heater** and the algorithm will not start a radiator if the max power will be exceeded after radiator starts.
![image](images/config-power.png?raw=true)
Note that all power values should have the same units (kW or W for example).
This allows you to change the max power along time using a Scheduler or whatever you like.
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. When shedding is encountered, the heater is set to the preset named ``power``. This is a hidden preset, you cannot select it manually.
2. I use this to avoid exceeded the limit of my electrical power contract when an electrical vehicle is charging. This makes a kind of auto-regulation.
3. Always keep a margin, because max power can be briefly exceeded while waiting for the next cycle calculation typically or by not regulated equipement.
4. If you don't want to use this feature, just leave the entities id empty
## Configure the presence or occupancy
This feature allows you to dynamically changes the temperature of all configured Versatile thermostat's presets when nobody is at home or when someone comes back home. For this, you have to configure the temperature that will be used for each preset when presence is off. When the occupancy sensor turns to off, those tempoeratures will be used. When it turns on again the "normal" temperature configured for the preset is used. See [preset management](#configure-the-preset-temperature).
If you choose the ```Presence management``` feature, this feature allows you to dynamically changes the temperature of all configured Versatile thermostat's presets when nobody is at home or when someone comes back home. For this, you have to configure the temperature that will be used for each preset when presence is off. When the occupancy sensor turns to off, those tempoeratures will be used. When it turns on again the "normal" temperature configured for the preset is used. See [preset management](#configure-the-preset-temperature).
To configure presence fills this form:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-presence.png?raw=true)
For this you need to configure:
1. A **occupancy sensor** which state should be 'on' or 'home' if someone is present or 'off' or 'not_home' else,
@@ -188,10 +219,58 @@ For this you need to configure:
3. The **temperature used in Comfort** preset when absent,
4. The **temperature used in Boost** preset when absent
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. the switch of temperature is immediate and is reflected on the front component. The calculation will take the new target temperature into account at the next cycle calculation,
2. you can use direct person.xxxx sensor or group of sensors of Home Assistant. The presence sensor handles ``on`` or ``home`` states as present and ``off`` or ``not_home`` state as absent.
## Advanced configuration
Those parameters allows to fine tune the thermostat.
The advanced configuration form is the following:
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/config-advanced.png?raw=true)
The first delay (minimal_activation_delay_sec) in sec in the minimum delay acceptable for turning on the heater. When calculation gives a power on delay below this value, the heater will stays off.
The second delay (security_delay_min) is the maximal delay between two temperature measure before setting the preset to ``security`` and turning off the thermostat. If the temperature sensor is no more giving temperature measures, the thermostat and heater will turns off after this delay and the preset of the thermostat will be set to ``security``. This is useful to avoid overheating is the battery of your temperature sensor is too low.
The third parameter (security_min_on_percent) is the minimal on_percent value below which the security preset won't be trigger. If you set it to ``0.00`` security preset will be trigger regardeless of the heating on_percent when there is a temperature loss, at the opposite ``1.00`` will never trigger the security preset.
See [exemple tuning](#examples-tuning) to have some commons tuning examples
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
1. The ``security`` preset is a hidden preset. You cannot select it manually or by the preset service,
2. When the temperature sensor will comes to live and re-send temperatures, the preset will be restored to its previous value,
3. Beware that two temperatures are needed: internal temp and external temp and each should give temperature else the thermostat will be in ``security`` preset.
# Examples tuning
## Electrical heater
- cycle: between 5 and 10 minutes,
- minimal_activation_delay_sec: 30 seconds
## Central heating (gaz or fuel heating system)
- cycle: between 30 and 60 min,
- minimal_activation_delay_sec: 300 seconds (because of the response time)
## Temperature sensor will battery
- security_delay_min: 60 min (because those sensors are leazy)
## Reponsive temperature sensor
- security_delay_min: 15 min
## My preset configuration
This is just an example of how I use the preset. It up to you to adapt to your configuration but it can be useful to understand how it works.
``Eco``: 17
``Comfort``: 19
``Boost``: 20
When presence if off:
``Eco``: 16.5
``Comfort``: 17
``Boost``: 18
Motion detector in my office is set to use ``Boost`` when motion is detected and ``Eco`` if not.
# Algorithm
This integration uses a proportional algorithm. A Proportional algorithm is useful to avoid the oscillation around the target temperature. This algorithm is based on a cycle which alternate heating and stop heating. The proportion of heating vs not heating is determined by the difference between the temperature and the target temperature. Bigger the difference is and bigger is the proportion of heating inside the cycle.
@@ -248,13 +327,13 @@ target:
entity_id: climate.my_thermostat
```
> ![Tip](images/tips.png) _*Notes*_
> ![Tip](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/tips.png?raw=true) _*Notes*_
- after a restart the preset are resetted to the configured temperature. If you want your change to be permanent you should modify the temperature preset into the confguration of the integration.
# Custom attributes
To tune the algorithm you have access to all context seen and calculted by the thermostat through dedicated attributes. You can see (and use) those attributes in the "Development tools / states" HMI of HA. Enter your thermostat and you will see something like this:
![image](images/dev-tools-climate.png?raw=true)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/dev-tools-climate.png?raw=true)
Custom attributes are the following:
@@ -284,24 +363,36 @@ Custom attributes are the following:
| ``motion_state`` | The last known state of the motion sensor. None if motion is not configured |
| ``overpowering_state`` | The last known state of the overpowering sensor. None if power management is not configured |
| ``presence_state`` | The last known state of the presence sensor. None if presence management is not configured |
| ``security_delay_min`` | The delay before setting the security mode when temperature sensor are off |
| ``security_min_on_percent`` | The minimal on_percent below which security preset won't be trigger |
| ``last_temperature_datetime`` | The date and time in ISO8866 format of the last internal temperature reception |
| ``last_ext_temperature_datetime`` | The date and time in ISO8866 format of the last external temperature reception |
| ``security_state`` | The security state. true or false |
| ``minimal_activation_delay_sec`` | The minimal activation delay in seconds |
| ``last_update_datetime`` | The date and time in ISO8866 format of this state |
| ``friendly_name`` | The name of the thermostat |
| ``supported_features`` | A combination of all features supported by this thermostat. See official climate integration documentation for more informations |
# Some results
Convergence of temperature to target configured by preset:
![image](images/results-1.png?raw=true)
**Convergence of temperature to target configured by preset:**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-1.png?raw=true)
Cycle of on/off calculated by the integration:
![image](images/results-2.png?raw=true)
[Cycle of on/off calculated by the integration:](https://)
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-2.png?raw=true)
Coef_int too high (oscillations around the target)
![image](images/results-3.png?raw=true)
**Coef_int too high (oscillations around the target)**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-3.png?raw=true)
Algorithm calculation evolution
![image](images/results-4.png?raw=true)
**Algorithm calculation evolution**
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-4.png?raw=true)
See the code of this component [[below](#even-better-with-apex-chart-to-tune-your-thermostat)]
**Fine tuned thermostat**
Thank's [impuR_Shozz](https://forum.hacf.fr/u/impur_shozz/summary) !
We can see stability around the target temperature (consigne) and when at target the on_percent (puissance) is near 0.3 which seems a very good value.
![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/results-fine-tuned.png?raw=true)
Enjoy !
@@ -335,7 +426,7 @@ I hope this example helps you, don't hesitate to give me your feedbacks !
## Even-even better with custom:simple-thermostat front integration
The ``custom:simple-thermostat`` [here](https://github.com/nervetattoo/simple-thermostat) is a great integration which allow some customisation which fits well with this thermostat.
You can have something like that very easily ![image](images/simple-thermostat.png?raw=true)
You can have something like that very easily ![image](https://github.com/jmcollin78/versatile_thermostat/blob/main/images/simple-thermostat.png?raw=true)
Example configuration:
```

37
container Executable file
View File

@@ -0,0 +1,37 @@
#!/bin/bash
# set -x
. .bashrc
cd $HA
echo "arguments are: "$*
# Post installation of container
command=$1
if [ "$command" == "install" ]; then
echo "Running container post installation"
script/setup
fi
if [ "$command" == "start" ]; then
echo "Running container start"
hass -c ./config --debug
fi
if [ "$command" == "translations" ]; then
echo "Running container start"
python3 -m script.translations develop
fi
if [ "$command" == "hassfest" ]; then
echo "Running container start"
python3 -m script.hassfest
fi
if [ "$command" == "restart" ]; then
echo "Killing existing container"
pkill hass
echo "Killing existing container"
hass -c ./config
fi

View File

@@ -0,0 +1 @@
/home/vscode/core/homeassistant

View File

@@ -29,20 +29,24 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
# hass.data.setdefault(DOMAIN, {})
# TODO 1. Create API instance
api: VersatileThermostatAPI = hass.data.get(DOMAIN)
if api is None:
api = VersatileThermostatAPI(hass)
# TODO 2. Validate the API connection (and authentication)
# TODO 3. Store an API object for your platforms to access
api.add_entry(entry)
entry.async_on_unload(entry.add_update_listener(update_listener))
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""
await hass.config_entries.async_reload(entry.entry_id)
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
api: VersatileThermostatAPI = hass.data.get(DOMAIN)
@@ -89,3 +93,21 @@ class VersatileThermostatAPI(Dict):
def hass(self):
"""Get the HomeAssistant object"""
return self._hass
# Example migration function
async def async_migrate_entry(hass, config_entry: ConfigEntry):
"""Migrate old entry."""
_LOGGER.debug("Migrating from version %s", config_entry.version)
if config_entry.version == 1:
new = {**config_entry.data}
# TODO: modify Config Entry data
config_entry.version = 2
hass.config_entries.async_update_entry(config_entry, data=new)
_LOGGER.info("Migration to version %s successful", config_entry.version)
return True

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,13 @@
"""Config flow for Versatile Thermostat integration."""
from __future__ import annotations
from typing import Any
import logging
import copy
from collections.abc import Mapping
import voluptuous as vol
from collections.abc import Mapping
from typing import Any
from homeassistant.exceptions import HomeAssistantError
from homeassistant.core import callback
from homeassistant.config_entries import (
@@ -14,11 +15,27 @@ from homeassistant.config_entries import (
ConfigFlow as HAConfigFlow,
OptionsFlow,
)
from homeassistant.data_entry_flow import FlowHandler
from homeassistant.data_entry_flow import FlowResult
from homeassistant.exceptions import HomeAssistantError
from homeassistant.data_entry_flow import FlowHandler, FlowResult
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers import selector
from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.input_boolean import (
DOMAIN as INPUT_BOOLEAN_DOMAIN,
)
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.input_number import (
DOMAIN as INPUT_NUMBER_DOMAIN,
)
from homeassistant.components.person import DOMAIN as PERSON_DOMAIN
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from .const import (
DOMAIN,
@@ -45,10 +62,25 @@ from .const import (
CONF_TPI_COEF_INT,
CONF_PRESENCE_SENSOR,
PROPORTIONAL_FUNCTION_TPI,
CONF_SECURITY_DELAY_MIN,
CONF_SECURITY_MIN_ON_PERCENT,
CONF_SECURITY_DEFAULT_ON_PERCENT,
DEFAULT_SECURITY_MIN_ON_PERCENT,
DEFAULT_SECURITY_DEFAULT_ON_PERCENT,
CONF_MINIMAL_ACTIVATION_DELAY,
CONF_TEMP_MAX,
CONF_TEMP_MIN,
CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_SWITCH,
CONF_CLIMATE,
CONF_USE_WINDOW_FEATURE,
CONF_USE_MOTION_FEATURE,
CONF_USE_PRESENCE_FEATURE,
CONF_USE_POWER_FEATURE,
CONF_THERMOSTAT_TYPES,
UnknownEntity,
)
# from .climate import VersatileThermostat
_LOGGER = logging.getLogger(__name__)
@@ -93,6 +125,35 @@ def add_suggested_values_to_schema(
return vol.Schema(schema)
# def is_temperature_sensor(sensor: RegistryEntry):
# """Check if a registryEntry is a temperature sensor or assimilable to a temperature sensor"""
# if not sensor.entity_id.startswith(
# INPUT_NUMBER_DOMAIN
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
# return False
# return (
# sensor.device_class == TEMPERATURE
# or sensor.original_device_class == TEMPERATURE
# or sensor.unit_of_measurement in TEMPERATURE_UNITS
# )
#
#
# def is_power_sensor(sensor: RegistryEntry):
# """Check if a registryEntry is a power sensor or assimilable to a temperature sensor"""
# if not sensor.entity_id.startswith(
# INPUT_NUMBER_DOMAIN
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
# return False
# return (
# sensor.unit_of_measurement
# in [
# UnitOfPower.KILO_WATT,
# UnitOfPower.WATT,
# UnitOfPower.BTU_PER_HOUR,
# ]
# )
class VersatileThermostatBaseConfigFlow(FlowHandler):
"""The base Config flow class. Used to put some code in commons."""
@@ -103,13 +164,60 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
super().__init__()
_LOGGER.debug("CTOR BaseConfigFlow infos: %s", infos)
self._infos = infos
is_empty: bool = not bool(infos)
# Fix features selection depending to infos
self._infos[CONF_USE_WINDOW_FEATURE] = (
is_empty or self._infos.get(CONF_WINDOW_SENSOR) is not None
)
self._infos[CONF_USE_MOTION_FEATURE] = (
is_empty or self._infos.get(CONF_MOTION_SENSOR) is not None
)
self._infos[CONF_USE_POWER_FEATURE] = is_empty or (
self._infos.get(CONF_POWER_SENSOR) is not None
and self._infos.get(CONF_MAX_POWER_SENSOR) is not None
)
self._infos[CONF_USE_PRESENCE_FEATURE] = (
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
)
self.STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_NAME): cv.string,
vol.Required(CONF_HEATER): cv.string,
vol.Required(CONF_TEMP_SENSOR): cv.string,
vol.Required(CONF_EXTERNAL_TEMP_SENSOR): cv.string,
vol.Required(
CONF_THERMOSTAT_TYPE, default=CONF_THERMOSTAT_SWITCH
): selector.SelectSelector(
selector.SelectSelectorConfig(
options=CONF_THERMOSTAT_TYPES, translation_key="thermostat_type"
)
),
vol.Required(CONF_TEMP_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
),
),
# vol.In(temp_sensors),
vol.Required(CONF_EXTERNAL_TEMP_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
),
), # vol.In(temp_sensors),
vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int,
vol.Required(CONF_TEMP_MIN, default=7): vol.Coerce(float),
vol.Required(CONF_TEMP_MAX, default=35): vol.Coerce(float),
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,
vol.Optional(CONF_USE_PRESENCE_FEATURE, default=False): cv.boolean,
}
)
self.STEP_THERMOSTAT_SWITCH = vol.Schema(
{
vol.Required(CONF_HEATER): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[SWITCH_DOMAIN, INPUT_BOOLEAN_DOMAIN]
),
), # vol.In(switches),
vol.Required(
CONF_PROP_FUNCTION, default=PROPORTIONAL_FUNCTION_TPI
): vol.In(
@@ -120,6 +228,14 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
}
)
self.STEP_THERMOSTAT_CLIMATE = vol.Schema(
{
vol.Required(CONF_CLIMATE): selector.EntitySelector(
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
), # vol.In(climates),
}
)
self.STEP_TPI_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_TPI_COEF_INT, default=0.6): vol.Coerce(float),
@@ -136,14 +252,22 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
self.STEP_WINDOW_DATA_SCHEMA = vol.Schema(
{
vol.Optional(CONF_WINDOW_SENSOR): cv.string,
vol.Optional(CONF_WINDOW_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN]
),
), # vol.In(window_sensors),
vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int,
}
)
self.STEP_MOTION_DATA_SCHEMA = vol.Schema(
{
vol.Optional(CONF_MOTION_SENSOR): cv.string,
vol.Optional(CONF_MOTION_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN]
),
), # vol.In(window_sensors),
vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int,
vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In(
CONF_PRESETS_SELECTIONABLE
@@ -156,16 +280,32 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
self.STEP_POWER_DATA_SCHEMA = vol.Schema(
{
vol.Optional(CONF_POWER_SENSOR): cv.string,
vol.Optional(CONF_MAX_POWER_SENSOR): cv.string,
vol.Optional(CONF_DEVICE_POWER): vol.Coerce(float),
vol.Optional(CONF_PRESET_POWER): vol.Coerce(float),
vol.Optional(CONF_POWER_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
),
), # vol.In(power_sensors),
vol.Optional(CONF_MAX_POWER_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
),
), # vol.In(power_sensors),
vol.Optional(CONF_DEVICE_POWER, default="1"): vol.Coerce(float),
vol.Optional(CONF_PRESET_POWER, default="13"): vol.Coerce(float),
}
)
self.STEP_PRESENCE_DATA_SCHEMA = vol.Schema(
{
vol.Optional(CONF_PRESENCE_SENSOR): cv.string,
vol.Optional(CONF_PRESENCE_SENSOR): selector.EntitySelector(
selector.EntitySelectorConfig(
domain=[
PERSON_DOMAIN,
BINARY_SENSOR_DOMAIN,
INPUT_BOOLEAN_DOMAIN,
]
),
), # vol.In(presence_sensors),
}
).extend(
{
@@ -174,6 +314,23 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
}
)
self.STEP_ADVANCED_DATA_SCHEMA = vol.Schema(
{
vol.Required(
CONF_MINIMAL_ACTIVATION_DELAY, default=10
): cv.positive_int,
vol.Required(CONF_SECURITY_DELAY_MIN, default=60): cv.positive_int,
vol.Required(
CONF_SECURITY_MIN_ON_PERCENT,
default=DEFAULT_SECURITY_MIN_ON_PERCENT,
): vol.Coerce(float),
vol.Required(
CONF_SECURITY_DEFAULT_ON_PERCENT,
default=DEFAULT_SECURITY_DEFAULT_ON_PERCENT,
): vol.Coerce(float),
}
)
async def validate_input(self, data: dict) -> dict[str]:
"""Validate the user input allows us to connect.
@@ -190,6 +347,7 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
CONF_POWER_SENSOR,
CONF_MAX_POWER_SENSOR,
CONF_PRESENCE_SENSOR,
CONF_CLIMATE,
]:
d = data.get(conf, None) # pylint: disable=invalid-name
if d is not None and self.hass.states.get(d) is None:
@@ -249,9 +407,25 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
_LOGGER.debug("Into ConfigFlow.async_step_user user_input=%s", user_input)
return await self.generic_step(
"user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_tpi
"user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_type
)
async def async_step_type(self, user_input: dict | None = None) -> FlowResult:
"""Handle the flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_type user_input=%s", user_input)
if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH:
return await self.generic_step(
"type", self.STEP_THERMOSTAT_SWITCH, user_input, self.async_step_tpi
)
else:
return await self.generic_step(
"type",
self.STEP_THERMOSTAT_CLIMATE,
user_input,
self.async_step_presets,
)
async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult:
"""Handle the flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_tpi user_input=%s", user_input)
@@ -264,35 +438,63 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
"""Handle the presets flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_presets user_input=%s", user_input)
next_step = self.async_step_advanced
if self._infos[CONF_USE_WINDOW_FEATURE]:
next_step = self.async_step_window
elif self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, self.async_step_window
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, next_step
)
async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
"""Handle the window sensor flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_window user_input=%s", user_input)
next_step = self.async_step_advanced
if self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"window", self.STEP_WINDOW_DATA_SCHEMA, user_input, self.async_step_motion
"window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step
)
async def async_step_motion(self, user_input: dict | None = None) -> FlowResult:
"""Handle the window and motion sensor flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_motion user_input=%s", user_input)
next_step = self.async_step_advanced
if self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"motion", self.STEP_MOTION_DATA_SCHEMA, user_input, self.async_step_power
"motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step
)
async def async_step_power(self, user_input: dict | None = None) -> FlowResult:
"""Handle the power management flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_power user_input=%s", user_input)
next_step = self.async_step_advanced
if self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"power",
self.STEP_POWER_DATA_SCHEMA,
user_input,
self.async_step_presence,
next_step,
)
async def async_step_presence(self, user_input: dict | None = None) -> FlowResult:
@@ -303,9 +505,35 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
"presence",
self.STEP_PRESENCE_DATA_SCHEMA,
user_input,
self.async_step_advanced,
)
async def async_step_advanced(self, user_input: dict | None = None) -> FlowResult:
"""Handle the advanced parameter flow steps"""
_LOGGER.debug("Into ConfigFlow.async_step_advanced user_input=%s", user_input)
return await self.generic_step(
"advanced",
self.STEP_ADVANCED_DATA_SCHEMA,
user_input,
self.async_finalize, # pylint: disable=no-member
)
async def async_finalize(self):
"""Should be implemented by Leaf classes"""
raise HomeAssistantError(
"async_finalize not implemented on VersatileThermostat sub-class"
)
def find_all_climates(self) -> list(str):
"""Find all climate known by HA"""
component: EntityComponent[ClimateEntity] = self.hass.data[CLIMATE_DOMAIN]
ret: list(str) = list()
for entity in component.entities:
ret.append(entity.entity_id)
_LOGGER.debug("Found all climate entities: %s", ret)
return ret
class VersatileThermostatConfigFlow(
VersatileThermostatBaseConfigFlow, HAConfigFlow, domain=DOMAIN
@@ -329,16 +557,12 @@ class VersatileThermostatConfigFlow(
return self.async_create_entry(title=self._infos[CONF_NAME], data=self._infos)
class UnknownEntity(HomeAssistantError):
"""Error to indicate there is an unknown entity_id given."""
class VersatileThermostatOptionsFlowHandler(
VersatileThermostatBaseConfigFlow, OptionsFlow
):
"""Handle options flow for Versatile Thermostat integration."""
def __init__(self, config_entry: ConfigEntry):
def __init__(self, config_entry: ConfigEntry) -> None:
"""Initialize options flow."""
super().__init__(config_entry.data.copy())
self.config_entry = config_entry
@@ -364,9 +588,27 @@ class VersatileThermostatOptionsFlowHandler(
)
return await self.generic_step(
"user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_tpi
"user", self.STEP_USER_DATA_SCHEMA, user_input, self.async_step_type
)
async def async_step_type(self, user_input: dict | None = None) -> FlowResult:
"""Handle the flow steps"""
_LOGGER.debug(
"Into OptionsFlowHandler.async_step_user user_input=%s", user_input
)
if self._infos[CONF_THERMOSTAT_TYPE] == CONF_THERMOSTAT_SWITCH:
return await self.generic_step(
"type", self.STEP_THERMOSTAT_SWITCH, user_input, self.async_step_tpi
)
else:
return await self.generic_step(
"type",
self.STEP_THERMOSTAT_CLIMATE,
user_input,
self.async_step_presets,
)
async def async_step_tpi(self, user_input: dict | None = None) -> FlowResult:
"""Handle the tpi flow steps"""
_LOGGER.debug(
@@ -383,8 +625,18 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_presets user_input=%s", user_input
)
next_step = self.async_step_advanced
if self._infos[CONF_USE_WINDOW_FEATURE]:
next_step = self.async_step_window
elif self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, self.async_step_window
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, next_step
)
async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
@@ -393,8 +645,15 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_window user_input=%s", user_input
)
next_step = self.async_step_advanced
if self._infos[CONF_USE_MOTION_FEATURE]:
next_step = self.async_step_motion
elif self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"window", self.STEP_WINDOW_DATA_SCHEMA, user_input, self.async_step_motion
"window", self.STEP_WINDOW_DATA_SCHEMA, user_input, next_step
)
async def async_step_motion(self, user_input: dict | None = None) -> FlowResult:
@@ -403,8 +662,14 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_motion user_input=%s", user_input
)
next_step = self.async_step_advanced
if self._infos[CONF_USE_POWER_FEATURE]:
next_step = self.async_step_power
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"motion", self.STEP_MOTION_DATA_SCHEMA, user_input, self.async_step_power
"motion", self.STEP_MOTION_DATA_SCHEMA, user_input, next_step
)
async def async_step_power(self, user_input: dict | None = None) -> FlowResult:
@@ -413,11 +678,15 @@ class VersatileThermostatOptionsFlowHandler(
"Into OptionsFlowHandler.async_step_power user_input=%s", user_input
)
next_step = self.async_step_advanced
if self._infos[CONF_USE_PRESENCE_FEATURE]:
next_step = self.async_step_presence
return await self.generic_step(
"power",
self.STEP_POWER_DATA_SCHEMA,
user_input,
self.async_step_presence, # pylint: disable=no-member
next_step,
)
async def async_step_presence(self, user_input: dict | None = None) -> FlowResult:
@@ -430,13 +699,38 @@ class VersatileThermostatOptionsFlowHandler(
"presence",
self.STEP_PRESENCE_DATA_SCHEMA,
user_input,
self.async_finalize, # pylint: disable=no-member
self.async_step_advanced,
)
async def async_finalize(self):
"""Finalization of the ConfigEntry creation"""
async def async_step_advanced(self, user_input: dict | None = None) -> FlowResult:
"""Handle the advanced flow steps"""
_LOGGER.debug(
"CTOR ConfigFlow.async_finalize - updating entry with: %s", self._infos
"Into OptionsFlowHandler.async_step_advanced user_input=%s", user_input
)
return await self.generic_step(
"advanced",
self.STEP_ADVANCED_DATA_SCHEMA,
user_input,
self.async_end,
)
async def async_end(self):
"""Finalization of the ConfigEntry creation"""
if not self._infos[CONF_USE_WINDOW_FEATURE]:
self._infos[CONF_WINDOW_SENSOR] = None
if not self._infos[CONF_USE_MOTION_FEATURE]:
self._infos[CONF_MOTION_SENSOR] = None
if not self._infos[CONF_USE_POWER_FEATURE]:
self._infos[CONF_POWER_SENSOR] = None
self._infos[CONF_MAX_POWER_SENSOR] = None
if not self._infos[CONF_USE_PRESENCE_FEATURE]:
self._infos[CONF_PRESENCE_SENSOR] = None
_LOGGER.info(
"Recreating entry %s due to configuration change. New config is now: %s",
self.config_entry.entry_id,
self._infos,
)
self.hass.config_entries.async_update_entry(self.config_entry, data=self._infos)
return self.async_create_entry(title=None, data=None)

View File

@@ -1,5 +1,6 @@
"""Constants for the Versatile Thermostat integration."""
from enum import Enum
from homeassistant.const import CONF_NAME
from homeassistant.components.climate.const import (
# PRESET_ACTIVITY,
@@ -9,11 +10,16 @@ from homeassistant.components.climate.const import (
SUPPORT_TARGET_TEMPERATURE,
)
from homeassistant.exceptions import HomeAssistantError
from .prop_algorithm import (
PROPORTIONAL_FUNCTION_TPI,
)
PRESET_POWER = "power"
PRESET_SECURITY = "security"
HIDDEN_PRESETS = [PRESET_POWER, PRESET_SECURITY]
DOMAIN = "versatile_thermostat"
@@ -35,6 +41,20 @@ CONF_TPI_COEF_INT = "tpi_coef_int"
CONF_TPI_COEF_EXT = "tpi_coef_ext"
CONF_PRESENCE_SENSOR = "presence_sensor_entity_id"
CONF_PRESET_POWER = "power_temp"
CONF_MINIMAL_ACTIVATION_DELAY = "minimal_activation_delay"
CONF_TEMP_MIN = "temp_min"
CONF_TEMP_MAX = "temp_max"
CONF_SECURITY_DELAY_MIN = "security_delay_min"
CONF_SECURITY_MIN_ON_PERCENT = "security_min_on_percent"
CONF_SECURITY_DEFAULT_ON_PERCENT = "security_default_on_percent"
CONF_THERMOSTAT_TYPE = "thermostat_type"
CONF_THERMOSTAT_SWITCH = "thermostat_over_switch"
CONF_THERMOSTAT_CLIMATE = "thermostat_over_climate"
CONF_CLIMATE = "climate_entity_id"
CONF_USE_WINDOW_FEATURE = "use_window_feature"
CONF_USE_MOTION_FEATURE = "use_motion_feature"
CONF_USE_PRESENCE_FEATURE = "use_presence_feature"
CONF_USE_POWER_FEATURE = "use_power_feature"
CONF_PRESETS = {
p: f"{p}_temp"
@@ -81,6 +101,20 @@ ALL_CONF = (
CONF_TPI_COEF_INT,
CONF_TPI_COEF_EXT,
CONF_PRESENCE_SENSOR,
CONF_MINIMAL_ACTIVATION_DELAY,
CONF_TEMP_MIN,
CONF_TEMP_MAX,
CONF_SECURITY_DELAY_MIN,
CONF_SECURITY_MIN_ON_PERCENT,
CONF_SECURITY_DEFAULT_ON_PERCENT,
CONF_THERMOSTAT_TYPE,
CONF_THERMOSTAT_SWITCH,
CONF_THERMOSTAT_CLIMATE,
CONF_CLIMATE,
CONF_USE_WINDOW_FEATURE,
CONF_USE_MOTION_FEATURE,
CONF_USE_PRESENCE_FEATURE,
CONF_USE_POWER_FEATURE,
]
+ CONF_PRESETS_VALUES
+ CONF_PRESETS_AWAY_VALUES,
@@ -90,7 +124,24 @@ CONF_FUNCTIONS = [
PROPORTIONAL_FUNCTION_TPI,
]
CONF_THERMOSTAT_TYPES = [CONF_THERMOSTAT_SWITCH, CONF_THERMOSTAT_CLIMATE]
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE
SERVICE_SET_PRESENCE = "set_presence"
SERVICE_SET_PRESET_TEMPERATURE = "set_preset_temperature"
DEFAULT_SECURITY_MIN_ON_PERCENT = 0.5
DEFAULT_SECURITY_DEFAULT_ON_PERCENT = 0.1
class EventType(Enum):
SECURITY_EVENT: str = "versatile_thermostat_security_event"
POWER_EVENT: str = "versatile_thermostat_power_event"
TEMPERATURE_EVENT: str = "versatile_thermostat_temperature_event"
HVAC_MODE_EVENT: str = "versatile_thermostat_hvac_mode_event"
PRESET_EVENT: str = "versatile_thermostat_preset_event"
class UnknownEntity(HomeAssistantError):
"""Error to indicate there is an unknown entity_id given."""

View File

@@ -1,5 +1,4 @@
import logging
import math
_LOGGER = logging.getLogger(__name__)
@@ -21,23 +20,28 @@ class PropAlgorithm:
tpi_coef_int,
tpi_coef_ext,
cycle_min: int,
minimal_activation_delay: int,
):
"""Initialisation of the Proportional Algorithm"""
_LOGGER.debug(
"Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d",
"Creation new PropAlgorithm function_type: %s, tpi_coef_int: %s, tpi_coef_ext: %s, cycle_min:%d, minimal_activation_delay:%d",
function_type,
tpi_coef_int,
tpi_coef_ext,
cycle_min,
minimal_activation_delay,
)
# TODO test function_type, bias, cycle_min
self._function = function_type
self._tpi_coef_int = tpi_coef_int
self._tpi_coef_ext = tpi_coef_ext
self._cycle_min = cycle_min
self._minimal_activation_delay = minimal_activation_delay
self._on_percent = 0
self._calculated_on_percent = 0
self._on_time_sec = 0
self._off_time_sec = self._cycle_min * 60
self._security = False
self._default_on_percent = 0
def calculate(
self, target_temp: float, current_temp: float, ext_current_temp: float
@@ -47,7 +51,7 @@ class PropAlgorithm:
_LOGGER.warning(
"Proportional algorithm: calculation is not possible cause target_temp or current_temp is null. Heating will be disabled" # pylint: disable=line-too-long
)
self._on_percent = 0
self._calculated_on_percent = 0
else:
delta_temp = target_temp - current_temp
delta_ext_temp = (
@@ -55,7 +59,7 @@ class PropAlgorithm:
)
if self._function == PROPORTIONAL_FUNCTION_TPI:
self._on_percent = (
self._calculated_on_percent = (
self._tpi_coef_int * delta_temp
+ self._tpi_coef_ext * delta_ext_temp
)
@@ -64,7 +68,35 @@ class PropAlgorithm:
"Proportional algorithm: unknown %s function. Heating will be disabled",
self._function,
)
self._on_percent = 0
self._calculated_on_percent = 0
self._calculate_internal()
_LOGGER.debug(
"heating percent calculated for current_temp %.1f, ext_current_temp %.1f and target_temp %.1f is %.2f, on_time is %d (sec), off_time is %d (sec)", # pylint: disable=line-too-long
current_temp if current_temp else -9999.0,
ext_current_temp if ext_current_temp else -9999.0,
target_temp if target_temp else -9999.0,
self._calculated_on_percent,
self.on_time_sec,
self.off_time_sec,
)
def _calculate_internal(self):
"""Finish the calculation to get the on_percent in seconds"""
if self._security:
_LOGGER.debug(
"Security is On using the default_on_percent %f",
self._default_on_percent,
)
self._on_percent = self._default_on_percent
else:
_LOGGER.debug(
"Security is Off using the calculated_on_percent %f",
self._calculated_on_percent,
)
self._on_percent = self._calculated_on_percent
# calculated on_time duration in seconds
if self._on_percent > 1:
@@ -74,31 +106,48 @@ class PropAlgorithm:
self._on_time_sec = self._on_percent * self._cycle_min * 60
# Do not heat for less than xx sec
if self._on_time_sec < PROPORTIONAL_MIN_DURATION_SEC:
_LOGGER.debug(
"No heating period due to heating period too small (%f < %f)",
self._on_time_sec,
PROPORTIONAL_MIN_DURATION_SEC,
)
if self._on_time_sec < self._minimal_activation_delay:
if self._on_time_sec > 0:
_LOGGER.info(
"No heating period due to heating period too small (%f < %f)",
self._on_time_sec,
self._minimal_activation_delay,
)
else:
_LOGGER.debug(
"No heating period due to heating period too small (%f < %f)",
self._on_time_sec,
self._minimal_activation_delay,
)
self._on_time_sec = 0
self._off_time_sec = self._cycle_min * 60 - self._on_time_sec
_LOGGER.debug(
"heating percent calculated for current_temp %.1f, ext_current_temp %.1f and target_temp %.1f is %.2f, on_time is %d (sec), off_time is %d (sec)", # pylint: disable=line-too-long
current_temp if current_temp else -9999.0,
ext_current_temp if ext_current_temp else -9999.0,
target_temp if target_temp else -9999.0,
self._on_percent,
self.on_time_sec,
self.off_time_sec,
)
def set_security(self, default_on_percent: float):
"""Set a default value for on_percent (used for security mode)"""
self._security = True
self._default_on_percent = default_on_percent
self._calculate_internal()
def unset_security(self):
"""Unset the security mode"""
self._security = False
self._calculate_internal()
@property
def on_percent(self) -> float:
"""Returns the percentage the heater must be ON (1 means the heater will be always on, 0 never on)""" # pylint: disable=line-too-long
"""Returns the percentage the heater must be ON
In security 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
(1 means the heater will be always on, 0 never on)""" # pylint: disable=line-too-long
return round(self._calculated_on_percent, 2)
@property
def on_time_sec(self) -> int:
"""Returns the calculated time in sec the heater must be ON"""

View File

@@ -3,7 +3,6 @@ set_presence:
description: Force the presence mode in thermostat
target:
entity:
multiple: true
integration: versatile_thermostat
fields:
presence:
@@ -26,7 +25,6 @@ set_preset_temperature:
description: Change the target temperature of a preset
target:
entity:
multiple: true
integration: versatile_thermostat
fields:
preset:

View File

@@ -8,11 +8,25 @@
"description": "Main mandatory attributes",
"data": {
"name": "Name",
"heater_entity_id": "Heater entity id",
"thermostat_type": "Thermostat type",
"temperature_sensor_entity_id": "Temperature sensor entity id",
"external_temperature_sensor_entity_id": "External temperature sensor entity id",
"cycle_min": "Cycle duration (minutes)",
"proportional_function": "Algorithm to use (TPI is the only one for now)"
"temp_min": "Minimal temperature allowed",
"temp_max": "Maximal temperature allowed",
"use_window_feature": "Use window detection",
"use_motion_feature": "Use motion detection",
"use_power_feature": "Use power management",
"use_presence_feature": "Use presence detection"
}
},
"type": {
"title": "Linked entity",
"description": "Linked entity attributes",
"data": {
"heater_entity_id": "Heater entity id",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"climate_entity_id": "Underlying thermostat entity id"
}
},
"tpi": {
@@ -69,6 +83,16 @@
"comfort_away_temp": "Temperature in Comfort preset when no presence",
"boost_away_temp": "Temperature in Boost preset when no presence"
}
},
"advanced": {
"title": "Advanced parameters",
"description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.",
"data": {
"minimal_activation_delay": "Delay in secondes under which the equipment will not be activated",
"security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state",
"security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of on_percent the thermostat won't go into security preset",
"security_default_on_percent": "The default heating percent value in security preset. Set to 0 to switch off heater in security present"
}
}
},
"error": {
@@ -87,11 +111,25 @@
"description": "Main mandatory attributes",
"data": {
"name": "Name",
"heater_entity_id": "Heater entity id",
"thermostat_type": "Thermostat type",
"temperature_sensor_entity_id": "Temperature sensor entity id",
"external_temperature_sensor_entity_id": "External temperature sensor entity id",
"cycle_min": "Cycle duration (minutes)",
"proportional_function": "Algorithm to use (TPI is the only one for now)"
"temp_min": "Minimal temperature allowed",
"temp_max": "Maximal temperature allowed",
"use_window_feature": "Use window detection",
"use_motion_feature": "Use motion detection",
"use_power_feature": "Use power management",
"use_presence_feature": "Use presence detection"
}
},
"type": {
"title": "Linked entity",
"description": "Linked entity attributes",
"data": {
"heater_entity_id": "Heater entity id",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"climate_entity_id": "Underlying thermostat entity id"
}
},
"tpi": {
@@ -148,6 +186,16 @@
"comfort_away_temp": "Temperature in Comfort preset when no presence",
"boost_away_temp": "Temperature in Boost preset when no presence"
}
},
"advanced": {
"title": "Advanced parameters",
"description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.",
"data": {
"minimal_activation_delay": "Delay in secondes under which the equipment will not be activated",
"security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a security off state",
"security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of on_percent the thermostat won't go into security preset",
"security_default_on_percent": "The default heating percent value in security preset. Set to 0 to switch off heater in security present"
}
}
},
"error": {
@@ -157,5 +205,39 @@
"abort": {
"already_configured": "Device is already configured"
}
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"state_attributes": {
"preset_mode": {
"state": {
"power": "Shedding",
"security": "Security",
"none": "Manual"
}
}
}
}
}
},
"state_attributes": {
"_": {
"preset_mode": {
"state": {
"power": "Shedding",
"security": "Security",
"none": "Manual"
}
}
}
}
}

View File

@@ -8,11 +8,25 @@
"description": "Main mandatory attributes",
"data": {
"name": "Name",
"heater_entity_id": "Heater entity id",
"thermostat_type": "Thermostat type",
"temperature_sensor_entity_id": "Temperature sensor entity id",
"external_temperature_sensor_entity_id": "External temperature sensor entity id",
"cycle_min": "Cycle duration (minutes)",
"proportional_function": "Algorithm to use (TPI is the only one for now)"
"temp_min": "Minimal temperature allowed",
"temp_max": "Maximal temperature allowed",
"use_window_feature": "Use window detection",
"use_motion_feature": "Use motion detection",
"use_power_feature": "Use power management",
"use_presence_feature": "Use presence detection"
}
},
"type": {
"title": "Linked entity",
"description": "Linked entity attributes",
"data": {
"heater_entity_id": "Heater entity id",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"climate_entity_id": "Underlying thermostat entity id"
}
},
"tpi": {
@@ -69,6 +83,16 @@
"comfort_away_temp": "Temperature in Comfort preset when no presence",
"boost_away_temp": "Temperature in Boost preset when no presence"
}
},
"advanced": {
"title": "Advanced parameters",
"description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.",
"data": {
"minimal_activation_delay": "Delay in secondes under which the equipment will not be activated",
"security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state",
"security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of on_percent the thermostat won't go into security preset",
"security_default_on_percent": "The default heating percent value in security preset. Set to 0 to switch off heater in security present"
}
}
},
"error": {
@@ -87,11 +111,25 @@
"description": "Main mandatory attributes",
"data": {
"name": "Name",
"heater_entity_id": "Heater entity id",
"thermostat_type": "Thermostat type",
"temperature_sensor_entity_id": "Temperature sensor entity id",
"external_temperature_sensor_entity_id": "External temperature sensor entity id",
"cycle_min": "Cycle duration (minutes)",
"proportional_function": "Algorithm to use (TPI is the only one for now)"
"temp_min": "Minimal temperature allowed",
"temp_max": "Maximal temperature allowed",
"use_window_feature": "Use window detection",
"use_motion_feature": "Use motion detection",
"use_power_feature": "Use power management",
"use_presence_feature": "Use presence detection"
}
},
"type": {
"title": "Linked entity",
"description": "Linked entity attributes",
"data": {
"heater_entity_id": "Heater entity id",
"proportional_function": "Algorithm to use (TPI is the only one for now)",
"climate_entity_id": "Underlying thermostat entity id"
}
},
"tpi": {
@@ -148,6 +186,16 @@
"comfort_away_temp": "Temperature in Comfort preset when no presence",
"boost_away_temp": "Temperature in Boost preset when no presence"
}
},
"advanced": {
"title": "Advanced parameters",
"description": "Configuration of advanced parameters. Leave the default values if you don't know what you are doing.\nThis parameters can lead to a very bad temperature or power regulation.",
"data": {
"minimal_activation_delay": "Delay in secondes under which the equipment will not be activated",
"security_delay_min": "Maximum allowed delay in minutes between two temperature mesures. Above this delay, the thermostat will turn to a sceurity off state",
"security_min_on_percent": "Minimal heating percent value for security preset activation. Below this amount of on_percent the thermostat won't go into security preset",
"security_default_on_percent": "The default heating percent value in security preset. Set to 0 to switch off heater in security present"
}
}
},
"error": {
@@ -157,5 +205,39 @@
"abort": {
"already_configured": "Device is already configured"
}
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat over a switch",
"thermostat_over_climate": "Thermostat over another thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"state_attributes": {
"preset_mode": {
"state": {
"power": "Shedding",
"security": "Security",
"none": "Manual"
}
}
}
}
}
},
"state_attributes": {
"_": {
"preset_mode": {
"state": {
"power": "Shedding",
"security": "Security",
"none": "Manual"
}
}
}
}
}

View File

@@ -8,11 +8,24 @@
"description": "Principaux attributs obligatoires",
"data": {
"name": "Nom",
"heater_entity_id": "Radiateur entity id",
"temperature_sensor_entity_id": "Température sensor entity id",
"external_temperature_sensor_entity_id": "Temperature exterieure sensor entity id",
"cycle_min": "Durée du cycle (minutes)",
"proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)"
"temp_min": "Température minimale permise",
"temp_max": "Température maximale permise",
"use_window_feature": "Avec détection des ouvertures",
"use_motion_feature": "Avec détection de mouvement",
"use_power_feature": "Avec gestion de la puissance",
"use_presence_feature": "Avec détection de présence"
}
},
"type": {
"title": "Entité liée",
"description": "Attributs de l'entité liée",
"data": {
"heater_entity_id": "Radiateur entity id",
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
"climate_entity_id": "Thermostat sous-jacent entity id"
}
},
"tpi": {
@@ -69,6 +82,16 @@
"comfort_away_temp": "Température en preset Comfort en cas d'absence",
"boost_away_temp": "Température en preset Boost en cas d'absence"
}
},
"advanced": {
"title": "Parameters avancés",
"description": "Configuration des paramètres avancés. Laissez les valeurs par défaut si vous ne savez pas ce que vous faites.\nCes paramètres peuvent induire des mauvais comportements du thermostat.",
"data": {
"minimal_activation_delay": "Délai en secondes en-dessous duquel l'équipement ne sera pas activé",
"security_delay_min": "Délai maximal autorisé en minutes entre 2 mesures de températures. Au-dessus de ce délai, le thermostat se mettra en position éteinte de sécurité",
"security_min_on_percent": "Seuil minimal de pourcentage de chauffage en-dessous duquel le préréglage sécurité ne sera jamais activé",
"security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité"
}
}
},
"error": {
@@ -87,11 +110,26 @@
"description": "Principaux attributs obligatoires",
"data": {
"name": "Nom",
"heater_entity_id": "Radiateur entity id",
"thermostat_over_switch": "Thermostat sur un switch",
"thermostat_over_climate": "Thermostat sur un autre thermostat",
"temperature_sensor_entity_id": "Température sensor entity id",
"external_temperature_sensor_entity_id": "Temperature exterieure sensor entity id",
"cycle_min": "Durée du cycle (minutes)",
"proportional_function": "Algorithm à utiliser (Seul TPI est disponible pour l'instant)"
"temp_min": "Température minimale permise",
"temp_max": "Température maximale permise",
"use_window_feature": "Avec détection des ouvertures",
"use_motion_feature": "Avec détection de mouvement",
"use_power_feature": "Avec gestion de la puissance",
"use_presence_feature": "Avec détection de présence"
}
},
"type": {
"title": "Entité liée",
"description": "Attributs de l'entité liée",
"data": {
"heater_entity_id": "Radiateur entity id",
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
"climate_entity_id": "Thermostat sous-jacent entity id"
}
},
"tpi": {
@@ -148,6 +186,16 @@
"comfort_away_temp": "Température en preset Comfort en cas d'absence",
"boost_away_temp": "Température en preset Boost en cas d'absence"
}
},
"advanced": {
"title": "Parameters avancés",
"description": "Configuration des paramètres avancés. Laissez les valeurs par défaut si vous ne savez pas ce que vous faites.\nCes paramètres peuvent induire des mauvais comportements du thermostat.",
"data": {
"minimal_activation_delay": "Délai en seondes en-dessous duquel l'équipement ne sera pas activé",
"security_delay_min": "Délai maximal autorisé en minutes entre 2 mesures de températures. Au-dessus de ce délai, le thermostat se mettra en position éteinte de sécurité",
"security_min_on_percent": "Seuil minimal de pourcentage de chauffage en-dessous duquel le préréglage sécurité ne sera jamais activé",
"security_default_on_percent": "Valeur par défaut pour le pourcentage de chauffage en mode sécurité. Mettre 0 pour éteindre le radiateur en mode sécurité"
}
}
},
"error": {
@@ -157,5 +205,39 @@
"abort": {
"already_configured": "Le device est déjà configuré"
}
},
"selector": {
"thermostat_type": {
"options": {
"thermostat_over_switch": "Thermostat sur un switch",
"thermostat_over_climate": "Thermostat sur un autre thermostat"
}
}
},
"entity": {
"climate": {
"versatile_thermostat": {
"state_attributes": {
"preset_mode": {
"state": {
"power": "Délestage",
"security": "Sécurité",
"none": "Manuel"
}
}
}
}
}
},
"state_attributes": {
"_": {
"preset_mode": {
"state": {
"power": "Délestage",
"security": "Sécurité",
"none": "Manuel"
}
}
}
}
}

BIN
images/config-advanced.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
images/config-presence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB