Gas- und Wasserzähler mit Kamera auslesen

Schema: Eine ESP32-Kamera liest die Ziffern eines Zählers, sendet den Wert per MQTT an Home Assistant, ein Filter verwirft Ausreißer, bevor sie in die Statistik gehen

Verfasst von

in

Meine Gas- und Wasserzähler sind ganz normale mechanische Zähler mit Ziffernrollen, ohne Schnittstelle. Trotzdem will ich den Verbrauch in Home Assistant sehen, im Energie-Dashboard und auf dem Handy. Die Lösung ist eine kleine ESP32-Kamera vor jedem Zähler mit der freien Firmware „AI on the Edge“. Sie fotografiert die Ziffern, erkennt sie mit einem neuronalen Netz direkt auf dem Chip und schickt den Zählerstand per MQTT an Home Assistant. Das klingt nach einem Wochenendprojekt, und der Aufbau ist es auch. Der Betrieb ist es nicht. Hier geht es deshalb vor allem um das, was danach kam: Lesefehler, Spiegelungen, ein getauschter Zähler und ein Filter, der Ausreißer abfängt, bevor sie die Statistik ruinieren.

Schema: Eine ESP32-Kamera liest die Ziffern eines Zählers, sendet den Wert per MQTT an Home Assistant, ein Filter verwirft Ausreißer, bevor sie in die Statistik gehen

Der Aufbau

Vor jedem Zähler hängt ein ESP32 mit Kamera und eingebauter LED. Die Firmware läuft bei mir in Version 16.0.0. Version 16.1.0 ist verfügbar, ich habe sie aber nicht eingespielt: Sie ändert unter anderem die MQTT Discovery, und das könnte Entitäten in Home Assistant umbenennen, sodass Dashboards und Filter ins Leere zeigen. Ich warte, bis die Erkennung stabil ist, und spiele sie dann ein Gerät nach dem anderen ein. Sie macht in festen Abständen ein Foto, richtet es aus, schneidet die einzelnen Ziffern als sogenannte ROIs (Regions of Interest) aus und lässt jede Ziffer von einem kleinen Modell erkennen. Analoge Zeiger, wie sie Wasserzähler für die Stellen hinter dem Komma haben, erkennt ein eigenes Modell.

Die beiden Zähler sind recht verschieden:

WasserzählerGaszähler
Anzeige4 Ziffernrollen und 4 Zeiger8 Ziffernrollen, davon 3 hinter dem Komma
Erkennung heutestabil, ohne FehlerStellen hinter dem Komma unzuverlässig
BesonderheitZähler wurde kürzlich getauschtLED spiegelt sich im Sichtfenster

Die Werte gehen per MQTT an den Mosquitto-Broker von Home Assistant. Die Firmware nutzt dabei MQTT Discovery, die Sensoren tauchen also ohne Konfiguration in Home Assistant auf.

Die Geräte haben eine Web-API

Jedes Gerät hat eine Weboberfläche und eine einfache HTTP-API. Für die Fehlersuche ist das praktisch, weil ich Wert, Foto und Vorwert ohne Klicken abfragen und setzen kann:

GET /json                                    # aktueller Wert und Status
GET /capture_with_flashlight?flashtime=3000  # Foto mit LED
GET /setPreValue?value=4.6905&numbers=main   # Vorwert setzen
GET /reboot                                  # Neustart

Die Konfiguration steckt in einer config.ini auf der SD-Karte. Ich lade sie herunter, ändere sie und lade sie wieder hoch. Kameraeinstellungen gelten erst nach einem Neustart: Wenn die neue LED-Helligkeit nichts ändert, fehlt meist der Neustart. Auf dem Gerät liegt eine config.bak, die älteren Fassungen meiner Änderungen habe ich aber nicht dauerhaft abgelegt. Wenn eine SD-Karte stirbt, fange ich mit der Einmessung von vorn an.

Die Firmware bringt von Haus aus weder TLS noch eine Anmeldung für ihre API mit. Wer im Heimnetz an das Gerät kommt, kann Vorwerte setzen oder es neu starten. Die Zähler gehören deshalb in einen Netzbereich, den man kontrolliert, ohne Zugang von außen.

Fehlerquelle 1: der getauschte Wasserzähler

Eines Tages lieferte der Wasserzähler nur noch Unsinn. Die Ursache war banal: Der Zähler war getauscht worden. Die Kamera sah ein neues Zifferblatt, aber die Firmware arbeitete mit den alten ROIs, dem alten Referenzbild und dem alten Vorwert. Der neue Zähler startete fast bei null, weit unter dem letzten Stand des alten. Jeder neue Wert war also kleiner als der Vorwert, und die Firmware meldete eine negative Änderungsrate.

Die Lösung war eine komplette Neueinmessung:

  • LED-Helligkeit von 3 auf 20 erhöht, Helligkeit und Kontrast der Kamera auf 0.
  • Automatische Ausrichtung aus, weil die Kamera fest montiert ist.
  • Neues Referenzbild, neue ROIs für Ziffern und Zeiger.
  • Vorwert auf den echten Stand des neuen Zählers gesetzt.

Seitdem liest der Wasserzähler fehlerfrei. Das Gerät war also nicht kaputt, es schaute nur auf ein Bild, das es nicht kannte.

Fehlerquelle 2: Spiegelung und Unschärfe am Gaszähler

Beim Gaszähler spiegelte sich die LED im Sichtfenster genau über der fünften und sechsten Ziffer. Die Erkennung verwechselte dort ständig Ziffern. Die Lösung war mechanisch: Ich habe die Kamera um 180 Grad gedreht und das Bild in der Firmware mit CamHmirror und CamVflip wieder aufgerichtet. Dazu kamen eine schwächere LED (von 25 auf 12), neue ROIs für alle acht Stellen und eine Plausibilitätsprüfung direkt im Gerät:

# Auszug aus der config.ini des Gaszählers (Nachverarbeitung)
MaxRateType = RateChange
MaxRateValue = 0.07
CheckDigitIncreaseConsistency = true

RateChange begrenzt die Änderung auf 0,07 m³ pro Minute. CheckDigitIncreaseConsistency prüft, ob der Übertrag zwischen den Stellen zusammenpasst. Ich habe außerdem mehrere andere Ziffernmodelle ausprobiert. Keines war besser als das ursprüngliche.

Die Stellen hinter dem Komma erkennt der Gaszähler weiterhin nicht zuverlässig. Das Bild ist unscharf, und der Fokus der Kamera muss nachgestellt werden.

Der zweite Filter: Plausibilität in Home Assistant

Der Filter in der Firmware fängt viel ab, aber nicht alles. Ein einziger falsch erkannter Wert reicht, um die Verbrauchsstatistik in Home Assistant dauerhaft zu verfälschen. Wie dauerhaft, habe ich gesehen, als ich nachgezählt habe: In der Statistik des rohen Wasserzählers standen durch Fehlmessungen über 40.000 m³, mehr als ein Haushalt je verbraucht.

Deshalb gibt es eine zweite Stufe in Home Assistant. Ein Paket mit Template-Sensoren erzeugt je Zähler einen gefilterten Sensor. Er übernimmt einen neuen Wert nur, wenn dieser nicht sinkt und höchstens um eine plausible Menge steigt: 4 m³ pro Stunde beim Gas, 3 m³ pro Stunde beim Wasser, jeweils plus 0,05 m³ Spielraum. Sonst bleibt der letzte gültige Wert stehen. Den Rohwert legt der Sensor als Attribut ab, damit ich sehe, was das Gerät eigentlich gemeldet hat.

Vereinfacht sieht die Logik so aus. Das ist eine Skizze, nicht meine Datei eins zu eins:

template:
  - trigger:
      - platform: state
        entity_id: sensor.watermeter_value
    sensor:
      - name: "Wasserzähler gefiltert"
        unit_of_measurement: "m³"
        device_class: water
        state_class: total_increasing
        state: >
          {% set neu = trigger.to_state.state | float(-1) %}
          {% set alt = this.state | float(-1) %}
          {% if alt < 0 %}{{ neu }}
          {% else %}
            {% set h = (now() - this.last_changed).total_seconds() / 3600 %}
            {% if neu >= alt and neu <= alt + 3 * h + 0.05 %}{{ neu }}{% else %}{{ alt }}{% endif %}
          {% endif %}
        attributes:
          rohwert: "{{ trigger.to_state.state }}"
Entscheidung des Filters in Home Assistant: Ein neuer Rohwert wird nur übernommen, wenn er nicht sinkt und höchstens um die plausible Menge steigt, sonst bleibt der letzte gültige Wert

Alle Dashboards und das Energie-Dashboard nutzen nur noch die gefilterten Sensoren. Die Datei liegt in meinem Git-Repository für die Home-Assistant-Konfiguration und kam per Merge-Request hinein. Einen Neustart brauchte es nicht, ein Neuladen der Templates genügt.

Eine Schwäche hat der Filter: Gibt es einen echten Sprung, etwa nach einem Zählertausch oder nach längerem Ausfall des Geräts, lehnt er jeden neuen Wert ab. Dann lösche ich die gefilterte Entität in den Einstellungen. Der nächste Rohwert wird ungeprüft übernommen, danach greift der Filter wieder.

Die Statistik bereinigen, aber mit Sicherung

Mit dem neuen Filter war die alte Statistik immer noch falsch. Ich habe die Langzeitstatistik der beiden Rohsensoren deshalb gelöscht. Vorher habe ich sie als CSV gesichert und die alten Einstellungen des Energie-Dashboards exportiert. Die Statistik der gefilterten Sensoren beginnt mit dem Tag der Umstellung neu. Beim Gas verschwindet damit die Historie seit Frühjahr 2024 aus dem Dashboard. Eine Historie mit 40.000 m³ Wasser war aber nicht zu retten.

Offen ist am Gaszähler die Prüfung vor Ort: Spannung, WLAN und SD-Karte, denn das Gerät war zwischendurch offline. Solange es nicht sendet, fehlen die Gaswerte im Dashboard.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht, deine IP-Adresse wird nicht gespeichert. Kommentare erscheinen erst nach Freigabe. Was mit deinen Angaben passiert, steht in der Datenschutzerklärung. Pflichtfelder sind mit * markiert.