Zum Inhalt springen
labkompass

Logbuch#homeos#energie#shelly#zeitreihen#monitoring

Energie-Auswertung: drei Zahlen, die falsch waren, bevor die Historie richtig wurde

Von Niclas Hennrich · veröffentlicht · geschehen am


BuildIm Einsatz

Selbst gebaut und in Betrieb genommen. Gehört zum Vorhaben HomeOS — Control Center mit drei Säulen.

Eingefrorene Leistung im Export (real 44 W)
487W
Frische-Grenze für Messwerte
180s
366 Tage in Tagesauflösung
16ms

HomeOS ist mein selbst gebautes Control Center fürs Homelab, aus dem Infrastruktur-NOC gewachsen — drei Säulen: Infrastruktur, Haus (Smart Home) und Family (Haushalt). Die Haus-Säule hängt seit ein paar Tagen an fünf echten Shelly-Messpunkten, jeder mit Leistungs- und Energiezähler. Echte Historie gibt es seit dem 29. August, etwa 20 Uhr.

Was ich wollte: Aus der Live-Ansicht (Leistung jetzt, vier kWh-Fenster, 24-Stunden-Verlauf) eine Auswertung machen: richtige Kalendertage, Monatsverläufe, faire Vergleiche, Kosten, Drilldown pro Gerät — auf einem Datenmodell, das später Smart Meter, PV und Batterie trägt, ohne den Kern neu zu bauen.

Zuerst das Audit. Bevor ich etwas anbaue, will ich wissen, woher jede Zahl kommt und ob sie überhaupt stimmen kann. Drei Befunde.

Erstens flossen stale Wattwerte in alle Summen. Ging ein Gerät offline, behielt es seinen letzten Leistungswert als „jetzt". Schlimmer: Mein eigener Metrics-Export lieferte diese eingefrorenen Werte bei jedem Scrape erneut an die Zeitreihen-Datenbank. Die Kurve zeigte dauerhaft rund 487 W von Steckdosen, die niemand mehr erreichte — lokal nachgemessen waren es 44 W frisch.

Zweitens war „heute" der UTC-Kalendertag, weil der Container keine Zeitzone kannte. Der Energie-Tag wechselte um 02:00 Uhr Sommerzeit.

Drittens — den fand ich erst beim Bauen — richtet VictoriaMetrics cache-fähige Range-Queries auf Vielfache des Steps seit der Epoche aus. Bei einem Tages-Step landen die Auswertungspunkte auf UTC-Mitternacht, egal was man anfragt. Tückisch: Kurze Zeiträume blieben unausgerichtet, erst lange kippten. nocache=1 für die Kalendertag-Abfrage löst es.

Was ich gebaut habe: Eine Frische-Regel für alles. Ein Wert ist frisch, wenn das Gerät online ist und die Messung jünger als 180 Sekunden. Sie gilt für Summen, Übersicht, Entity-API und den Export. Stale Werte erzeugen keinen Serienpunkt mehr — die Lücke ist die ehrliche Form. Und Zähler verzeihen sie: Taucht das Gerät wieder auf, holt increase die Differenz als ganz normalen Zuwachs nach.

Kalendertage in Europe/Berlin, DST-fest: 23- und 25-Stunden-Tage werden als eigene Segmente gerechnet. Historie ohne zweite Ablage — keine Rollup-Tabellen, die Entscheidung vom Speicher-Tausch gilt weiter. Tages- und Monatsreihen entstehen zur Abfragezeit aus den Zähler-Serien; dadurch sind sie idempotent und Late-Data-fest, ohne dass ich es beweisen muss. Lücken bleiben None, und die API sagt stundengenau, seit wann es Daten gibt, statt Nullen zu erfinden.

Fairness: heute gegen „gestern bis zur gleichen Uhrzeit", Monat gegen „Vormonat, gleiche Tage". Und liegt das Vergleichsfenster vor dem Historienbeginn, gibt es kein Delta. Das lernte ich am ersten Datentag: „Gestern +356 % gegenüber dem Vortag" — der Vortag war ab 20 Uhr gemessen. Dieselbe korrekte Prozentrechnung wird zur Falschaussage, wenn eine Seite nur teilweise gemessen ist.

Dazu ein Tarifmodell als Gültig-ab-Kette: Historische Kosten rechnen mit dem damals gültigen Preis, Kosten gibt es nur für Kalenderzeiträume, der Grundpreis wird nie einem Gerät zugerechnet, und ohne hinterlegten Tarif gibt es keine geratenen Preise. Ein Tarif ist eine Historie, kein Setting.

Kontrolle: Zählerdifferenz eines Messpunkts seit Mitternacht 1,237 kWh, die API sagt 1,238 kWh — Rundung. 366 Tage in Tagesauflösung kommen in 16 ms, kein Cache nötig.

Was ich mitnehme: Ein Export ist auch ein Messgerät — wer Zustände re-exportiert, exportiert deren Alter mit. Query-Engines haben Meinungen über Zeit: Wer Kalenderfenster abfragt, muss die Auswertungszeitpunkte prüfen, nicht nur die Werte. Und überall steht weiterhin dran: gemessene Verbraucher ≠ Hausverbrauch.