Compteur d'eau avec afficheur 7 segments

Mesurez la consommation d’eau des douches avec un ESP32 et des capteurs de débit. Suivez les litres consommés, recevez alertes sonores et visuelles, et sensibilisez la famille à l’eau. Simple, pratique et écolo !
Compteur d'eau avec afficheur 7 segments

Sommaire

Mesurez la consommation d’eau des douches avec un ESP32 et des capteurs de débit. Suivez les litres consommés, recevez alertes sonores et visuelles, et sensibilisez la famille à l’eau. Simple, pratique et écolo !

Introduction

Ce tuto partait d'un besoin simple, surtout depuis ma dernière facture d'eau : connaître la consommation des douches des kids à la maison.
J'avais 3 ans de consommation fixe, à savoir 89 m³ à l'année (pour un foyer de 4 personnes, 2 adultes et deux ados 16 et 17 ans cette année) et la dernière facture de 103 m³ m'a fait me pencher et me sensibiliser sur l'eau.
Nous avons 2 salles de bain, une utilisée par les kids, au 1er étage et une autre pour nous, les parents, au 2ᵉ étage.
J'aurais pu me connecter au compteur principal, mais ayant des difficultés, de distance et donc de portée radio et wifi (compteur à 35 m à l'extérieur de la maison) et pas de point d'énergie à proximité du compteur… J'ai abandonné l'idée. Finalement, je me concentre sur l'essentiel : l'eau des douches.

Voici donc deux vidéos courtes qui illustrent le concept :

Matériel

Le matériel utilisé est le suivant.

Mesures

  • 1 ESP32 (celui qui vous plaira, un mini fera l'affaire, on a besoin de 2 GPIO pour les capteurs)
    J'ai pris un ESP32-WROOM-32U avec antenne déportée pour plus de sensibilité étant donné l'endroit exigu, enfermé sous la baignoire.
ESP32-WROOM-32U WROVER Module WIFI Module with 2.4G Antenna Optional ESP32 Development Board WROOM-32U - AliExpress 502
Smarter Shopping, Better Living! Aliexpress.com
  • 2 capteurs / débitmètres :
  • Soit la version "Cheap" Plastique : YF-S201C (Attention il y a un sens de montage) Au moment de la réalisation j'ai fait avec ce modèle, mais j'ai préféré la sureté et je suis passé peu de temps après sur le modèle laiton (cité juste après).
Water Flow Sensor Switch G1/2
Smarter Shopping, Better Living! Aliexpress.com
  • Soit la version laiton (conseillée) : YF-B8.
Brass Water Flow Sensor Hall Effect Flow Meter Liquid Flow Rate Sensor Brass Flow Switch Digital Monitoring Detector - AliExpress 1420
Smarter Shopping, Better Living! Aliexpress.com
  • 1 alimentation 5V.
AC 110-240V DC 3V 5V 6V 9V 12V 15V 24V 0.5A 1A 2A 3A 5A 6A 8A Universal Power Adapter Supply Charger adapter Eu Us for LED light - AliExpress 13
Smarter Shopping, Better Living! Aliexpress.com
  • Du câble et des connecteurs Dupont si vous ne voulez pas souder. C'est mon choix, car plus facile à démonter en cas de problème.
  • 2 résistances de 10 Kohms pour le pull down et ainsi éviter d'avoir des impulsions parasites.
  • Bonus selon votre config : 2 X Manchon laiton double Femelle 15/21 (1/2") à butée (valable pour la version plastique)

https://www.bricodepot.fr/rouen/manchon-laiton-double-femelle-1521-12-a-butee/prod78936/


Comme vous le verrez sur la vidéo, mes nourrices ont un filetage mâle et les capteurs également... donc 2 manchons à prévoir et 4 joints (2 pour chaque manchon) Mais la question ne se pose plus si vous choisissez la version laiton, puisqu'il y a une extrémité mâle et une extrémité femelle.

Il y a un sens de montage, sur le modèle plastique, vous avez une flèche bien visible. pour le modèle laiton, c'est moins flagrant, le sens de circulation de l'eau se fait dans le sens filetage femelle vers mâle.

  • Bonus 2: le boitier, si vous avez une imprimante 3D...

Affichage

  • 1 ESP32-S3 (celui qui vous plaira aussi, j'avais ce modèle sous le coude et je ne regrette pas, car LED embarquée : le programme pour le coup la prend en compte)
ESP32-S3 Development Board 2.4G Wifi Module for Arduino ESP IDF ESP32-S3WROOM1 N8R2 N16R8 44Pin Type-C 8M PSRAM ESP32 S3 - AliExpress 502
Smarter Shopping, Better Living! Aliexpress.com
  • 1 afficheur 7 segments TM1637 de la couleur de votre convenance.
TM1637 LED Display Module for Arduino 4 Digit Tube 7 Segment 0.56 inch Time Clock Indicator Module Red Blue Green Yellow White - AliExpress 502
Smarter Shopping, Better Living! Aliexpress.com
  • 1 alimentation 5 V (le même que pour la mesure, je prends 5V 3A pour ne jamais être embêté)
    J'en avais 4 sous le coude pour un autre projet, mais le câble était trop court donc c'est parfait, en voilà 2 d'utilisées.
  • 1 buzzer PASSIF (récupéré pour moi certainement d'un ancien PC) Passif, car on peut faire des "mélodies" alors qu'un actif fera un son fixe continu.
10PCS 12085 Passive Buzzer 12MM*8.5MM 42R Resistance 3V 5V 9V 12V in Common Use Mini Piezo Buzzers Kit, for Arduino - AliExpress 502
Smarter Shopping, Better Living! Aliexpress.com
  • 1 capteur tactile (capacitif) TTP223.
1 Channel TTP223 Jog Digital Touch Blue Digital TTP223B Sensor Module Capacitive Touch Switch for Arduino Diy Starter Kit - AliExpress 502
Smarter Shopping, Better Living! Aliexpress.com

J'ai masqué avec du scotch électricien la LED de l'afficheur 7 segments, elle n'est pas désactivable, l'autre solution serait de la dessouder...

Code

Mesures

Pour commencer, la partie pour la mesure de l'eau à l'aide des deux YF-S201C (ou les deux YF-B8, selon ce que vous aurez choisi) :

esphome:
  name: debitmetre_sdb
  friendly_name: Débitmètre Douche SDB

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:

api:
  encryption:
    key: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"

ota:
  - platform: esphome
    password: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"

web_server:
  port: 80

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

captive_portal:

mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_user
  password: !secret mqtt_password
  discovery: true
  discovery_retain: true
  topic_prefix: "esp32/debitmetre"
  birth_message:
    topic: esp32/debitmetre/status
    payload: online
  will_message:
    topic: esp32/debitmetre/status
    payload: offline


globals:
  - id: eau_froide
    type: float
    restore_value: yes
    initial_value: '0.0'
  - id: eau_chaude
    type: float
    restore_value: yes
    initial_value: '0.0'

sensor:
  - platform: pulse_counter
    pin:
      number: GPIO26
      mode:
        input: true
        pullup: false
    id: debit_1
    update_interval: 5s
    on_raw_value:
      then:
        - lambda: |-
            ESP_LOGI("EAU FROIDE", "Pulses reçus: %d", x); 
            id(eau_froide) += x * 0.00031;
      # La première ligne avec les Pulses reçus permet de savoir que tout est en ordre et que vous n'avez pas de pulses parasites
      # Surtout si vous ne tirez pas d'eau : les pulses doivent être à 0
  - platform: pulse_counter
    pin:
      number: GPIO27
      mode:
        input: true
        pullup: false
    id: debit_chaude
    internal_filter: 13us
    update_interval: 5s
    on_raw_value:
      then:
        - lambda: |-
            ESP_LOGI("EAU CHAUDE", "Pulses reçus: %d", x);
            id(eau_chaude) += x * 0.00031;

  # Eau froide
  - platform: template
    name: "Volume Eau Froide"
    id: sensor_eau_froide
    unit_of_measurement: "L"
    accuracy_decimals: 2
    update_interval: 5s
    lambda: |-
      return id(eau_froide);

  # Eau chaude
  - platform: template
    name: "Volume Eau Chaude"
    id: sensor_eau_chaude
    unit_of_measurement: "L"
    accuracy_decimals: 2
    update_interval: 5s
    lambda: |-
      return id(eau_chaude);

button:
  - platform: template
    name: "Réinitialiser Volumes"
    id: bouton_reset
    icon: "mdi:restart"
    on_press:
      then:
        - lambda: |-
            id(eau_froide) = 0.0;
            id(eau_chaude) = 0.0;
        - sensor.template.publish:
            id: sensor_eau_froide
            state: "0.00"
        - sensor.template.publish:
            id: sensor_eau_chaude
            state: "0.00"   

esphome: name: debitmetre_sdb friendly_name: Débitmètre Douche SDB

Une fois que vous avez flashé votre ESP et qu'il est allumé & connecté il va publier 2 valeurs sous MQTT, à savoir :
sensor_eau_froide
sensor_eau_chaude

explorer_KmGjqc1bMh|420x500

Vous pouvez alors créer votre template dans configuration.yaml qui va additionner les valeurs de ces deux sensors :

template:
  - sensor:
      - name: "Consommation Eau SDB"
        unique_id: consommation_eau_sdb
        unit_of_measurement: "L"
        device_class: water
        state_class: total_increasing
        state: >-
          {{ (states('sensor.debitmetre_douche_sdb_volume_eau_froide') | float(0)) +
             (states('sensor.debitmetre_douche_sdb_volume_eau_chaude') | float(0)) }}

template:

Affichage

Ensuite, passons à la partie affichage (dans mon cas sur mon petit cube en polycarbonate) :

esphome:
  name: afficheur-eau
  friendly_name: Afficheur Eau
  on_boot:
    priority: -100
    then:
      - light.turn_on:
          id: led_rgb
          red: 0.0
          green: 0.0
          blue: 1.0
      - script.execute: clignote_bleu
      - rtttl.play:
          id: my_rtttl
          rtttl: "two_short:d=4,o=5,b=100:16e6,16e6"
      - delay: 10s
      - lambda: |-
          id(autorise_logiciel) = true;

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

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

web_server:
  port: 80 

captive_portal:

logger:

api:
  encryption:
    key: "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"

ota:
  - platform: esphome
    password: "zzzzzzzzzzzzzzzzzzzzzzzzzzz"

# ========================
# Afficheur TM1637
# ========================

display:
  - platform: tm1637
    id: tm_display
    clk_pin: GPIO10
    dio_pin: GPIO11
    inverted: false
    length: 4
    lambda: |-
      if (id(eau_litres).has_state()) {
        int valeur = int(id(eau_litres).state);
        char buf[5];
        if (valeur < 10) {
          snprintf(buf, sizeof(buf), "  %1dL", valeur);
        } else if (valeur < 100) {
          snprintf(buf, sizeof(buf), " %2dL", valeur);
        } else {
          snprintf(buf, sizeof(buf), "%3dL", valeur);
        }
        it.print(buf);
      } else {
        it.print("---L");
      }

# ========================
# LED RGB WS2812
# ========================

light:
  - platform: fastled_clockless
    chipset: WS2812
    pin: GPIO48
    num_leds: 1
    rgb_order: GRB
    name: "LED Statut"
    id: led_rgb
    restore_mode: RESTORE_DEFAULT_OFF

# ========================
# Buzzer passif avec RTTTL
# ========================

output:
  - platform: ledc
    pin: GPIO4
    id: rtttl_out

rtttl:
  output: rtttl_out
  id: my_rtttl

# ========================
# Variables globales
# ========================

globals:
  - id: alarme_desactivee
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: autorise_logiciel
    type: bool
    restore_value: no
    initial_value: 'false'
  - id: dernier_seuil_bip
    type: int
    restore_value: no
    initial_value: '0'    

# ========================
# Script clignotement bleu
# ========================

script:
  - id: clignote_bleu
    mode: single
    then:
      - repeat:
          count: 10
          then:
            - light.turn_on:
                id: led_rgb
                red: 0.0
                green: 0.0
                blue: 1.0
            - delay: 1s
            - light.turn_off: led_rgb
            - delay: 500ms
      - lambda: |-
          // Ne rien faire ici → on laisse l’interval gérer la suite

# ========================
# Script alarme sonore
# ========================

  - id: trigger_alarm
    mode: single
    then:
      - rtttl.play:
          id: my_rtttl
          rtttl: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"

# ========================
# Script bips dizaines
# ========================

  - id: bip_1
    then:
      - rtttl.play:
          id: my_rtttl
          rtttl: "bip_1:d=4,o=5,b=100:16e6
"

  - id: bip_2
    then:
      - rtttl.play:
          id: my_rtttl
          rtttl: "bip_2:d=4,o=5,b=100:16e6,16e6"

  - id: bip_3
    then:
      - rtttl.play:
          id: my_rtttl
          rtttl: "bip_3:d=4,o=5,b=100:16e6,16p,16e6,16p,16e6
"          

# ========================
# Bouton arrêt alarme
# ========================

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO14
      mode: INPUT_PULLUP
      inverted: true
    name: "Bouton arrêt alarme"
    on_press:
      then:
        - logger.log: "Alarme arrêtée manuellement"
        - script.stop: trigger_alarm
        - lambda: |-
            id(alarme_desactivee) = true;

# ========================
# Donnée Home Assistant
# ========================

sensor:
  - platform: homeassistant
    id: eau_litres  
    entity_id: sensor.consommation_eau_sdb
    internal: true

# ========================
# Logique couleur LED après init
# ========================

interval:
  - interval: 1s
    then:
      - lambda: |-
          if (!id(autorise_logiciel)) return;

          float r = 0.0, g = 0.0, b = 0.0;  // Déclaration en haut

          if (!id(eau_litres).has_state()) {
            // Couleur défaut si pas encore de données
            auto call = id(led_rgb).make_call();
            call.set_state(true);
            call.set_rgb(0.0, 0.0, 1.0); // Bleu
            call.perform();
            return;
          }

          int litres = int(id(eau_litres).state);

          // Gestion des seuils
          if (litres != id(dernier_seuil_bip)) {
            if (litres == 10) {
              id(bip_1).execute();
              id(dernier_seuil_bip) = 10;
            } else if (litres == 15) {
              id(bip_2).execute();
              id(dernier_seuil_bip) = 15;
            } else if (litres == 20) {
              id(bip_3).execute();
              id(dernier_seuil_bip) = 20;
            }
          }

          id(clignote_bleu).stop();

          if (litres <= 15) {
            r = 0.0; g = 1.0; b = 0.0;  // Vert
            id(alarme_desactivee) = false;
          } else if (litres <= 22) {
            r = 1.0; g = 0.65; b = 0.0; // Orange
          } else {
            r = 1.0; g = 0.0; b = 0.0;  // Rouge
            if (!id(alarme_desactivee)) {
              id(trigger_alarm).execute();
            }
          }

          auto call = id(led_rgb).make_call();
          call.set_state(true);   // <-- Important, sinon la LED peut rester OFF
          call.set_rgb(r, g, b);
          call.perform();



Pour le Reset du compteur, une automatisation qui appuie sur le bouton créé précédemment, juste en fermant la porte.

chrome_uvLzZFmAOS|690x315

Ou en YAML si vous préférez :

alias: Compteur Eau RESET
description: ""
triggers:
  - type: not_opened
    device_id: zzzzzzzzzzzzzzzzzzzzzzzzzzzz
    entity_id: zzzzzzzzzzzzzzzzzzzzzzzzzzzzz
    domain: binary_sensor
    trigger: device
conditions: []
actions:
  - action: button.press
    metadata: {}
    data: {}
    target:
      entity_id: button.debitmetre_douche_sdb_reinitialiser_volumes
mode: single

Conclusion

Ce projet montre qu’il est simple et amusant de suivre la consommation d’eau des douches à la maison. Avec quelques capteurs et un ESP32, on transforme des données abstraites en chiffres concrets et alertes visuelles ou sonores. Finalement, on gagne en contrôle, en conscience écologique, et on peut agir pour réduire le gaspillage. Une petite installation, mais un grand pas pour une maison plus responsable !