Je domotiser ma consommation d’eau

Cet article fait suite au précédent article :

J’ai souhaité remplacer un D1 Mini par un D1 mini V4 nouvelle version.

D1 Mini V4

Le précédent était flashé avec Esp Easy, le nouveau, je l’ai flashé avec ESP Home.

Voici les deux tutos :

Une fois le D1 mini V4 flashé avec Esp Home, je poursuis la configuration.

Je profite du changement de D1Mini pour remplacer la résistance du pont diviseur entre A0 et GND, je mets une 10K. La valeur de cette résistance est calé sur la valeur de la thermorésistance à 25°C.

Pour mémoire, voici le schéma de câblage

Le câblage du D1 Mini est inchangé, je reproduis donc le schéma avec le D1 Mini V4.

Se référer à cette page pour plus d’explication :

Je réalise la configuration du fichier yaml du device ESP Home

Une fois le D1 mini V4 flashé, je vais dans ESPHome Builder et je trouve mon équipement :

ESPHome Builder

Je clique sur EDIT et je modifie le fichier yaml, voici la configuration :

substitutions:
  name: esphome-web-e586c5
  friendly_name: ESPHome Eau Chaude
esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  min_version: 2024.6.0
  name_add_mac_suffix: false
  project:
    name: esphome.web
    version: dev
esp8266:
  board: esp01_1m
# Activer la journalisation
logger:
# Activer l'API Home Assistant
api:
# Autoriser les mises à jour Over-The-Air
ota:
- platform: esphome
# Autoriser la configuration Wi-Fi via le port série
improv_serial:
wifi:
  # Configurer un point d'accès Wi-Fi
  ap: {}
# En combinaison avec l'option `ap`, cela permet à l'utilisateur
# de configurer les identifiants Wi-Fi via l'AP Wi-Fi.
captive_portal:
dashboard_import:
  package_import_url: github://esphome/example-configs/esphome-web/esp8266.yaml@main
  import_full_config: true
# Pour avoir une "URL suivante" pour improv_serial
web_server:
sensor:
  - platform: ntc
    sensor: temp_resistance
    name: "Température"
    unit_of_measurement: "°C"
    accuracy_decimals: 2
    calibration:
      b_constant: 3950
      reference_temperature: 25°C
      reference_resistance: 10kOhm
    
  - platform: resistance
    id: temp_resistance
    sensor: temp_voltage
    configuration: DOWNSTREAM
    resistor: 10kOhm
  - platform: adc
    pin: A0
    id: temp_voltage
  # Capteur de turbine pour l'eau froide
  - platform: pulse_meter
    pin:
      number: GPIO13
      mode:
        input: true
        pullup: true
    name: 'Débit Eau potable'
    unit_of_measurement: 'L/min'
    accuracy_decimals: 0
    internal_filter: 100ms
    timeout: 5s
    filters:
      - multiply: 0.013
    total:
      name: 'Total Eau potable'
      unit_of_measurement: 'L'
      id: total_eau_potable
      accuracy_decimals: 2
      filters:
        - multiply: 0.013  
  # Capteur de turbine pour l'eau chaude
  - platform: pulse_meter
    pin:
      number: GPIO14
      mode:
        input: true
        pullup: true
    name: 'Débit Eau chaude'
    unit_of_measurement: 'L/min'
    accuracy_decimals: 0
    internal_filter: 100ms
    timeout: 5s
    filters:
      - multiply: 0.013  # 1/77
    total:
      name: 'Total Conso Eau chaude'
      unit_of_measurement: 'L'
      id: total_eau_chaude
      accuracy_decimals: 2
      filters:
        - multiply: 0.013  # 1/77  
  # Calculated sensor for net cold water consumption
  - platform: template
    name: "Total Conso Eau froide"
    unit_of_measurement: "L"
    accuracy_decimals: 2
    lambda: |-
      return id(total_eau_potable).state - id(total_eau_chaude).state;

En quelques lignes, voici l’explication :

Capteur de température (NTC) :

  • Utilise un thermistor NTC
  • Mesure en °C avec 2 décimales
  • Configuration en cascade : ADC (A0) → resistance → ntc
  • Calibré avec une constante B de 3950 et une référence à 25°C/10kΩ

Deux capteurs de débit d’eau (pulse_meter) :

  • Eau potable sur GPIO13, Eau chaude sur GPIO14
  • Configuration en mode input avec pullup activé
  • Conversion : multiplie par 0.013 (calibré sur 77 impulsions/L)
  • Timeout de 5s (retour à 0 si pas d’impulsions)
  • Filtre interne de 100ms pour stabiliser la lecture
  • Chacun dispose d’un compteur total en litres
  • Précision : 0 décimale pour le débit, 2 pour le total

Un capteur calculé :

  • Calcule la consommation d’eau froide
  • Formule : Total eau potable – Total eau chaude
  • Précision : 2 décimales

Je sélectionne les capteurs que je garde

Sélection des capteurs

Je vais garder les 4 derniers capteurs, je désactive les autres et je les renomme en :

  • sensor.temperature_eau_chaude
  • sensor.esphome_total_eau_potable
  • sensor.esphome_total_eau_chaude
  • sensor.esphome_total_eau_froide

Renommage des capteurs

Renommage des capteurs

J’ajoute 3 capteurs d’offset

Quand le D1 Mini V4 redémarre (coupure de jus par exemple), le comptage repart à zéro.

J’ai donc organisé le calcul du comptage total via un capteur qui me donne la somme d’un offset et de la valeur du comptage en cours.

J’ai donc ajouté 3 entités d’offset. Pour les puristes, seuls deux sont obligatoires, le 3eme peut être calculé.

Donc dans Paramètres/Appareils et Services/Entrées, j’ai ajouté une entrée

Ajout d'une entrée

Puis Nombre

Ajout d'un nombre

Configuration du nombre

Cela me créé donc input_number.eau_froide_offset.

Je fais cela pour les deux autres offset

Configuration des offsets

J’ai choisi d’utiliser « eau potable » pour tout ce qui passe dans le compteur eau potable donc le consommation totale : eau froide + eau chaude.

J’ajoute 3 automatisations pour gérer le Reset du compteur du D1 Mini

Le D1 Mini a un défaut de taille, il perd la valeur de ses compteurs en cas de reset, tout repart donc à zéro, cela ne me convient donc pas.

J’ai remarqué qu’au moment du reset, les capteurs passent à l’état « unavailable » avant de repasser à zéro.

Je vais donc affecté l’état précédent unavailable à un input_number qui me servira d’offset, c’est à dire de valeur de correction pour le comptage global.

Pour que ce soit plus simple, je fais 3 automatisations qui réalisent cela :

alias: Offset Eau Chaude sur Unavailable
triggers:
  - entity_id: sensor.esphome_total_eau_chaude
    to: unavailable
    trigger: state
actions:
  - target:
      entity_id: input_number.eau_chaude_offset
    data:
      value: >-
        {{ states('input_number.eau_chaude_offset') | float +
        trigger.from_state.state | float }}
    action: input_number.set_value
mode: single
alias: Offset Eau Froide sur Unavailable
triggers:
  - entity_id: sensor.esphome_total_eau_froide
    to: unavailable
    trigger: state
actions:
  - target:
      entity_id: input_number.eau_froide_offset
    data:
      value: >-
        {{ states('input_number.eau_froide_offset') | float +
        trigger.from_state.state | float }}
    action: input_number.set_value
mode: single
alias: Offset Eau Potable sur Unavailable
triggers:
  - entity_id: sensor.esphome_total_eau_potable
    to: unavailable
    trigger: state
actions:
  - target:
      entity_id: input_number.eau_potable_offset
    data:
      value: >-
        {{ states('input_number.eau_potable_offset') | float +
        trigger.from_state.state | float }}
    action: input_number.set_value
mode: single

Pour chaque type d’eau (chaude, froide, potable), quand le capteur devient indisponible (‘unavailable’) :

  • L’automatisation capture la dernière valeur connue avant la déconnexion
  • Cette valeur est ajoutée à un compteur d’offset stocké dans un input_number
  • Cela permet de conserver le cumul total même après un redémarrage du capteur

Automatisation

Je déclare les capteurs finaux de consommation

Dans mon fichier templates.yaml, j’ajoute ces 3 capteurs :

Capteurs finaux
- sensor:    
 
    - name: "Consommation Eau Potable"
      unique_id: sensor.consommation_eau_potable
      unit_of_measurement: "L"
      device_class: water
      state_class: total_increasing
      state: >
        {% set mesure_actuelle = states('sensor.esphome_total_eau_potable') | float %}
        {% set total_offset = states('input_number.eau_potable_offset') | float %}
        {{ total_offset + mesure_actuelle if states('sensor.esphome_total_eau_potable') != 'unavailable' else total_offset }}
        
    - name: "Consommation Eau Froide"
      unique_id: sensor.consommation_eau_froide
      unit_of_measurement: "L"
      device_class: water
      state_class: total_increasing
      state: >
        {% set mesure_actuelle = states('sensor.esphome_total_eau_froide') | float %}
        {% set total_offset = states('input_number.eau_froide_offset') | float %}
        {{ total_offset + mesure_actuelle if states('sensor.esphome_total_eau_froide') != 'unavailable' else total_offset }}
        
    - name: "Consommation Eau Chaude"
      unique_id: sensor.consommation_eau_chaude
      unit_of_measurement: "L"
      device_class: water
      state_class: total_increasing
      state: >
        {% set mesure_actuelle = states('sensor.esphome_total_eau_chaude') | float %}
        {% set total_offset = states('input_number.eau_chaude_offset') | float %}
        {{ total_offset + mesure_actuelle if states('sensor.esphome_total_eau_chaude') != 'unavailable' else total_offset }}      

Ces capteurs sont des capteurs virtuels (templates) qui permettent de suivre la consommation d’eau de manière persistante. Analysons leur fonctionnement :

Sources des données :

  • Capteurs physiques ESP Home (sensor.esphome_total_eau_*)
  • Compteurs d’offset (input_number.eau_*_offset)

Types de mesures :

  • Eau Potable : Total de l’eau entrante
  • Eau Chaude : Consommation d’eau chaude
  • Eau Froide : Consommation d’eau froide

Caractéristiques communes :

  • state_class: total_increasing : Indique un compteur qui augmente continuellement
  • unit_of_measurement: « L » : Mesure en litres

Logique de fonctionnement :

{% set mesure_actuelle = states(‘sensor.esphome_total_eau_*’) | float %}
{% set total_offset = states(‘input_number.eau_*_offset’) | float %}
{{ total_offset + mesure_actuelle if states(…) != ‘unavailable’ else total_offset }}

  • Si le capteur ESP est disponible : Total = Offset + Mesure actuelle
  • Si le capteur ESP est indisponible : Total = Offset uniquement

Je configure recorder

Il faut penser à garder ce dont on a besoin mais aussi à ne pas enregistrer ce qui n’est pas utile.

Ainsi dans la configuration de Recorder, je mets dans :

  include:
    entity_globs: 
[...]
      - input_number.eau_*
      - sensor.consommation_eau_*
  exclude:
    entity_globs:
[...]
      - sensor.esphome*    

Je teste le reset du D1 Mini V4

Au final, j’ai donc

  • 3 input_number qui servent d’offset,
  • 3 sensors qui me donnent la valeur des compteurs actuels du D1 Mini
  • 3 sensors calculés qui me donnent la valeur des compteurs permanents

Test du reset

A ce stade, le D1 ne s’est jamais relancé, donc les compteurs du D1 et les compteurs permanents sont identiques.

Je débranche et rebranche le D1 mini, les capteurs vont devenir indisponible le temps du reset puis repasser à 0.

Reset du D1 Mini

A ce moment là, les Offset prennent les dernières valeurs des compteurs. Puis le D1 mini se reconnecte à Home assistant :

Reconnexion du D1 Mini

Les compteurs permanents reprennent la valeur des offset + valeur du compteur du D1 (0).

Je fais couler un peu d’eau chaude et un peu d’eau froide, les offset ne bougent pas mais les compteurs affichent les bonnes valeurs :

Test de consommation

Je garde donc uniquement les 3 derniers compteurs pour mon Dashboard et pour les statistiques de conso.

Résultat

Résultat final

Résultat final

Résultat final

Si c’était à refaire (idées ou retour d’expérience)

  • J’utiliserais une turbine avec capteur de température même pour l’eau froide, j’ai la curiosité de vouloir savoir la température surtout en hiver.