Naissance d’une nouvelle intégration pour optimiser vos productions solaire. Elle est en tests depuis 2 semaines maintenant chez moi et comme elle marche bien, je me propose de vous en faire profiter.
Attention : elle est encore très jeune donc peut être pas parfaite.
Vos retours seront précieux pour faire avancer ce partage.
Elle est dispo ici (et sous HACS) : GitHub - jmcollin78/solar_optimizer: The Solar Optimizer integration for Home Assistant starts and stops your equipments depending on the Solar net production
Cette intégration permet d’optimiser l’utilisation de votre énergie solaire. Elle commande l’allumage et l’extinction de vos équipements dont l’activation est différable dans le temps en fonction de la production et de la consommation électrique courante.
- Qu’est-ce que Solar Optimizer ?
- Comment fonctionne-t-elle ?
- Comment on l’installe ?
- La configuration
- Entités disponibles
- En complément
- Les contributions sont les bienvenues !
Nouveautés
- release 1.3.0 :
- ajout du paramètre
duration_stop_min
qui permet de spécifier une durée minimale de désactivation pour le distinguer du délai minimal d’activationduration_min
. Si non spécifié, ce paramètre prend la valeur deduration_min
.- restaure l’état des switchs
enable
au démarrage de l’intégration.- lance un calcul immédiatement après le démarrage de Home Assistant
- release 1.0 : première version opérationnelle. Commande d’équipements basés sur des switchs, commande de puissance (Tesla) et paramétrage via configuration.yaml.
Qu’est-ce que Solar Optimizer ?
Cette intégration va vous permettre de maximiser l’utilisation de votre production solaire. Vous lui déléguez le contrôle de vos équipements dontl’activation peut être différée dans le temps (chauffe-eau, pompe de piscine, charge de véhicle électrique, lave-vaisselle, lave-linge, etc) et elle s’occupe de les lancer lorsque la puissance produite est suffisante.
Elle tente en permanence de minimiser l’import et l’export d’énergie en démarrant, stoppant, modifiant la puissance allouée à un équipement.
2 types d’équipements sont gérés :
- les équipements commandés par un switch (un service d’une manière générale) qui ont une puissance consommée fixe et pré-déterminée,
- les équipements dont la puissance de consommation est réglable (Tesla, Robotdyn). En réglant la puissance allouée à ces équipements, Solar Optimizer aligne la consommation sur la production au plus près.
L’idéal est d’avoir au moins un équipement dont la puissance est ajustable dans la liste des équipements gérés par Solar Optimizer.
Comment fonctionne-t-elle ?
Le fonctionnement est le suivant :
- à interval régulier (paramétrable), l’algorithme simule des modifications des états des équipements (allumé / éteint / puissance allouée) et calcule un coût de cette configuration. Globalement le coût est le
a * puissance_importée + b * puissance_exportée
. La coefficients a et b sont calculés en fonction du cout de l’électricité au moment du calcul, - l’algorithme garde la meilleure configuration (celle qui a un cout minimum) et cherche d’autres solutions, jusqu’à ce qu’un minimum soit atteint.
- la meilleure configuration est alors appliquée.
L’algorithme utilisé est un algorithme de type recuit simulé dont vous trouverez une description ici : Recuit simulé — Wikipédia
Anti-bagot
Pour éviter les effets de bagottements d’un cycle à l’autre, un délai minimal d’activation est paramétrable par équipements. Par exemple : un chauffe-eau doit être activé au moins une heure pour que l’allumage soit utile, la charge d’une voiture électrique doit durer au moins deux heures, …
Utilisabilité
A chaque équipement configuré est associé une entité de type switch qui permet d’autoriser l’algorithme à utiliser l’équipement. Si je veux forcer la chauffe du ballon d’eau chauffe, je mets son switch sur off. L’algorithme ne le regardera donc pas, le chauffe-eau repasse en manuel, non géré par Solar Optimizer.
Par ailleurs, il est possible de définir une règle d’utilisabilité des équipements. Par exemple, si la voiture est chargée à plus de 90%, l’algorithme considère que l’équipement qui pilote la charge de la voiture doit être éteint. Cette régle est définit sous la forme d’un template configurable qui vaut True si l’équipement est utilisable.
Ces 2 règles permettent à l’algorithme de ne commander que ce qui est réellement utile à un instant t. Ces règles sont ré-évaluées à chaque cycle.
Comment on l’installe ?
HACS installation (recommendé)
- Installez HACS. De cette façon, vous obtenez automatiquement les mises à jour.
- Ajoutez ce repository Github en tant que repository personnalisé dans les paramètres HACS.
- recherchez et installez « Solar Optimizer » dans HACS et cliquez sur « installer ».
- Redémarrez Home Assistant.
- Ensuite, vous pouvez ajouter l’intégration de Solar Optimizer dans la page d’intégration. Vous ne pouvez installer qu’une seule intégration Solar Optimizer.
Installation manuelle
Une installation manuelle est possible. Elle n’est pas recommandée et donc elle ne sera pas décrite ici.
La configuration
Configurer l’intégration
Lors de l’ajout de l’intégration Solar Optimizer, la page de paramétrage suivante s’ouvre :
Vous devez spécifier :
- le sensor qui donne la consommation nette instantanée du logement (elle doit être négative si la production dépasse la consommation). Ce chiffre est indiqué en Watt,
- le sensor qui donne la production photovoltaïque instantanée en Watt aussi,
- un sensor ou input_number qui donne le cout du kwh importée,
- un sensor ou input_number qui donne le prix du kwh exortée (dépend de votre contrat),
- un sensor ou input_number qui donne la taxe applicable sur les kwh exortée (dépend de votre contrat)
Ces 5 informations sont nécessaires à l’algorithme pour fonctionner, elles sont donc toutes obligatoires. Le fait que ce soit des sensor ou input_number permet d’avoir des valeurs qui sont réévaluées à chaque cycle. En conséquence le passage en heure creuse peut modifier le calcul et donc les états des équipements puisque l’import devient moins cher. Donc tout est dynamique et recalculé à chaque cycle.
Configurer les équipements
Les équipements pilotables sont définis dans le fichier configuration.yaml de la façon suivante :
-
ajouter la ligne suivante dans votre configuration.yaml:
solar_optimizer: !include solar_optimizer.yaml
-
et créez un fichier au même niveau que le configuration.yaml avec les informations suivantes :
algorithm:
initial_temp: 1000
min_temp: 0.1
cooling_factor: 0.95
max_iteration_number: 1000
devices:
- name: "<nom de l'équipement>"
entity_id: "switch.xxxxx"
power_max: <puissance max consommée>
check_usable_template: "{{ <le template qui vaut True si l'équipement est utilisable> }}"
duration_min: <la durée minimale d'activation en minutes>
duration_stop_min: <la durée minimale de desactivation en minutes>
action_mode: "service_call"
activation_service: "<service name>
deactivation_service: "switch/turn_off"
Note: les paramètres sous algorithm
ne doivent pas être touchés sauf si vous savez exactement ce que vous faites.
Sous devices
il faut déclarer tous les équipements qui seront commandés par Solar Optimizer de la façon suivante :
attribut | valable pour | signification | exemple | commentaire |
---|---|---|---|---|
name |
tous | Le nom de l’équipement | « VMC sous-sol » | - |
entity_id |
tous | l’entity id de l’équipement à commander | « switch.vmc_sous_sol » | - |
power_max |
tous | la puissance maximale consommée par l’équipement | 250 | - |
check_usable_template |
tous | Un template qui vaut True si l’équipement pourra être utilisé par Solar Optimizer | « {{ is_state(‹ cover.porte_garage_garage ›, ‹ closed ›) }} » | Dans l’exemple, Sonar Optimizer n’essayera pas de commander la « VMC sous-sol » si la porte du garage est ouverte |
duration_min |
tous | La durée en minute minimale d’activation | 60 | La VMC sous-sol s’allumera toujours pour une heure au minimum |
duration_stop_min |
tous | La durée en minute minimale de desactivation. Vaut duration_min si elle n’est pas précisée |
15 | La VMC sous-sol s’éteindra toujours pour 15 min au minimum |
action_mode |
tous | le mode d’action pour allumer ou éteindre l’équipement. Peut être « service_call » ou « event » (*) | « service_call » | « service_call » indique que l’équipement s’allume et s’éteint via un appel de service. Cf. ci-dessous. « event » indique qu’un évènement est envoyé lorsque l’état doit changer. Cf. (*) |
activation_service |
uniquement si action_mode=« service_call » | le service a appeler pour activer l’équipement sous la forme « domain/service » | « switch/turn_on » | l’activation déclenchera le service « switch/turn_on » sur l’entité « entity_id » |
deactivation_service |
uniquement si action_mode=« service_call » | le service a appeler pour désactiver l’équipement sous la forme « domain/service » | « switch/turn_off » | la désactivation déclenchera le service « switch/turn_off » sur l’entité « entity_id » |
Pour les équipements à puissance variable, les attributs suivants doivent être valorisés :
attribut | valable pour | signification | exemple | commentaire |
---|---|---|---|---|
power_entity_id |
équipement à puissance variable | l’entity_id de l’entité gérant la puissance | number.tesla_charging_amps |
Le changement de puissance se fera par un appel du service change_power_service sur cette entité |
power_min |
équipement a puissance variable | La puissance minimale en watt de l’équipement | 100 | Lorsque la consigne de puissance passe en dessous de cette valeur, l’équipement sera éteint par l’appel du deactivation_service |
power_step |
équipement a puissance variable | Le pas de puissance | 10 | - |
change_power_service |
équipement a puissance variable | Le service a appelé pour changer la puissance | "number/set_value" |
- |
convert_power_divide_factor |
équipement a puissance variable | Le diviseur a appliquer pour convertir la puissance en valeur | 50 | Dans l’exemple, le service « number/set_value » sera appelé avec la consigne de puissance / 50 sur l’entité entity_id |
Exemple complet et commenté de la partie device :
devices:
- name: "Pompe réservoir"
# Le switch qui commande la pompe du réservoir
entity_id: "switch.prise_pompe_reservoir"
# la puissance de cette pompe
power_max: 170
# Toujours utilisable
# check_usable_template: "{{ True }}"
# 15 min d'activation minimum
duration_min: 15
# On active/desactive via un appel de service
action_mode: "service_call"
# Le service permettant d'activer le switch
activation_service: "switch/turn_on"
# Le service permettant de désactiver le switch
deactivation_service: "switch/turn_off"
- name: "Recharge Tesla"
entity_id: "switch.cloucloute_charger"
# La puissance minimale de charge est 660 W (soit 1 Amp car convert_power_divide_factor=660 aussi)
power_min: 660
# La puissance minimale de charge est 3960 W (soit 5 Amp (= 3960/600) )
power_max: 3960
# le step de 660 soit 1 Amp après division par convert_power_divide_factor
power_step: 660
# Utilisable si le mode de charge est "Solaire" et la voiture est branchée sur le chargeur et elle est chargée à moins de 90 % (donc ca s'arrête tout seul à 90% )
check_usable_template: "{{ is_state('input_select.charge_mode', 'Solaire') and is_state('binary_sensor.tesla_wall_connector_vehicle_connected', 'on') and is_state('binary_sensor.tesla_charger', 'on') and states('sensor.tesla_battery') | float(100) < states('number.cloucloute_charge_limit') | float(90) }}"
# 1 h de charge minimum
duration_min: 60
# 15 min de stop charge minimum
duration_stop_min: 15
# L'entité qui pilote l'ampérage de charge
power_entity_id: "number.tesla_charging_amps"
# 5 min minimum entre 2 changements de puissance
duration_power_min: 5
# l'activation se fait par un appel de service
action_mode: "service_call"
activation_service: "switch/turn_on"
deactivation_service: "switch/turn_off"
# le changement de puissance se fait par un appel de service
change_power_service: "number/set_value"
# le facteur permettant de convertir la puissance consigne en Ampères (number.tesla_charging_amps prend des Ampères)
convert_power_divide_factor: 660
...
Tout changement dans la configuration nécessite un arrêt / relance de l’intégration (ou de Home Assistant) pour être pris en compte.
Entités disponibles
L’intégration, une fois correctement configurée, créée un appareil (device) qui contient plusieurs entités :
- un sensor nommé « total_power » qui est le total de toutes les puissances des équipements commandés par Solar Optimizer,
- un sensor nommé « best_objective » qui est la valeur de la fonction de coût (cf. fonctionnement de l’algo),
- un switch par équipements nommé
switch.enable_solar_optimize_<name>
déclarés dans le configuration.yaml. Si le switch est « Off », l’algorithme ne considérera pas cet équipement pour le calcul. Ca permet de manuellement sortir un équipement de la liste sans avoir à modifier la liste. Ce switch contient des attributs additionnels qui permettent de suivre l’état interne de l’équipement vu de l’algorithme.
En complément
En complément, le code Lovelace suivant permet de controller chaque équipement déclaré :
# A mettre en début de page
decluttering_templates:
managed_device_power:
default: null
card:
type: custom:expander-card
expanded: false
title-card-button-overlay: true
title-card:
type: custom:mushroom-template-card
primary: "{{ state_attr('[[device]]', 'friendly_name') }}"
secondary: "[[secondary_infos]]"
icon: "[[icon]]"
badge_icon: >-
{% if is_state_attr('[[device]]','is_enabled', True) %}mdi:check{%
else %}mdi:cancel{% endif %}
badge_color: >-
{% if is_state_attr('[[device]]', 'is_usable', True) and
is_state_attr('[[device]]', 'is_enabled', True) %}green {% elif
is_state_attr('[[device]]', 'is_enabled', False) %}red {% elif
is_state_attr('[[device]]','is_waiting', True) %}orange {% elif
is_state_attr('[[device]]', 'is_usable', False) or
state_attr('[[device]]', 'is_usable') is none %}#A0B0FF{% else
%}blue{% endif %}
entity: "[[device]]"
icon_color: >-
{% if is_state('[[device]]', 'on')%}orange{% else %}lightgray{% endif
%}
tap_action:
action: toggle
hold_action:
action: more-info
double_tap_action:
action: none
cards:
- type: custom:mushroom-chips-card
chips:
- type: entity
entity: "[[enable_entity]]"
double_tap_action:
action: more-info
tap_action:
action: toggle
hold_action:
action: more-info
icon_color: green
content_info: name
- type: markdown
content: >-
**Prochaine dispo** : {{ ((as_timestamp(state_attr('[[device]]',
'next_date_available')) - as_timestamp(now())) / 60) | int }}
min<br> **Prochaine dispo puissance**: {{
((as_timestamp(state_attr('[[device]]',
'next_date_available_power')) - as_timestamp(now())) / 60) | int }}
min<br> **Utilisable** : {{ state_attr('[[device]]', 'is_usable')
}}<br> **Est en attente** : {{ state_attr('[[device]]',
'is_waiting') }}<br> **Puissance requise** : {{
state_attr('[[device]]', 'requested_power') }} W<br> **Puissance
courante** : {{ state_attr('[[device]]', 'current_power') }} W
title: Infos
managed_device:
default: null
card:
type: custom:expander-card
expanded: false
title-card-button-overlay: true
title-card:
type: custom:mushroom-template-card
primary: "{{ state_attr('[[device]]', 'friendly_name') }}"
secondary: >-
[[secondary_infos]] (max. {{ state_attr('[[device]]', 'power_max') }}
W)
icon: "[[icon]]"
badge_icon: >-
{% if is_state_attr('[[device]]','is_enabled', True) %}mdi:check{%
else %}mdi:cancel{% endif %}
badge_color: >-
{% if is_state_attr('[[device]]', 'is_usable', True) and
is_state_attr('[[device]]', 'is_enabled', True) %}green {% elif
is_state_attr('[[device]]', 'is_enabled', False) %}red {% elif
is_state_attr('[[device]]','is_waiting', True) %}orange {% elif
is_state_attr('[[device]]', 'is_usable', False) or
state_attr('[[device]]', 'is_usable') is none %}#A0B0FF{% else
%}blue{% endif %}
entity: "[[device]]"
icon_color: >-
{% if is_state('[[device]]', 'on')%}orange{% else %}lightgray{% endif
%}
tap_action:
action: toggle
hold_action:
action: more-info
double_tap_action:
action: none
cards:
- type: custom:mushroom-chips-card
chips:
- type: entity
entity: "[[enable_entity]]"
double_tap_action:
action: more-info
tap_action:
action: toggle
hold_action:
action: more-info
icon_color: green
content_info: name
- type: markdown
content: >-
**Prochaine dispo** : {{ ((as_timestamp(state_attr('[[device]]',
'next_date_available')) - as_timestamp(now())) / 60) | int }}
min<br> **Utilisable** : {{ state_attr('[[device]]', 'is_usable')
}}<br> **Est en attente** : {{ state_attr('[[device]]',
'is_waiting') }}<br> **Puissance requise** : {{
state_attr('[[device]]', 'requested_power') }} W<br> **Puissance
courante** : {{ state_attr('[[device]]', 'current_power') }} W
enable_template:
default: null
card:
type: custom:mushroom-chips-card
chips:
- type: entity
entity: '[[enable_entity]]'
double_tap_action:
action: more-info
tap_action:
action: toggle
hold_action:
action: more-info
icon_color: green
content_info: none
puis à utiliser de la façon suivante :
- type: vertical-stack
cards:
- type: custom:decluttering-card
template: managed_device_power
variables:
- device: switch.solar_optimizer_recharge_tesla
- secondary_infos: >-
{{ states('sensor.total_puissance_instantanee_twc_w') }} W
({{ states('number.tesla_charging_amps')}} A)
- icon: mdi:ev-station
- enable_entity: switch.enable_solar_optimizer_recharge_tesla
- type: custom:decluttering-card
template: managed_device
variables:
- device: switch.solar_optimizer_prise_recharge_voiture_garage
- secondary_infos: '{{ states(''sensor.prise_garage_voiture_power'') }} W'
- icon: mdi:power-socket-fr
- enable_entity: >-
switch.enable_solar_optimizer_prise_recharge_voiture_garage
Vous obtiendrez alors un composant permettant d’interagir avec l’équipement qui ressemble à ça :
Les contributions sont les bienvenues !
Si vous souhaitez contribuer, veuillez lire les directives de contribution