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
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.