LA PARTIE CODE
A- Pour commencer, la partie pour la mesure de l’eau à l’aide des deux YF-S201C
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"
Un 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
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)) }}
B- Ensuite 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.
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