Un lecteur de compteur d'eau MQTT transforme le cadran de votre sous-sol en données de consommation en direct : litres par jour, débit instantané et alerte précoce lorsque l'eau continue de couler alors qu'elle ne le devrait pas. Dans ce tutoriel, vous allez choisir le bon capteur pour votre compteur, compter les impulsions avec un ESP32, préserver le total en cas de coupure de courant et le publier vers un broker MQTT. Vous ajouterez aussi une logique de détection de fuites qui repère un robinet qui goutte ou une canalisation qui éclate. C'est un projet typique de maison connectée, et comme Jeedom et Domoticz savent aussi communiquer en MQTT, ces relevés ne sont pas réservés à un seul logiciel domotique.
Choisir un capteur pour votre compteur d'eau
La plupart des compteurs d'eau domestiques sont mécaniques et n'ont pas de port de données. On les lit en détectant un élément qui bouge une fois par litre (ou par dix litres). Examinez votre compteur avant d'acheter des composants :
| Caractéristique du compteur | Capteur | Fonctionnement | Remarques |
|---|---|---|---|
| Câble de sortie impulsions ou mention « pulse-ready » | Module à contact reed du fabricant du compteur | Se ferme une fois par litre ou par 10 litres | Le plus fiable, signal propre |
| Aimant rotatif (certains compteurs) | Interrupteur reed ou capteur à effet Hall fixé dessus | L'aimant passe devant le capteur à chaque rotation | Vérifiez avec une application boussole sur téléphone |
| Demi-disque métallique sur le cadran des litres | Capteur de proximité inductif (par ex. LJ18A3-8-Z/BX) | Détecte le métal à son passage | Choix courant ; nécessite généralement une alimentation de 5 à 12 V et un convertisseur de niveau ou un diviseur |
| Repère réfléchissant sur le cadran | Capteur infrarouge à réflexion (type TCRT5000) | Détecte le segment clair/sombre | Sensible à l'alignement et à la lumière ambiante |
| Aucun élément exploitable | Caméra avec reconnaissance de chiffres (ESP32-CAM) | Lit les chiffres optiquement | Le projet « AI-on-the-edge-device » publie lui-même en MQTT |
N'ouvrez et ne modifiez jamais le compteur lui-même ; il appartient généralement au distributeur d'eau. Tous les capteurs ci-dessus se clipsent ou se fixent à l'extérieur.
Câbler l'ESP32
Ce tutoriel utilise un signal d'impulsion sur le GPIO 25 qui passe à l'état bas une fois par litre. Pour un interrupteur reed, branchez-le entre le GPIO 25 et GND et utilisez la résistance de pull-up interne. Pour un capteur inductif NPN alimenté entre 5 et 12 V, reliez sa sortie au GPIO 25 avec le pull-up interne activé ; les sorties NPN à collecteur ouvert tirent la ligne vers le bas et ne la portent jamais au-dessus de 3,3 V, mais vérifiez la fiche technique de votre capteur, car certains modules intègrent un pull-up vers leur tension d'alimentation, auquel cas un diviseur de tension est nécessaire.
Les choix de conception qui comptent
Un lecteur de compteur d'eau paraît simple, mais trois détails déterminent si ses valeurs sont fiables :
- Le total doit survivre aux redémarrages. Si l'ESP32 redémarre et recompte à partir de zéro, votre graphique de consommation quotidienne est faussé. Le sketch stocke le total en flash (NVS) et vous permet de l'aligner sur le cadran physique.
- L'usure de la flash. Écrire en flash à chaque impulsion l'use rapidement. Sauvegardez lorsque le compte a changé et au plus toutes les quelques minutes, en acceptant qu'une coupure de courant puisse faire perdre quelques litres.
- L'anti-rebond. Les contacts mécaniques rebondissent, et un capteur inductif peut osciller en bordure du métal. Un court anti-rebond logiciel évite les doubles comptages.
Les topics de ce montage :
connectmq/demo/<random-id>/water/main/telemetry JSON every 60 s, retained
connectmq/demo/<random-id>/water/main/status online/offline (Last Will), retained
connectmq/demo/<random-id>/water/main/set/total_l command: set the total to match the dial
Le sketch ESP32 du compteur d'eau MQTT
Installez PubSubClient de Nick O'Leary depuis le gestionnaire de bibliothèques. Preferences fait partie du core Arduino ESP32. Le sketch se connecte au serveur MQTT public gratuit broker.connectmq.com, idéal pour les tests et les prototypes mais pas pour vos vraies données de consommation.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Preferences.h>
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* PREFIX = "connectmq/demo/w8m3d1/water/main";
const int PIN_PULSE = 25;
const float LITRES_PER_PULSE = 1.0; // 10.0 pour de nombreux modules d'impulsions de fabricant
const uint32_t SAVE_INTERVAL_MS = 5UL * 60 * 1000;
const uint32_t PUBLISH_INTERVAL_MS = 60UL * 1000;
WiFiClient net;
PubSubClient mqtt(net);
Preferences prefs;
volatile uint32_t pulses = 0;
volatile uint32_t lastPulseMs = 0;
uint64_t baseLitresX10 = 0; // total stocké, en unités de 0,1 L
uint32_t savedPulses = 0, lastSaveMs = 0, lastPublishMs = 0, pulsesAtPublish = 0;
char clientId[32], topicStatus[96], topicTelemetry[96], topicSet[96];
void IRAM_ATTR onPulse() {
uint32_t now = millis();
if (now - lastPulseMs > 50) { pulses++; lastPulseMs = now; } // anti-rebond de 50 ms
}
double totalLitres() {
noInterrupts(); uint32_t p = pulses; interrupts();
return baseLitresX10 / 10.0 + p * LITRES_PER_PULSE;
}
void saveTotal() {
noInterrupts(); uint32_t p = pulses; interrupts();
if (p == savedPulses) return; // rien de nouveau, pas d'écriture en flash
prefs.putULong64("total_x10", baseLitresX10 + (uint64_t)(p * LITRES_PER_PULSE * 10));
savedPulses = p;
}
void onMessage(char* topic, byte* payload, unsigned int len) {
if (strcmp(topic, topicSet) != 0) return;
char buf[24];
len = min(len, (unsigned int)sizeof(buf) - 1);
memcpy(buf, payload, len); buf[len] = 0;
double litres = atof(buf);
if (litres <= 0) return;
noInterrupts(); pulses = 0; interrupts();
baseLitresX10 = (uint64_t)(litres * 10);
savedPulses = 0; pulsesAtPublish = 0;
prefs.putULong64("total_x10", baseLitresX10);
Serial.printf("Total set to %.1f L\n", litres);
}
void connectMqtt() {
while (!mqtt.connected()) {
if (mqtt.connect(clientId, nullptr, nullptr, topicStatus, 1, true, "offline")) {
mqtt.publish(topicStatus, "online", true);
mqtt.subscribe(topicSet, 1);
} else {
Serial.printf("MQTT failed, state=%d\n", mqtt.state());
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
prefs.begin("water", false);
baseLitresX10 = prefs.getULong64("total_x10", 0);
pinMode(PIN_PULSE, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_PULSE), onPulse, FALLING);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
snprintf(clientId, sizeof(clientId), "water-%llx", ESP.getEfuseMac());
snprintf(topicStatus, sizeof(topicStatus), "%s/status", PREFIX);
snprintf(topicTelemetry, sizeof(topicTelemetry), "%s/telemetry", PREFIX);
snprintf(topicSet, sizeof(topicSet), "%s/set/total_l", PREFIX);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
connectMqtt();
lastSaveMs = lastPublishMs = millis();
}
void loop() {
if (!mqtt.connected()) connectMqtt();
mqtt.loop();
uint32_t now = millis();
if (now - lastSaveMs >= SAVE_INTERVAL_MS) { saveTotal(); lastSaveMs = now; }
if (now - lastPublishMs >= PUBLISH_INTERVAL_MS) {
noInterrupts(); uint32_t p = pulses; interrupts();
float litresInterval = (p - pulsesAtPublish) * LITRES_PER_PULSE;
float flowLpm = litresInterval / ((now - lastPublishMs) / 60000.0);
char payload[160];
snprintf(payload, sizeof(payload),
"{\"total_l\":%.1f,\"flow_lpm\":%.2f,\"interval_l\":%.1f,\"rssi\":%d}",
totalLitres(), flowLpm, litresInterval, WiFi.RSSI());
mqtt.publish(topicTelemetry, payload, true);
Serial.println(payload);
pulsesAtPublish = p;
lastPublishMs = now;
}
}
Flashez la carte, ouvrez un robinet et observez le moniteur série. Abonnez-vous ensuite depuis votre ordinateur :
mosquitto_sub -h broker.connectmq.com -p 1883 -i water-view-2207 -t "connectmq/demo/w8m3d1/water/#" -v
Relevez le cadran physique et alignez le total dessus, en litres :
mosquitto_pub -h broker.connectmq.com -p 1883 -i water-set-2208 -t "connectmq/demo/w8m3d1/water/main/set/total_l" -m "482137"
La commande de réglage n'est volontairement pas retenue : elle s'applique une seule fois et ne réinitialise pas le total à chaque reconnexion de l'ESP32. Si la connexion échoue, le tutoriel ESP32 MQTT propose une section de dépannage pas à pas.
Détecter les fuites à partir des données du compteur d'eau MQTT
Les données de consommation prennent toute leur valeur lorsqu'elles vous alertent. Deux schémas repèrent la plupart des fuites :
- Un débit continu. Dans la plupart des logements, chaque heure comporte des périodes sans aucun débit. Si
interval_lest resté supérieur à zéro sur chaque intervalle d'une minute pendant, disons, deux heures, quelque chose coule : un robinet flotteur de chasse d'eau, un robinet qui goutte ou une zone d'arrosage restée ouverte. - Un débit élevé trop longtemps. Un tuyau ou une canalisation qui éclate se traduit par un
flow_lpmélevé qui dure bien plus longtemps qu'une douche ou un bain. Choisissez un seuil d'après vos pics habituels après une semaine de données.
Le premier schéma nécessite de suivre un état dans le temps et s'intègre bien dans Node-RED ou un court abonné Python. Le second est un simple seuil ; dans le portail ConnectMQ, vous pouvez créer une règle d'alerte sur seuil sur flow_lpm et consulter les alertes déclenchées dans le journal des alertes. Pour une détection ponctuelle sous les éviers et les lave-linge, combinez cela avec des capteurs dédiés présentés dans le guide de détection des fuites d'eau ; le compteur vous dit que l'eau coule, le capteur au sol vous dit où.
Consommation quotidienne et mensuelle
L'ESP32 publie un total cumulé plutôt que des chiffres quotidiens, et c'est voulu : un total est facile à maintenir exact, et n'importe quel abonné peut en déduire la consommation quotidienne, hebdomadaire ou mensuelle en faisant la différence entre le premier et le dernier total de chaque période. Telegraf avec InfluxDB, l'assistant utility meter de Home Assistant ou un petit script écrivant dans SQLite fonctionnent tous ainsi. Gardez l'appareil simple et faites les calculs calendaires en aval, là où les fuseaux horaires et les périodes de facturation sont plus faciles à gérer que sur un microcontrôleur.
Liste de contrôle précision et fiabilité
- Comparez au cadran chaque semaine pendant le premier mois et ajustez
LITRES_PER_PULSEou la position du capteur si les relevés dérivent. - Vérifiez l'absence de double comptage en tirant 10 litres mesurés dans un seau ; le compte doit augmenter d'exactement 10 impulsions à raison de 1 L par impulsion.
- Protégez le capteur de la condensation. Les regards de compteur et les tuyaux d'eau froide suintent ; utilisez un capteur étanche et gardez l'ESP32 dans un boîtier sec.
- Attention au Wi-Fi en sous-sol. Un signal faible provoque des reconnexions ; la télémétrie retenue et le statut Last Will rendent les coupures visibles.
- Faites appel à votre plombier ou à votre distributeur d'eau pour tout ce qui touche au compteur lui-même.
Passer à un broker privé
La consommation d'eau révèle les habitudes quotidiennes et les moments où la maison est vide, et n'importe qui pourrait publier sur votre topic de réglage sur un broker partagé. Une fois le lecteur fonctionnel, passez à un broker privé avec identifiants et TLS. Un broker MQTT managé comme ConnectMQ vous l'offre sans rien héberger chez vous. Utilisez WiFiClientSecure avec le certificat ISRG Root X1 pour Let's Encrypt, le port 8883 et vos identifiants du portail :
#include <WiFiClientSecure.h>
WiFiClientSecure net; // à la place de WiFiClient
// setup(): net.setCACert(ISRG_ROOT_X1_PEM);
// mqtt.setServer("broker.connectmq.com", 8883);
// mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", topicStatus, 1, true, "offline");
La consommation d'eau trouve naturellement sa place à côté de vos données électriques issues d'un suivi énergétique de la maison. Pour d'autres idées d'automatisation, consultez le guide de l'automatisation IoT, et pour les compromis d'hébergement, la présentation du broker MQTT dans le cloud.
Suivez votre consommation d'eau avec ConnectMQ
ConnectMQ offre à votre lecteur de compteur un broker MQTT privé et sécurisé par TLS, avec un explorateur de topics en direct et des règles d'alerte sur seuil pour les avertissements de fuite basés sur le débit. Créez un broker Serverless (Free) sur app.connectmq.com, sans carte bancaire, et recevez vos premiers relevés en quelques minutes.
Questions fréquentes
Puis-je lire n'importe quel compteur d'eau avec MQTT ?
La plupart des compteurs mécaniques peuvent être lus depuis l'extérieur avec un capteur reed, inductif ou optique, ou avec une caméra qui lit les chiffres. Les compteurs communicants à protocole sans fil nécessitent plutôt un récepteur adapté.
Combien de litres représente une impulsion ?
Cela dépend du compteur et du capteur. Un capteur placé sur le cadran des litres donne généralement une impulsion par litre, tandis que les modules d'impulsions des fabricants donnent souvent une impulsion par 10 litres. Vérifiez par rapport au cadran pour confirmer.
Le total sera-t-il perdu après une coupure de courant ?
Pas avec le sketch ci-dessus. Le total est enregistré dans la flash de l'ESP32 toutes les quelques minutes lorsqu'il change ; au pire, quelques minutes d'impulsions peuvent être perdues, et vous pouvez resynchroniser avec la commande de réglage.
Comment détecter une fuite lente ?
Cherchez un débit présent dans chaque intervalle sur une longue période, par exemple deux heures la nuit. Un foyer normal connaît régulièrement des périodes sans débit ; un petit débit continu est donc un fort indicateur de fuite.



