Plant Telemetry — Speicherstand und Zähler an uns schicken
POST /v1/plant/telemetry — SOC % und Zähler (kWh) regelmäßig senden. Loxone: Nur Telemetrie oder im Paket Hours & Telemetrie. Telemetrie-Softcap Community 2000/Tag — frisst nicht den Fair-Use-/Billable-Pool (200/Tag).
Was macht diese Funktion?
Ihr Haus schickt regelmäßig zwei Messwerte:
1. SOC % — wie voll ist die Batterie? (z. B. 40 %) 2. Zählerstand kWh — wie viele Kilowattstunden hat der Bezugszähler bisher angezeigt? (eine steigende Zahl, z. B. 3725,4 — nicht „Verbrauch heute“)
Wir speichern das am API-Key (Ihrer Anlage). Daraus lernen wir über Tage, wie Ihr Haus typischerweise verbraucht. Das verbessert die Empfehlungen von Hours Demand. Jeder SOC-Ping wird zusätzlich als Historie gespeichert (ca. 15‑Min-Rhythmus), damit die Anlagenprognose den Speicherverlauf zeigen kann.
Im Portal unter Anlagenprognose und in der Sparvo-App (Startseite + Anlage) sehen Sie grafisch:
1. Speicherstand % 2. Tagesverbrauch heute (kWh) — bis zur ersten Differenz „warte auf Zählerdaten“, nie der Roh-Zählerstand 3. Geschätzter Gesamttagesverbrauch (kWh) 4. Aktueller Zählerstand seit Baseline-Datum (kWh) — Label „seit {Datum}“ (erste Übertragung bzw. letzter Reset)
Die Live-Leiste zeigt nur die Werte — ohne Methoden-Hinweis unter dem geschätzten Tagesverbrauch. Die Schätzung kommt intern aus Zählerhistorie (recency-gewichtet, Spike-gedämpft; heute plus Same-Day-Overlay über die WD/WE-Stundenform, nicht Uhrzeit × 24) bzw. Jahres÷365 bis ≥1 vollem Tag. Dieselbe Zahl wie Hours Rest-heute und Outlook-D0. Hours-Explain „Bis heute früh“ nutzt für die Kurzfrist-Cover-Nacht zusätzlich Teilstunde + Recent-Rate (v1.9) — nicht identisch mit dem Kalendertag-Summenwert oben. Ab ≥1 vollem Zählertag schreiben wir den Mittelwert vollständiger Tage seit Zählerstart × 365 (auf 100 kWh aufgerundet) ins Anlagenprofil — auch bei einem SOC-only-Ping, sobald Historie da ist. Tages-/Rest-heute-Schätzung bleibt recency-Typical. Details: Hours Demand.
Die Live-Leiste aktualisiert sich automatisch etwa alle 10 Minuten (aktive Hours-Session ~90 s, nur bei charge_now genau 1/"1" und nicht latched — nie Number(true)=1) (ohne Seiten-Reload), solange der Tab sichtbar ist — inkl. Zeitstempel „Aktualisiert …“. Endpunkte: Portal GET /plant-outlook/live-telem, Sparvo GET /api/live-telem.
Auf /plant-outlook und Sparvo /plant darunter (Reihenfolge: Live-Leiste → Hours-Erklärung → PV-Chart):
- Start-Speicherstand (manuell) — Slider nur als Fallback, wenn noch keine Live-Telemetrie kommt (bei Live-SOC gesperrt).
- Zähler zurücksetzen — nächster EMS-Ping = neuer Startwert.
SOC, Tagesverbrauch und Zählerstand erscheinen nur in der Live-Leiste, nicht noch einmal in separaten Karten. Ohne Live-Telem zeigt das Portal die Werte weiterhin in der Telemetrie-Karte (Fallback).
Portal-Slider: Sobald POST /v1/plant/telemetry einen SOC liefert (soc_source=hours_api), überschreibt er den Slider-Wert und sperrt den Slider (ca. 36 h Frische). Ohne frischen API-SOC ist der Slider wieder freigegeben.
Alltagsbeispiel: Wie eine Fitness-App, der Sie täglich Gewicht und Schritte schicken — nur eben SOC und Stromzähler.
Wann nutzen?
- Sie haben eine Batterie / ein EMS
- Sie wollen gute Hours-Empfehlungen, nicht nur Schätzungen
Telemetry speichert SOC und Zähler. Ein SOC-Ping aktualisiert außerdem loxone.d0_soc_eod im Decide-PV-Pack (Mitternachts-Prognose ab Live-SoC; PV und Netz-kWh der laufenden Stunde nur Restminuten, siehe PV-Forecast). Ausnahme: liegt der SoC nur noch 10 Prozentpunkte über dem Mindest-SoC (dann nochmal bei 5 pp und am Minimum) — oder steigt er spiegelbildlich wieder (Floor → 5 pp → 10 pp → Headroom) — oder war die letzte Hours-Session aktiv (charge_now==1) und live SoC ≥ Session-Stopp (Session-Complete, Debounce 120 s) —, startet der Server intern async einen Hours-Decide — Snapshot + PV-Pack + optional Webhook plant.plan_updated. Das zählt nicht gegen den Fair-Use-/Billable-Pool. Loxone-Extract liest die neue Entnahme-Cap (O12) erst beim nächsten Hours-Decide (:00 / SOC-Stufe / I6), sofern kein Webhook den Plan holt. Sofort-Replan am Session-Stopp: Extract v1.23 O5 (PulseSessionStop) → Fetch I5+I6 (Telemetrie + Decide) — kein Mid-Poll-Fetch nur aus Extract. Sticky Latch (charge_latched, charge_stop_hysteresis_pp = Stopp−H) lebt im Decide-Publish (§6.7) — Telemetrie startet den Replan, schreibt O3/O12 aber nicht selbst.
Wichtig: Kontingent
Telemetry zählt nicht gegen den Fair-Use-/Billable-Pool. Sie dürfen also öfter „pingen“ (mit Softcap, siehe Rate Limits).
Endpoint
POST https://api.spotpriceapi.com/v1/plant/telemetry
curl -X POST https://api.spotpriceapi.com/v1/plant/telemetry \
-H "Content-Type: application/json" \
-H "X-API-Key: sf_live_YOUR_KEY" \
-d "{
\"battery\": { \"soc_pct\": 40 },
\"meter\": { \"import_kwh_total\": 3725.4 }
}"
Erster Ping vs. später
| Situation | Was passiert |
|---|---|
| Erster Zählerwert (auch 3725 kWh) | Startwert / Baseline — noch kein Verbrauch; meter.is_baseline=true, delta_kwh leer |
| Ping mit 0, danach echter Stand | 0 ist Platzhalter, kein Startwert; der echte Stand wird Baseline (kein erfundener Tagesverbrauch) |
| Bis zur ersten Differenz | Portal/Sparvo „Tagesverbrauch heute“ = warte auf Zählerdaten (0 kWh intern) — der Zählerstand selbst zählt nicht |
| Ab dem zweiten Ping mit Anstieg | delta_kwh = Differenz zum letzten Stand; erst dann ein Wert > 0 in der Live-Leiste |
| Portal „Zähler zurücksetzen“ | Gespeicherter Stand wird gelöscht; nächster Ping ist wieder Startwert |
| Zählerstand sinkt (Zählerwechsel) | Neuer Startwert; meter.reset_suspected=true (kein negativer Verbrauch) |
Antwort
| Feld | Bedeutung |
|---|---|
telemetry_status | ok wenn gespeichert |
soc_pct | Gespeicherter Stand |
meter.import_kwh_total | Gespeicherter Zählerstand |
meter.observed_at | Zeitstempel der Speicherung |
meter.is_baseline | true beim Startwert (erster Ping / nach Reset) |
meter.delta_kwh | Verbrauch seit letztem Ping (fehlt beim Startwert) |
quota_class | telemetry bei Erfolg; access_denied bei Basic/anon not_available (nicht billable) |
Live-Leiste (Portal / Sparvo)
GET /plant-outlook/live-telem bzw. GET /api/live-telem liefern u. a.:
| Feld | Bedeutung |
|---|---|
day_import_kwh | Summe der Meter-Δ heute (intern 0, bis erste positive Δ) |
awaiting_first_delta | true bis zur ersten positiven Δ seit Baseline/Reset — UI zeigt dann warte auf Zählerdaten, nicht den Zählerstand |
awaiting_baseline | true, wenn noch kein Zählerstand gespeichert (wartet auf Ping nach Reset) |
meter_total_kwh | Letzter kumulativer Stand (auch während awaiting_first_delta) |
meter_since_date | Lokales ISO-Datum der aktuellen Baseline-Serie (YYYY-MM-DD); nach Portal-Reset Fallback cleared_at bis zum nächsten Ping — UI „Zählerstand seit …“ |
Voraussetzungen
- Community-Key (oder höher)
- Anlagenprofil im Portal (Standort)
Loxone / Miniserver
Laut Loxone-Doku ersetzt der Virtuelle Ausgang Befehl nur <v> / <v.1> / <v.2> / <v.3> / <v.t> — das ist der Wert am Input des Befehls, nicht <v.ViName>.
Empfohlen:
1. VO FetchPlantTelemetrySoc — Input = SOC, Body {"battery":{"soc_pct":<v.2>}} 2. VO FetchPlantTelemetryMeter — Input = Zähler, Body {"meter":{"import_kwh_total":<v.2>}} 3. VO FetchPlantTelemetryPvMeter — Input = PV-Ertrag, Body {"meter":{"pv_production_kwh_total":<v.2>}} (optional; kein Decide auf PV-Δ) 4. Optional VO FetchPlantGridChargeAllow — Input = Schalter 0/1, Body {"grid_charge_allowed":<v.0>} (nur bei Änderung senden) 5. Soc+Meter+PvMeter-Trigger von FetchPlantHours O4; Antwort nach /user/common/spotprice_telemetry.json 6. Header: X-API-Key + Content-Type: application/json
Die API akzeptiert Partial-POSTs (nur SOC, nur Import-Meter, nur PV-Meter, nur grid_charge_allowed, oder Kombinationen). Response sibling pv_meter + updated.pv_meter. Bei grid_charge_allowed-Update zusätzlich Hours-EMS-Echo: charge_now, prefix_hours_needed_today, prefix_energy_charge_kwh, hours_needed* (bei Aus = 0) — Server-Plan ist sofort genullt; lokale Extract-JSON folgt per Decide/Webhook. Import- und PV-Meter werden unabhängig ingestiert (Fehler in einem Sibling blockiert den anderen nicht). Optionaler PV-Ertragszähler verfeinert D0 in Hours Decide, Outlook/GET /v1/plant/pv-forecast / Loxone: abgeschlossene Stunden = Ist; laufende Stunde erst wenn Meter‑Δ > 0 kWh (sonst Prognose); Rest heute × Scale 0,5…1,5 gegen Kalendertag-Prognose. Chart: Grün = PV (alle Anlagen); mit Meter Softgrün = Prognose. pv_kind=meter_blend für alle Keys, sobald Chart‑Ist existiert (auch nur laufende Stunde). Forecast-Day-Cap (Ist schon > 1,2× Modelltag) skippt nur Scale — UI behält Blend. Kill HOURS_PV_METER_REFINE=0 → kein Scale; UI/GET malt Ist trotzdem (meter_blend + skipped); Decide-Horizont bleibt unskaliert bei Kill; kein Decide allein auf PV-Δ. FetchPlantHours v1.17 — O4 → Analogspeicher → VO <v.2>: Nur Telemetrie. Netzladung lesen: Extract O10 nach Decide — Loxone Hours.
Nächste Schritte
- Hours Demand
- Loxone Hours — Telemetry aus dem Miniserver
Community registrieren oder Code-Beispiele mit Ihrem persönlichen Key.