Ein Wasserzähler-Leser mit MQTT verwandelt das Zifferblatt in Ihrem Keller in Live-Verbrauchsdaten: Liter pro Tag, aktueller Durchfluss und eine frühe Warnung, wenn Wasser läuft, obwohl es das nicht sollte. In diesem Tutorial wählen Sie den passenden Sensor für Ihren Zähler, zählen Impulse mit einem ESP32, sichern den Zählerstand gegen Stromausfälle und veröffentlichen ihn an einen MQTT-Broker. Außerdem ergänzen Sie eine Leckerkennung, die einen tropfenden Wasserhahn oder einen Rohrbruch bemerkt.
Den passenden Sensor für Ihren Wasserzähler wählen
Die meisten Hauswasserzähler sind mechanisch und haben keine Datenschnittstelle. Sie lesen sie aus, indem Sie etwas erfassen, das sich einmal pro Liter (oder pro zehn Liter) bewegt. Prüfen Sie Ihren Zähler, bevor Sie Teile kaufen:
| Zählermerkmal | Sensor | Funktionsweise | Hinweise |
|---|---|---|---|
| Impulsausgangskabel oder Kennzeichnung „pulse-ready“ | Reedkontakt-Modul des Zählerherstellers | Schließt einmal pro Liter oder pro 10 Liter | Am zuverlässigsten, sauberes Signal |
| Rotierender Magnet (bei manchen Zählern) | Reedschalter oder Hallsensor, oben aufgeklebt | Der Magnet passiert den Sensor bei jeder Umdrehung | Mit einer Kompass-App auf dem Smartphone prüfen |
| Metallische Halbscheibe auf dem Literrad | Induktiver Näherungssensor (z. B. LJ18A3-8-Z/BX) | Erfasst das Metall beim Vorbeilaufen | Häufige Wahl; braucht meist 5-12 V Versorgung und einen Pegelwandler oder Spannungsteiler |
| Reflektierende Markierung auf dem Zifferblatt | Infrarot-Reflexsensor (TCRT5000-Typ) | Erfasst das helle/dunkle Segment | Empfindlich gegenüber Ausrichtung und Umgebungslicht |
| Kein nutzbares Merkmal | Kamera mit Ziffernerkennung (ESP32-CAM) | Liest die Ziffern optisch | Das Projekt „AI-on-the-edge-device“ veröffentlicht selbst per MQTT |
Öffnen oder verändern Sie niemals den Zähler selbst; er gehört in der Regel dem Versorger. Alle oben genannten Sensoren werden außen aufgesteckt oder aufgeklebt.
Den ESP32 verdrahten
Dieses Tutorial verwendet ein Impulssignal an GPIO 25, das einmal pro Liter auf Low geht. Einen Reedschalter schließen Sie zwischen GPIO 25 und GND an und nutzen den internen Pull-up. Einen NPN-Induktivsensor mit 5 bis 12 V Versorgung verbinden Sie mit seinem Ausgang an GPIO 25 bei aktiviertem internem Pull-up; NPN-Open-Collector-Ausgänge ziehen die Leitung auf Low und treiben sie nie über 3,3 V. Prüfen Sie aber das Datenblatt Ihres Sensors, denn manche Module enthalten einen Pull-up auf ihre Versorgungsspannung, und dann ist ein Spannungsteiler erforderlich.
Designentscheidungen, auf die es ankommt
Ein Wasserzähler-Leser wirkt einfach, aber drei Details entscheiden darüber, ob seinen Werten zu trauen ist:
- Der Zählerstand muss Neustarts überstehen. Startet der ESP32 neu und zählt ab null, ist Ihr Tagesverbrauchsdiagramm kaputt. Der Sketch speichert den Zählerstand im Flash (NVS) und lässt Sie ihn an das physische Zifferblatt anpassen.
- Flash-Verschleiß. Bei jedem Impuls in den Flash zu schreiben, nutzt ihn schnell ab. Speichern Sie nur, wenn sich der Zählerstand geändert hat, und höchstens alle paar Minuten; dafür nehmen Sie in Kauf, dass bei einem Stromausfall ein paar Liter verloren gehen können.
- Entprellung. Mechanische Kontakte prellen, und ein induktiver Sensor kann an der Kante des Metalls flattern. Eine kurze Software-Entprellung verhindert Doppelzählungen.
Topics für diesen Aufbau:
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
Der ESP32-Sketch für den Wasserzähler mit MQTT
Installieren Sie PubSubClient von Nick O'Leary über den Bibliotheksverwalter. Preferences ist Teil des ESP32-Arduino-Cores.
#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 bei vielen Impulsmodulen der Hersteller
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; // gespeicherter Zählerstand in 0,1-L-Einheiten
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; } // 50 ms Entprellung
}
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; // nichts Neues, kein Flash-Schreibvorgang
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;
}
}
Flashen Sie das Board, öffnen Sie einen Wasserhahn und beobachten Sie den seriellen Monitor. Abonnieren Sie dann von Ihrem Computer aus:
mosquitto_sub -h broker.connectmq.com -p 1883 -i water-view-2207 -t "connectmq/demo/w8m3d1/water/#" -v
Lesen Sie das physische Zifferblatt ab und setzen Sie den Zählerstand passend dazu, in Litern:
mosquitto_pub -h broker.connectmq.com -p 1883 -i water-set-2208 -t "connectmq/demo/w8m3d1/water/main/set/total_l" -m "482137"
Der Set-Befehl ist bewusst nicht retained, damit er einmal angewendet wird und den Zählerstand nicht bei jeder Neuverbindung des ESP32 zurücksetzt. Falls die Verbindung nicht klappt, enthält das ESP32-MQTT-Tutorial einen Schritt-für-Schritt-Abschnitt zur Fehlersuche.
Lecks anhand der Wasserzähler-MQTT-Daten erkennen
Verbrauchsdaten werden dann wertvoll, wenn sie Sie warnen. Zwei Muster erfassen die meisten Lecks:
- Dauerhafter Durchfluss. In den meisten Haushalten gibt es jede Stunde Phasen ohne Durchfluss. War
interval_lin jedem einminütigen Intervall über beispielsweise zwei Stunden größer als null, läuft irgendwo etwas: ein Füllventil am WC, ein tropfender Wasserhahn oder eine hängende Bewässerungszone. - Zu lange hoher Durchfluss. Ein geplatzter Schlauch oder ein Rohrbruch zeigt sich als hoher
flow_lpm, der viel länger anhält als eine Dusche oder ein Bad. Legen Sie den Schwellwert nach einer Woche Daten anhand Ihrer normalen Spitzen fest.
Das erste Muster braucht einen Zustand über die Zeit und passt gut in Node-RED oder einen kurzen Python-Subscriber. Das zweite ist ein einfacher Schwellwert; im ConnectMQ-Portal können Sie eine Schwellwert-Alarmregel auf flow_lpm anlegen und ausgelöste Alarme im Alarmprotokoll sehen. Für die punktuelle Erkennung unter Spülen und Waschmaschinen kombinieren Sie das mit dedizierten Sensoren aus dem Leitfaden zur Wasserleck-Erkennung: Der Zähler sagt Ihnen, dass Wasser fließt, der Bodensensor, wo.
Tages- und Monatsverbrauch
Der ESP32 veröffentlicht einen laufenden Zählerstand statt Tageswerten, und das ist Absicht: Zählerstände lassen sich leicht korrekt halten, und jeder Subscriber kann Tages-, Wochen- oder Monatsverbrauch ermitteln, indem er die Differenz zwischen erstem und letztem Zählerstand jedes Zeitraums bildet. Telegraf mit InfluxDB, der Utility-Meter-Helfer von Home Assistant oder ein kleines Skript, das in SQLite schreibt, arbeiten alle nach diesem Prinzip. Halten Sie das Gerät einfach und erledigen Sie die Kalenderrechnung nachgelagert, wo Zeitzonen und Abrechnungszeiträume leichter zu handhaben sind als auf einem Mikrocontroller.
Checkliste für Genauigkeit und Zuverlässigkeit
- Im ersten Monat wöchentlich mit dem Zifferblatt vergleichen und
LITRES_PER_PULSEoder die Sensorposition anpassen, wenn die Werte abweichen. - Auf Doppelzählungen prüfen, indem Sie abgemessene 10 Liter in einen Eimer laufen lassen; bei 1 L pro Impuls muss der Zähler um genau 10 Impulse steigen.
- Den Sensor vor Kondenswasser schützen. Zählerschächte und Kaltwasserleitungen schwitzen; verwenden Sie einen abgedichteten Sensor und halten Sie den ESP32 in einem trockenen Gehäuse.
- WLAN im Keller beachten. Schwache Signale führen zu Neuverbindungen; die retained Telemetrie und der Last-Will-Status machen Ausfälle sichtbar.
- Für alles, was den Zähler selbst betrifft, wenden Sie sich an Ihren Installateur oder Versorger.
Umstieg auf einen privaten Broker
Der Wasserverbrauch verrät Tagesabläufe und wann das Haus leer steht, ist also im Sinne der DSGVO schützenswert, und auf einem gemeinsam genutzten Broker könnte jeder auf Ihr Set-Topic veröffentlichen. Sobald der Leser funktioniert, wechseln Sie zu einem privaten Broker mit Zugangsdaten und TLS. Ein verwalteter MQTT-Broker wie ConnectMQ bietet Ihnen das, ohne dass Sie zu Hause etwas hosten müssen. Verwenden Sie WiFiClientSecure mit dem ISRG-Root-X1-Zertifikat für Let's Encrypt, Port 8883 und Ihre Zugangsdaten aus dem Portal:
#include <WiFiClientSecure.h>
WiFiClientSecure net; // statt 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");
Der Wasserverbrauch passt ganz natürlich neben Ihre Stromdaten aus einem Energiemonitor für Zuhause. In Gewerbe und Industrie gehört derselbe Impulszähler zum Energiemonitoring eines Standorts: Wasser-, Strom- und Druckluftzähler publizieren dort in den Unified Namespace (UNS) nach ISA-95, etwa acme/werk-stuttgart/versorgung/wasser/hauptzaehler/telemetry, sodass Verbräuche je Halle oder Linie auswertbar werden. Weitere Automatisierungsideen finden Sie im IoT-Automatisierungsleitfaden, Abwägungen zum Hosting im Überblick zum MQTT-Broker in der Cloud.
Verfolgen Sie Ihren Wasserverbrauch mit ConnectMQ
ConnectMQ bietet Ihrem Zählerleser einen privaten, TLS-gesicherten MQTT-Broker mit Live-Topic-Explorer und Schwellwert-Alarmregeln für durchflussbasierte Leckwarnungen. Erstellen Sie einen kostenlosen Serverless-Broker unter app.connectmq.com, ganz ohne Kreditkarte, und empfangen Sie Ihre ersten Messwerte innerhalb weniger Minuten.
Häufig gestellte Fragen
Kann ich jeden Wasserzähler mit MQTT auslesen?
Die meisten mechanischen Zähler lassen sich von außen mit einem Reed-, induktiven oder optischen Sensor auslesen oder mit einer Kamera, die die Ziffern liest. Smart Meter mit Funkprotokollen benötigen stattdessen einen passenden Empfänger.
Wie viele Liter entspricht ein Impuls?
Das hängt von Zähler und Sensor ab. Ein Sensor am Literrad liefert typischerweise einen Impuls pro Liter, Impulsmodule der Hersteller dagegen oft einen Impuls pro 10 Liter. Gleichen Sie zur Bestätigung mit dem Zifferblatt ab.
Geht der Zählerstand nach einem Stromausfall verloren?
Nicht mit dem obigen Sketch. Der Zählerstand wird bei Änderungen alle paar Minuten im Flash des ESP32 gespeichert, sodass höchstens die Impulse weniger Minuten verloren gehen können, und Sie können mit dem Set-Befehl neu synchronisieren.
Wie erkenne ich ein langsames Leck?
Achten Sie auf Durchfluss in jedem Intervall über einen langen Zeitraum, etwa zwei Stunden in der Nacht. In normalen Haushalten gibt es regelmäßig Phasen ohne Durchfluss, daher ist ein dauerhafter kleiner Durchfluss ein starkes Indiz für ein Leck.



