Encore un routeur solaire

Pour un chauffe eau à thermostat mécanique uniquement
{.is-warning}

J’ai des panneaux solaires, et parfois, ils produisent plus que ce que je consomme.

Idée : injecter le surplus dans mon eau chaude sanitaire.

Prospection et choix d’une solution

Au départ je louchais sur des projets comme l’excellentissime F1ATB. Sauf que moi j’ai déjà un système domotique plutôt élaboré qui détient déjà toutes les infos pour prendre les décisions que prend l’esp32 dans le projet F1ATB. Donc j’ai gardé la partie matos du projet (le strict minimum) et je me suis chargé du reste :

  • l’esp32 ne gère que la puissance injectée au chauffe eau avec son triac, ce n’est pas le cerveau, c’est juste un accionneur. On lui fournit un poucentage de puissance et il obéit.
  • HA collecte les données de consommation côté compteur (j’ai un appareil qui fait ça à peu près à la seconde), calcule ce qui doit être envoyé au chauffe eau et actionne l’esp32 en conséquence.

En plus mon compteur est dans le paninter à côté du portail et mon chauffe eau est dans les combles au dessus de la salle de bain, ni l’un ni l’autre ne sont à côté du tableau alors tout piloter en un seul point (mesure, cerveau, commande) est un peu illusoire chez moi.

Avantages :

  • avoir accès à toute la richesse des automatisations HA pour piloter son chauffe eau de façon simple.
  • un système domotique qui contrôle tout : le cerveau de la maison.
  • intégration native de tout le matos compatible HA

Inconvénients :

  • moins bonne réactivité en cas de changements rapides et fréquents d’appel de puissance, et encore, sauf si la mesure est directement reliée à HA.
  • il faut avoir un home assistant

Bref, je ne dis pas que ma solution est meilleure, je dis que c’est celle qui me va le mieux dans mon contexte.

Matos

Le même qu’ICI

  • un esp32
  • un triac
  • un radiateur/dissipateur, une boite, une alim, de la colle, un fer à souder…etc…

Je passe sur la phase d’assemblage soudage, c’est très bien documenté sur le site F1ATB. Moi je n’ai gardé que le strict minimum : esp32 + triac.

Et pour la programmation : esphome !

esphome

Un GPIO pour le signal ZC, un autre pour piloter le triac, un input number pour passer la consigne et… c’est tout.

esphome:
  name: "boiler-dimmer"
  friendly_name: Boiler Dimmer

esp32:
  board: esp32dev
  framework:
    type: arduino
#    version: 5.4.0 # ça c'est parce qu'une des versions récentes d'esphome buguait, maintenant ça remarche

# Enable logging
logger:
#   level: INFO

# Enable Home Assistant API
api:
  encryption:
    key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

ota:
  - platform: esphome
    password: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "XXXXXXXXXXXXXXXXXXXXXX"
    password: "XXXXXXXXXXXXXXX"
  
  use_address: 192.168.x.y # parce que mes IOT ont un réseau à part, alors je précise l'IP ici

## Si on veut le piloter directement dans une page web
#web_server:
#  ota: False
#  log: False
#  local: True
#  version: 3

captive_portal:

output:
  - platform: ac_dimmer
    id: triac_chauffe_eau
    gate_pin: GPIO14
    zero_cross_pin: 
      number: GPIO12
      mode: INPUT_PULLUP # Crucial pour la stabilité du signal Z-C
    min_power: 0%
    max_power: 100%

# On utilise un "number" ou "sensor" pour piloter finement la puissance
number:
  - platform: template
    name: "Puissance Chauffe-Eau"
    id: puissance_chauffe_eau
    min_value: 0
    max_value: 100
    step: 1
    unit_of_measurement: "%"
    optimistic: true
    set_action:
      then:
        - output.set_level:
            id: triac_chauffe_eau
            level: !lambda "return x / 100.0;"

# Capteur de diagnostic
sensor:
  - platform: wifi_signal
    name: "Signal WiFi ESP commande chauffe-eau"
    update_interval: 60s

Automatisations

quelques variables

Celles qui doivent être créées mais qui sont gérées automatiquement :

  • input_boolean.forcer_chauffe_eau : pour passer le chauffe en marche forcée (ou pour utiliser les heures creuses…)
  • input_number.target_chauffe_eau : valeur numérique calculée à envoyer à l’esp32

Celle qu’il faut créer et renseigner :

  • input_number.puissance_max_chauffe_eau : une valeur à définir selon son propre chauffe eau

mise à jour de la cible à atteindre : input_number.target_chauffe_eau

Quand la mesure de puissance change (à peu près toutes les secondes), cet automate enclenche le calcul du % de puissance à appliquer.

alias: Update target chauffe eau
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.my_sonoff_powct_power_a # c'est mon energy meter, chacun mettra le sien.
conditions: []
actions:
  - action: script.set_target_chauffe_eau
    metadata: {}
    data: {}
mode: single

Et le script de calcul associé : sa logique est simple, calculer la valeur optimale pour maintenir une faible consommation du réseau, de l’ordre d’1% de la puissance totale du chauffe eau pour injecter le moins possible. Stocker cette valeur dans input_number.target_chauffe_eau

sequence:
  - if:
      - condition: state
        entity_id: input_boolean.forcer_chauffe_eau
        state:
          - "on"
    then:
      - action: input_number.set_value
        metadata: {}
        target:
          entity_id: input_number.target_chauffe_eau
        data:
          value: 100
    else:
      - action: input_number.set_value
        metadata: {}
        target:
          entity_id: input_number.target_chauffe_eau
        data:
          value: >
            {% set current = states('input_number.target_chauffe_eau') | float
            %} {% set puissance_max =
            states('input_number.puissance_max_chauffe_eau') | float %} {% set
            puissance_compteur = states('sensor.my_sonoff_powct_power_a') |
            float %} {% set un_pourcent = puissance_max / 100 %}

            {% if puissance_compteur < 0 %}
              {% set injection = puissance_compteur | abs %}
              {% set x = injection / un_pourcent %}
              {% set n = (x + 1) | int %}
              {{ [current + n, 100] | min }}
            {% elif puissance_compteur > un_pourcent %}
              {% set reduction = (puissance_compteur / un_pourcent) | int %}
              {{ [current - reduction, 0] | max }}
            {% else %}
              {{ current }}
            {% endif %}
alias: Set Target chauffe eau
description: ""

injection de la cible calculée vers l’esp32

Quand la valeur de input_number.target_chauffe_eau change (automate précédent), cet automate actualise la consigne vers l’esp32.

alias: Set target to triac on target change
description: ""
triggers:
  - trigger: state
    entity_id:
      - input_number.target_chauffe_eau
  - trigger: homeassistant
    event: start
conditions: []
actions:
  - data:
      value: "{{ states('input_number.target_chauffe_eau') | float }}"
    action: number.set_value
    target:
      entity_id: number.boiler_dimmer_puissance_chauffe_eau
mode: single

Conclusion

Selon moi, c’est beaucoup plus simple et beaucoup plus modulaire. Avantage, j’ai d’autres automatisations/script (gestion heures creuses, marche forcée) qui viennent se brancher dessus et tout roucoule tranquillou :slight_smile: Et d’autres sont à venir, par exemple : 5 mesures de température sur toute la hauteur du chauffe eau pour évaluer la quantité d’eau chaude et prévoir une marche forcée pendant les heures creuses si nécessaire. J’aurais juste à créer un module en plus qui viendra se brancher dessus. Une architecture modulaire et évolutive sans devoir tout reprendre à chaque étape :slight_smile: