Smarte Wasserzähler

Von | Juli 12, 2024

Wer seinen Wasserzähler in seinem Smarthome auslesen möchte, steht häufig vor der Herausforderung, dass die Installierten Zähler entsprechend alt sind – und damit über noch keinerlei Möglichkeiten verfügen, direkt irgendwo angebunden zu werden.

Eine Häufige Variante ist daher, den Zählerstand mittels einem kleinen Kameramodul (z.B. esp-cam) abzufotografieren und die Zählerstände dann via KI-Implementierung (AI-on-the-Edge) zu interpretieren.

Ich kann es nicht genau beschreiben warum – aber irgend etwas stört mich persönlich bei der Implementierung einer solchen Lösung – daher habe ich mich entschlossen, dort, wo ich den Wasserverbrauch ermitteln möchte, die Vorhandenen Zähler (sofern möglich) zu ersetzen bzw. weitere zu installieren.

Hierzu nutze ich Zähler, welche direkt mit einem Impulsgeber ausgestattet sind.
Diese gibt es in verschiedenen Varianten – 1 Liter pro Impuls, oder 0,25 Liter pro Impuls – sowohl für Kaltwasser, wie auch für Warmwasser.
Ein kleines Metall-Plättchen im Zählwerk sorgt hierbei bei jeder Umdrehung für einen Impuls, welcher dann über z.B. einen ESP registriert und verarbeitet werden kann.

Nun benötigt es zum Auslesen der Sensorwerte noch ein klein wenig „Computer-Technik“.
In meinem Fall übernimmt dies ein ESP32 – oder ein ESP8266, je nachdem, was gerade da ist – und ob man u.U. am Einsatzort noch zusätzlich einen Bluetooth-Proxy benötigen könnte, oder nicht 🙂

Der Code des ESP wird komplett über ESPHome erstellt.
Hierfür nutze ich die Komponente „pulse_meter“ von ESPHome.

sensor:
  - platform: pulse_meter
    id: cold_water_meter_pulse
    name: 'Cold Water Meter - FlowRate'
    unit_of_measurement: 'l/min'
    device_class: volume_flow_rate
    state_class: measurement
    internal_filter: 100ms
    accuracy_decimals: 0
    pin:
      number: GPIO14
      mode: INPUT_PULLUPCode-Sprache: JavaScript (javascript)

Hiermit bekommen wir schon einmal die Information der Durchfluss-Menge, also wie viel Liter pro Minute durch den Zähler fließen.
Wir nutzen dabei einen Filter (internal_filter) von 100ms, welcher kürzere Impulse ignoriert.
Hier muss man sich ggf. mit testen an den korrekten Wert seines Zählers heran tasten – der Filter dient letztendlich dazu, die Fehlerrate zu reduzieren.

Um jetzt aber an brauchbare Daten für das Energie-Dashboard zu kommen, brauchen wir noch die gezählten Impulse, also wie viel Liter bzw. Kubikmeter Wasser tatsächlich geflossen sind.

Dazu erweitern wir den Sensor um die Angabe „total“

    total:
      name: 'Cold Water Meter - Total m³'
      id: cold_water_meter_total
      unit_of_measurement: 'm³'
      accuracy_decimals: 3
      state_class: total_increasing
      device_class: water
      filters:
        - multiply: 0.001Code-Sprache: JavaScript (javascript)

hiermit bekommen wir nun die Information, wie viel m³ durch den Zähler geflossen sind – allerdings, mit einem Neustart des ESPHome werden diese Zähler immer wieder zurück gesetzt.

Für das EnergyDashboard ist das kein Problem, dadurch dass als state_class „total_increasing“ angegeben wurde, weiß HomeAssistant, wie es mit diesen Werten für die Statisitk umgehen muss.

Wollen wir uns aber den Zählerstand als solchen auf unserem Dashboard ausgeben, wäre es sinnvoll, wenn wir den Wert irgendwie speichern könnten.
Und dann haben die Wasseruhren ja meistens bereits ein paar m³ auf der Uhr, wenn wir sie erhalten… dies sollte ggf. auch berücksichtigt werden, wenn wir z.B. den Zählerstand mal irgendwann an den Versorger übermitteln wollen ohne ständig in den Keller zu laufen dafür 😉

Hier benötigen wir daher noch ein paar Unterstützende Elemente…

In HomeAssistant legen wir uns als erstes einen Helfer vom Typ „input_number“ an.
Er bekommt die folgende Konfiguration:

Wichtig sind hier die „Step size“, Unit of Measurement und die Maximale größe…
Der rest kann beliebig vergeben werden und wir müssen uns die Entity_ID lediglich merken um sie in ESPHome zu nutzen.

In den „Sensor“ Block von HomeAssistant kommt jetzt unser angelegter Helfer dazu:

  - platform: homeassistant
    id: store_count
    entity_id: input_number.water_meter_store
    accuracy_decimals: 3
    internal: False
    unit_of_measurement: "m³"
    state_class: totalCode-Sprache: PHP (php)

Zusätzlich müssen wir uns eine Globale Variable in ESPHome anlegen, in welcher wir die Werte unseres Zählers speichern.

globals:
   - id: water_total_previous
     type: float
     restore_value: no
     initial_value: '0'Code-Sprache: JavaScript (javascript)

Nun erweitern wir den „total“ Block um eine Lambda Funktion:

      on_value:
        then:
          - lambda: |-
              float y = round(x * 1000) / 1000;
              id(store_count).state = id(store_count).state - id(water_total_previous) + y ; 
              id(water_total_previous) = y ;
              ESP_LOGD ("global","%f", id(water_total_previous));
              ESP_LOGD ("store","%f", id(store_count).state);
          - homeassistant.service:
              service: input_number.set_value
              data:
                entity_id: input_number.water_meter_store
                value: !lambda return id(store_count).state;Code-Sprache: JavaScript (javascript)

Letzendlich updaten wir damit den angelegten Helfer bei jeder State-Änderung um den neuen Wert.
Wenn unsere Wasser-Uhr also z.B. beim Einbau schon 0,031 m³ angezeigt hatte, und wir nun 6 L Wasser durch laufen lassen, zeigt unser Helfer 0,037 m³ an.

Jetzt wollen wir uns der Einfachheit halber auch noch den Verbauch in Litern anzeigen lassen, auch, wenn das EnergyDashboard diese Umwandlung von sich aus vornimmt – für unser Dashboard ist das einfach bequemer 🙂

Dazu nutzen wir die „COPY“ platform in ESPHome, da wir keinen weiteren Sensor anlegen können, welcher den gleichen IO Port nutzt.

  - platform: copy
    name: 'Cold Water Meter - Total L'
    unit_of_measurement: 'L'
    accuracy_decimals: 0
    state_class: total_increasing
    device_class: water
    source_id: cold_water_meter_total
    filters:
      - multiply: 1000Code-Sprache: JavaScript (javascript)

Unser ESP-Code sieht gesamt also wie folgt aus:

globals:
   - id: water_total_previous
     type: float
     restore_value: no
     initial_value: '0'

sensor:
  - platform: pulse_meter
    id: cold_water_meter_pulse
    name: 'Cold Water Meter - FlowRate'
    unit_of_measurement: 'l/min'
    device_class: volume_flow_rate
    state_class: measurement
    internal_filter: 100ms
    accuracy_decimals: 0
    pin:
      number: GPIO14
      mode: INPUT_PULLUP

    total:
      name: 'Cold Water Meter - Total m³'
      id: cold_water_meter_total
      unit_of_measurement: 'm³'
      accuracy_decimals: 3
      state_class: total_increasing
      device_class: water
      filters:
        - multiply: 0.001
      on_value:
        then:
          - lambda: |-
              float y = round(x * 1000) / 1000;
              id(store_count).state = id(store_count).state - id(water_total_previous) + y ; 
              id(water_total_previous) = y ;
              ESP_LOGD ("global","%f", id(water_total_previous));
              ESP_LOGD ("store","%f", id(store_count).state);
          - homeassistant.service:
              service: input_number.set_value
              data:
                entity_id: input_number.water_meter_store
                value: !lambda return id(store_count).state;

  - platform: copy
    name: 'Cold Water Meter - Total L'
    unit_of_measurement: 'L'
    accuracy_decimals: 0
    state_class: total_increasing
    device_class: water
    source_id: cold_water_meter_total
    filters:
      - multiply: 1000

  - platform: homeassistant
    id: store_count
    entity_id: input_number.water_meter_store
    accuracy_decimals: 3
    internal: False
    unit_of_measurement: "m³"
    state_class: totalCode-Sprache: PHP (php)

Wer möchte, kann nun noch weitere Komponenten und Optionen hinzufügen – in meinem Fall ist das ein Bluetooth-Proxy, ein paar zusätzliche Buttons und Sensoren, wie z.B. Uptime, Wifi-Signalstärke und so weiter.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert