Verbrauch & Regenprognose im Blick

Das Home Assistant Zisternen-Dashboard für Verbrauch und Regenprognose mit dem Senvolon Füllstandmesser

Dieses How-To baut auf dem Trockenlaufschutz-Artikel auf und geht einen Schritt weiter: Statt nur vor dem Leerlaufen zu schützen, machen wir den Wasserverbrauch sichtbar und beantworten drei Fragen automatisch:

  • Wie viel Wasser habe ich diese Woche verbraucht?
  • Wie lange reicht die Zisterne bei aktuellem Verbrauch noch?
  • Wie viel Regen bekomme ich in den nächsten 7 Tagen – und wie viele Liter sind das für meine Zisterne?

Besonders spannend ist der dritte Punkt. Hier lernt das System den individuellen Ertragsfaktor Ihrer Zisterne komplett selbstständig an. Es vergleicht dazu einfach den gemessenen Regenzufluss mit der lokalen Wettervorhersage.

Voraussetzungen

  • Senvolon Füllstandmesser, per MQTT in Home Assistant integriert, mit aktivierter „Home Assistant"-Option (MQTT Discovery)
  • Home Assistant OS, Zugriff auf die /config-Dateien über ein Add-on wie File Editor oder Studio Code Server
  • Eine konfigurierte Wetter-Integration mit Vorhersage-Unterstützung (hier: Met.no)
  • Folgende Entitäten aus der MQTT-Discovery des Sensors:
Entität Bedeutung
sensor.level_sensor_fluid Füllstand in Litern
sensor.level_sensor_level Absoluter Füllstand in cm
sensor.level_sensor_distance Abstand zur Oberfläche
sensor.level_sensor_temperature Gehäusetemperatur
sensor.level_sensor_alert MIN/MAX-Alarm
sensor.level_sensor_rssi WLAN-Signalstärke
sensor.level_sensor_ip IP-Adresse

Architektur im Überblick

Vier Bausteine, die aufeinander aufbauen:

  1. Verbrauchszähler – der Füllstand ist kein Zähler, sondern schwankt in beide Richtungen (sinkt bei Verbrauch, steigt bei Regen/Nachfüllen). Ein utility_meter direkt auf dem Füllstand würde bei jedem Regenschauer negative Deltas verrechnen. Deshalb: ein Hilfszähler, der nur Abfälle aufsummiert.
  2. Regenzufluss – spiegelbildlich dazu ein zweiter Hilfszähler, der nur Anstiege aufsummiert.
  3. Reichweite – Füllstand geteilt durch den Wochendurchschnitt des Verbrauchs.
  4. Selbstkalibrierender Regenertrag – der Vergleich aus gemessenem Regenzufluss (Baustein 2) und der für den Tag vorhergesagten Regenmenge in mm ergibt über die Zeit einen empirischen Liter-pro-mm-Faktor für die eigene Zisterne, ganz ohne Annahmen zu Dachfläche oder Material.

Zugriff auf die Config-Dateien bei HAOS

Bei Home Assistant OS läuft der Zugriff z.B. über ein Add-on:

  • Einstellungen → Add-ons → Add-on Store
  • File Editor für einfache Textbearbeitung, oder
  • Studio Code Server für einen vollwertigen VS-Code-artigen Editor mit Syntax-Highlighting (empfohlen, wenn mehrere YAML-Dateien parallel bearbeitet werden)

Nach der Installation erscheint links in der Sidebar das jeweilige Editor-Icon, darüber gelangt man in den /config-Ordner.


Baustein 1: Verbrauchszähler

In eigener Sache: Diese Anleitung mischt Oberfläche und YAML. Was wäre Ihnen lieber, alles zum Klicken oder alles in einer Datei zum Kopieren? Kurze Mail an support@senvolon.de, wir bauen die nächsten How-tos danach.

1.1 Hilfszähler anlegen

Einstellungen → Geräte & Dienste → Helfer → + Helfer erstellen → Zahlenwert-Eingabe

  • Name: Zisterne Wasserverbrauch (kumuliert)
  • Minimum: 0, Maximum: 1000000, Schrittweite: 0.1
  • Maßeinheit: L

Entity-ID (automatisch generiert): input_number.zisterne_wasserverbrauch_kumuliert

1.2 Automation zum Aufsummieren

Einstellungen → Automationen → Automation erstellen → In YAML bearbeiten

alias: Zisterne Verbrauch tracken
description: >
  Addiert jeden Füllstandsabfall zum kumulierten Verbrauchszähler.
  Anstiege (Regen, Nachfüllen) werden bewusst ignoriert.
triggers:
  - trigger: state
    entity_id: sensor.level_sensor_fluid
conditions:
  - condition: template
    value_template: >
      {{ trigger.from_state is not none and trigger.to_state is not none
         and trigger.from_state.state not in ['unknown', 'unavailable']
         and trigger.to_state.state not in ['unknown', 'unavailable']
         and trigger.to_state.state | float(0) < trigger.from_state.state | float(0) }}
actions:
  - action: input_number.set_value
    target:
      entity_id: input_number.zisterne_wasserverbrauch_kumuliert
    data:
      value: >
        {{ states('input_number.zisterne_wasserverbrauch_kumuliert') | float(0)
           + (trigger.from_state.state | float(0) - trigger.to_state.state | float(0)) }}
mode: queued

1.3 Template-Sensor spiegeln

Der utility_meter braucht einen Sensor mit state_class: total_increasing als Quelle – ein input_number alleine reicht nicht. Deshalb wird der Wert gespiegelt:

Helfer → + Helfer erstellen → „Template" suchen → Sensor-Template

  • Name: Zisterne Wasserverbrauch
  • Zustand: {{ states('input_number.zisterne_wasserverbrauch_kumuliert') }}
  • Maßeinheit: L
  • Geräteklasse: Wasser
  • Zustandsklasse: Total Increasing
Stolperstein: Der Vorlage-Helfer-Typ heißt in der Suche schlicht „Template", nicht „Sensor" – eine Suche nach „sensor" findet ihn nicht, da sie nur nach Helfer-Typen mit „sensor" im Namen filtert (z. B. Ableitungssensor, Integralsensor).

1.4 Utility Meter (nur per YAML möglich)

Neue Datei utility_meter.yaml im /config-Wurzelverzeichnis anlegen:

zisterne_verbrauch_taeglich:
  source: sensor.zisterne_wasserverbrauch
  cycle: daily
zisterne_verbrauch_woechentlich:
  source: sensor.zisterne_wasserverbrauch
  cycle: weekly

In configuration.yaml einbinden:

utility_meter: !include utility_meter.yaml
Wichtig: In der ausgelagerten Datei fehlt das Top-Level-Wort (utility_meter:), das wird bereits durch den !include gesetzt. Die Datei startet direkt mit den Sensor-Namen bei Einrückungstiefe 0.

Danach: Einstellungen → System → Neu starten. Utility Meter registriert sich beim Boot – ein reines Config-Reload reicht dafür nicht aus, anders als bei Templates ohne Trigger.

Nach dem Neustart in Entwicklertools → Zustände prüfen: sensor.zisterne_verbrauch_taeglich und sensor.zisterne_verbrauch_woechentlich sollten existieren. Das Attribut last_period (Wert des zuletzt abgeschlossenen Zyklus) steht zu diesem Zeitpunkt noch auf 0 – das befüllt sich erst nach dem ersten vollständig durchlaufenen Zyklus.


Baustein 2: Regenzufluss

Exakt spiegelbildlich zu Baustein 1, nur mit umgedrehter Vergleichsrichtung.

2.1 Hilfszähler

input_number.zisterne_regenzufluss_kumuliert (gleiche Konfiguration wie oben).

2.2 Automation

alias: Zisterne Regenzufluss tracken
description: >
  Addiert jeden Füllstandsanstieg zum kumulierten Regenzufluss-Zähler.
  Setzt voraus, dass Anstiege ausschließlich durch Regen entstehen
  (keine aktive Nachfüllung/Pumpenbefüllung im Setup).
triggers:
  - trigger: state
    entity_id: sensor.level_sensor_fluid
conditions:
  - condition: template
    value_template: >
      {{ trigger.from_state is not none and trigger.to_state is not none
         and trigger.from_state.state not in ['unknown', 'unavailable']
         and trigger.to_state.state not in ['unknown', 'unavailable']
         and trigger.to_state.state | float(0) > trigger.from_state.state | float(0) }}
actions:
  - action: input_number.set_value
    target:
      entity_id: input_number.zisterne_regenzufluss_kumuliert
    data:
      value: >
        {{ states('input_number.zisterne_regenzufluss_kumuliert') | float(0)
           + (trigger.to_state.state | float(0) - trigger.from_state.state | float(0)) }}
mode: queued

2.3 Template-Sensor & Utility Meter

Analog zu 1.3: Sensor-Template Zisterne Regenzufluss (Zustand: {{ states('input_number.zisterne_regenzufluss_kumuliert') }}, Einheit L, Geräteklasse Wasser, Zustandsklasse Total Increasing).

utility_meter.yaml erweitern:

zisterne_verbrauch_taeglich:
  source: sensor.zisterne_wasserverbrauch
  cycle: daily
zisterne_verbrauch_woechentlich:
  source: sensor.zisterne_wasserverbrauch
  cycle: weekly
zisterne_regenzufluss_taeglich:
  source: sensor.zisterne_regenzufluss
  cycle: daily

Neustart erneut nötig.

Achtung: Dieser Ansatz setzt voraus, dass Füllstandsanstiege ausschließlich durch Regen entstehen. Wer in seinem Setup eine aktive Nachfüllung (z. B. Trinkwasser-Topup bei Trockenheit) betreibt, würde das fälschlich als Regen zählen – für dieses Szenario (reine Zisterne ohne Nachspeisung) ist das unkritisch.

Baustein 3: Reichweite

Reine State-Template-Logik, geht komplett über die UI.

Helfer → Vorlage → Sensor-Template

  • Name: Zisterne Reichweite
  • Zustand:
{% set wochenverbrauch = state_attr('sensor.zisterne_verbrauch_woechentlich', 'last_period') | float(0) %}
{% if wochenverbrauch > 0 %}
  {{ (states('sensor.level_sensor_fluid') | float(0) / (wochenverbrauch / 7)) | round(1) }}
{% else %}
  {{ none }}
{% endif %}
  • Maßeinheit: d
  • Geräteklasse und Zustandsklasse: leer lassen
Stolperstein: Eine naive Formel ohne Schutzabfrage (fluid / (last_period / 7)) wirft einen ZeroDivisionError in der Live-Vorschau, solange last_period noch 0 ist – also in der ersten Woche nach dem Einrichten. Die {% if %}-Abfrage mit {{ none }} im Else-Zweig sorgt stattdessen für einen sauberen unknown-Zustand, bis der erste Wochenzyklus durchgelaufen ist.

Baustein 4: Selbstkalibrierender Regenertrag

4.1 Kalibrierungs-Helfer

Zwei input_number-Helfer:

  • Zisterne Kalibrierung mm gesamt (Einheit mm, Minimum 0, Maximum 100000, Schrittweite 0.1)
  • Zisterne Kalibrierung Liter gesamt (Einheit L, Minimum 0, Maximum 1000000, Schrittweite 0.1)
Die Maßeinheiten sind fürs Rechnen nicht zwingend nötig (die Templates casten ohnehin mit | float(0)), machen die Helfer aber in der Übersicht und auf Dashboards sofort verständlich.

4.2 Kalibrierungs-Automation

Vergleicht täglich um 23:50 Uhr den gemessenen Regenzufluss des Tages mit der für den Tag vorhergesagten Regenmenge:

alias: Zisterne Regenkalibrierung täglich
description: >
  Vergleicht den gemessenen Regenzufluss mit der für heute prognostizierten
  Regenmenge und aktualisiert den empirischen Liter-pro-mm-Faktor.
triggers:
  - trigger: time
    at: "23:50:00"
actions:
  - action: weather.get_forecasts
    target:
      entity_id: weather.forecast_home
    data:
      type: hourly
    response_variable: forecast_data
  - variables:
      heute: "{{ now().strftime('%Y-%m-%d') }}"
      mm_heute: >
        {% set forecast = forecast_data['weather.forecast_home'].forecast %}
        {{ forecast
           | selectattr('datetime', 'match', heute)
           | map(attribute='precipitation')
           | map('float', 0)
           | sum
           | round(1) }}
      liter_heute: "{{ states('sensor.zisterne_regenzufluss_taeglich') | float(0) }}"
  - condition: template
    value_template: "{{ mm_heute | float(0) > 0.5 }}"
  - action: input_number.set_value
    target:
      entity_id: input_number.zisterne_kalibrierung_mm_gesamt
    data:
      value: "{{ states('input_number.zisterne_kalibrierung_mm_gesamt') | float(0) + mm_heute }}"
  - action: input_number.set_value
    target:
      entity_id: input_number.zisterne_kalibrierung_liter_gesamt
    data:
      value: "{{ states('input_number.zisterne_kalibrierung_liter_gesamt') | float(0) + liter_heute }}"
mode: single
weather.forecast_home durch die eigene Wetter-Entity-ID ersetzen (Entwicklertools → Zustände → nach weather. filtern).
Wichtige Einschränkung: weather.get_forecasts liefert typischerweise nur zukünftige Stunden ab dem Abrufzeitpunkt, nicht die bereits vergangenen Stunden des Tages. Regnet es also z. B. morgens kräftig, bleibt der Rest des Tages aber trocken, sieht die 23:50-Uhr-Abfrage davon nichts mehr – dieser Zeitraum liegt zu diesem Zeitpunkt bereits in der Vergangenheit. mm_heute bildet damit eher ab, was für den Rest des Tages ab dem Abrufzeitpunkt noch erwartet wurde, als was tatsächlich den ganzen Tag über gefallen ist. Bei einem über mehrere Stunden andauernden Regentag ist der Unterschied meist klein, bei kurzen Vormittagsschauern kann die Kalibrierung dadurch systematisch zu niedrige mm-Werte gegen die tatsächlich gemessenen Liter zählen – was den Ertragsfaktor künstlich nach oben verzerrt. Über viele Regentage gemittelt gleicht sich das größtenteils aus, ist aber kein exakter Messwert, sondern eine Annäherung.
Stolperstein: Met.no liefert das Vorhersage-Datum je nach HA-Version mit oder ohne Uhrzeit im ISO-Format. Falls selectattr('datetime', 'match', heute) keine Treffer liefert, match (matcht nur ab Zeichenkettenanfang) gegen search tauschen.

4.3 Ertragsfaktor-Sensor

Reine State-Template-Logik, geht über die UI:

Helfer → Vorlage → Sensor-Template

  • Name: Zisterne Ertrag pro mm
  • Zustand:
{% set mm = states('input_number.zisterne_kalibrierung_mm_gesamt') | float(0) %}
{% set liter = states('input_number.zisterne_kalibrierung_liter_gesamt') | float(0) %}
{% if mm > 5 %}
  {{ (liter / mm) | round(2) }}
{% else %}
  {{ 30 }}
{% endif %}
  • Maßeinheit: L/mm (als benutzerdefiniertes Element hinzufügen, da HA diese Einheit nicht kennt – unproblematisch, da keine Geräteklasse gesetzt ist und HA die Einheit somit nicht validiert)

Bis mehr als 5 mm kalibrierter Regen vorliegt, liefert der Sensor einen groben Platzhalterwert (30 L/mm), danach den empirisch gelernten Wert.

Wichtig zu verstehen: mm_gesamt und liter_gesamt werden niemals automatisch zurückgesetzt – der Ertragsfaktor ist also ein Lebenszeit-Durchschnitt seit dem allerersten Kalibrierungstag, kein gleitender Durchschnitt der letzten Tage oder Wochen. Das macht den Wert sehr stabil und ausreißerresistent (ein einzelner ungewöhnlicher Regentag verändert ihn nach vielen kalibrierten Tagen kaum noch), hat aber einen blinden Fleck: Ändert sich die reale Abflusscharakteristik mit der Zeit (Dach wird bemoost, Regenrinne setzt sich zu, Laubfall im Herbst), reagiert der Lebenszeit-Durchschnitt nur sehr träge darauf, weil die frühen, eventuell saubereren Jahre weiterhin mitgewichtet werden. Für den Einstieg ist der einfache Ansatz die pragmatischste Lösung – wer später merkt, dass sich der Wert über Jahre spürbar verschiebt, kann auf einen gleitenden Durchschnitt umstellen (z. B. nur die letzten 90 Kalibrierungstage berücksichtigen).

4.4 Regenertrag-Prognose (7 Tage)

Dieser Sensor braucht die trigger-basierte Template-Syntax mit weather.get_forecasts und response_variable – das kann kein UI-Helfer abbilden, nur ein YAML-Template mit eigenem trigger:-Block.

Neue Datei templates.yaml anlegen:

- trigger:
    - trigger: time_pattern
      hours: "/1"
  action:
    - action: weather.get_forecasts
      target:
        entity_id: weather.forecast_home
      data:
        type: daily
      response_variable: forecast_data
  sensor:
    - name: "Zisterne Regenertrag 7d"
      unique_id: zisterne_regenertrag_7d
      unit_of_measurement: L
      icon: mdi:weather-pouring
      state: >
        {% set forecast = forecast_data['weather.forecast_home'].forecast %}
        {% set regen_mm = forecast[:7] | map(attribute='precipitation') | map('float', 0) | sum %}
        {% set ertrag_pro_mm = states('sensor.zisterne_ertrag_pro_mm') | float(30) %}
        {{ (regen_mm * ertrag_pro_mm) | round(0) }}
      attributes:
        regen_mm_7d: >
          {% set forecast = forecast_data['weather.forecast_home'].forecast %}
          {{ (forecast[:7] | map(attribute='precipitation') | map('float', 0) | sum) | round(1) }}

In configuration.yaml einbinden:

template: !include templates.yaml

Neustart (auch trigger-basierte Templates brauchen einen echten Neustart, kein Hot-Reload).

Stolperstein: Der trigger-basierte Sensor feuert nicht sofort nach dem Neustart, sondern erst beim nächsten Intervall-Tick des time_pattern-Triggers (hier: zur nächsten vollen Stunde). Wer direkt nach dem Einrichten nachschaut und sensor.zisterne_regenertrag_7d noch bei 0 L bzw. unknown sieht, hat keinen Fehler gemacht – das System hat schlicht noch nicht ausgelöst. Zum schnellen Testen kann der Trigger kurzzeitig auf minutes: "/2" verkürzt werden (danach nicht vergessen, wieder auf hours: "/1" zurückzustellen und erneut neu zu starten, sonst ruft das System die Wetter-API unnötig oft auf).


Dashboard

Damit man bei der Anzahl an Entitäten nicht die Übersicht verliert, empfiehlt sich ein eigenes Dashboard mit dem neueren sections-View-Typ statt der klassischen Masonry-Ansicht – bei Masonry rutschen Karten je nach Höhe automatisch in beliebige Spalten, bei sections bleibt die Platzierung exakt so, wie man sie definiert.

Einstellungen → Dashboards → + Dashboard hinzufügen → Leeres Dashboard, dann über die drei Punkte oben rechts „In YAML bearbeiten":

title: Zisterne
views:
  - title: Übersicht
    path: zisterne
    icon: mdi:water-pump
    type: sections
    sections:
      - type: grid
        cards:
          - type: heading
            heading: Live-Messwerte
            heading_style: title
          - type: entities
            title: Füllstandmesser
            entities:
              - entity: sensor.level_sensor_fluid
                name: Füllstand
              - entity: sensor.level_sensor_level
                name: Absoluter Füllstand
              - entity: sensor.level_sensor_distance
                name: Abstand zur Oberfläche
              - entity: sensor.level_sensor_temperature
                name: Gehäusetemperatur
              - entity: sensor.level_sensor_alert
                name: Alarm

      - type: grid
        cards:
          - type: heading
            heading: Verbrauch & Reichweite
            heading_style: title
          - type: entities
            title: Verbrauchszähler
            entities:
              - entity: sensor.zisterne_verbrauch_taeglich
                name: Verbrauch heute
              - entity: sensor.zisterne_verbrauch_woechentlich
                name: Verbrauch diese Woche
              - type: attribute
                entity: sensor.zisterne_verbrauch_woechentlich
                attribute: last_period
                name: Verbrauch letzte Woche
                suffix: " L"
              - entity: sensor.zisterne_reichweite
                name: Wasser für

      - type: grid
        cards:
          - type: heading
            heading: Regenzufluss & Kalibrierung
            heading_style: title
          - type: entities
            title: Regen
            entities:
              - entity: sensor.zisterne_regenzufluss_taeglich
                name: Regenzufluss heute
              - entity: sensor.zisterne_ertrag_pro_mm
                name: Ertragsfaktor (gelernt)
              - entity: sensor.zisterne_regenertrag_7d
                name: Erwarteter Ertrag (7 Tage)
              - entity: input_number.zisterne_kalibrierung_mm_gesamt
                name: Kalibrierbasis mm
              - entity: input_number.zisterne_kalibrierung_liter_gesamt
                name: Kalibrierbasis Liter

      - type: grid
        cards:
          - type: heading
            heading: System & Rohzähler
            heading_style: title
          - type: entities
            title: Diagnose
            entities:
              - entity: sensor.level_sensor_rssi
                name: WLAN-Signal
              - entity: sensor.level_sensor_ip
                name: IP-Adresse
              - entity: input_number.zisterne_wasserverbrauch_kumuliert
                name: Verbrauch (Rohzähler)
              - entity: input_number.zisterne_regenzufluss_kumuliert
                name: Regenzufluss (Rohzähler)

Zudem lassen sich einzelnen Entitäten in das zuvor erstellte Pumpenschutz-Dashboard integrieren. 


Einlaufphase einplanen

Nach dem Neustart ist das System technisch fertig, liefert aber noch keine vollständig aussagekräftigen Werte:

  • Reichweite: valide erst nach dem ersten kompletten Wochenzyklus (cycle: weekly startet standardmäßig Montag 00:00 Uhr)
  • Ertragsfaktor: valide erst nach kumuliert mehr als 5 mm kalibriertem Regen, also nach den ersten ein bis zwei nennenswerten Regentagen
  • Verbrauch/Regenzufluss heute/diese Woche: sofort korrekt, da direkt aus Live-Messwerten abgeleitet

Anhang: Alle Entitäten auf einen Blick

Kurzreferenz zum Nachschlagen – die vollständige Erklärung und der zugehörige YAML-Code stehen jeweils im entsprechenden Abschnitt oben.

Grund-Helfer (Zahlenwert-Eingaben):

  • input_number.zisterne_wasserverbrauch_kumuliert – läuft nur hoch, addiert jeden Füllstandsabfall
  • input_number.zisterne_regenzufluss_kumuliert – läuft nur hoch, addiert jeden Füllstandsanstieg
  • input_number.zisterne_kalibrierung_mm_gesamt – Summe aller kalibrierten Regen-Millimeter seit Start
  • input_number.zisterne_kalibrierung_liter_gesamt – Summe der an diesen Regentagen tatsächlich gemessenen Liter

Gespiegelte Sensoren:

  • sensor.zisterne_wasserverbrauch – Verbrauchszähler mit total_increasing, macht ihn für Utility Meter nutzbar
  • sensor.zisterne_regenzufluss – dasselbe für den Regenzufluss

Utility Meter:

  • sensor.zisterne_verbrauch_taeglich – Verbrauch seit Mitternacht, resettet täglich
  • sensor.zisterne_verbrauch_woechentlich – Verbrauch seit Montag, resettet wöchentlich, liefert last_period
  • sensor.zisterne_regenzufluss_taeglich – Regenzufluss seit Mitternacht, wird von der Kalibrierung abgefragt

Berechnete Sensoren:

  • sensor.zisterne_reichweite („Wasser für") – Füllstand geteilt durch Wochendurchschnitt, in Tagen
  • sensor.zisterne_ertrag_pro_mm – gelernter Liter-pro-mm-Faktor, Lebenszeit-Durchschnitt
  • sensor.zisterne_regenertrag_7d – 7-Tage-Regenprognose in Litern, stündlich aktualisiert

Automationen:

  • Zisterne Verbrauch tracken – erkennt Füllstandsabfälle, füttert den Verbrauchszähler
  • Zisterne Regenzufluss tracken – erkennt Füllstandsanstiege, füttert den Regenzufluss-Zähler
  • Zisterne Regenkalibrierung täglich – vergleicht täglich 23:50 Uhr Vorhersage mit Messwert, füttert den Ertragsfaktor