EOS API - Load Prediction API nicht abwärtskompatibel?

Nachdem ich zwei Kapitel des geplanten Tutorials inklusive Screenshots fertiggestellt hatte, habe ich festgestellt, dass der bisher verwendete Endpunkt /gesamtlast_simple, auf dem das zweite Kapitel aufgesetzt hat, als "Deprecated" markiert ist. Nun gut, dann ändere ich das mal eben, ... dachte ich.

Leider scheint sich aber das Verhalten ebenfalls geändert zu haben und passt jetzt nicht mehr so einfach zum /optimize Endpunkt. Der Endpunkt /gesamtlast_simple lieferte für einen Jahresverbrauch in Wh für den Zeitraum "0:00 Uhr heute" bis "23:00 Uhr morgen" 48 Werte als Array, was ganz praktisch war, da der /optimize Endpunkt genau dieses im Knoten gesamtlast erwartet hatte.

Der neue Endpunkt liefert nun auch 48 Werte in Form eines Arrays, allerdings ab dem Zeitpunkt des Aufrufs und setzt eine Konfiguration in Form von kWh voraus. Möchte man das alte Verhalten nachbilden, muss man nun zunächst einen String im Format DateTime für den Startzeitpunkt "0:00 Uhr heute" und einen String im Format DateTime für den Endzeitpunkt "23:00 Uhr morgen" erzeugen und diese dann an /v1/prediction/list?key=load_mean übergeben, was das Ganze (zumindest in Node-RED) ein Stück aufwändiger macht. Lässt man den Endzeitpunkt weg, bekommt man sogar 48+x Werte, wobei x die Anzahl der Stunden des heutigen Tages bei Aufruf des Endpunktes ist, dessen Zweck zumindest ich irgendwie noch nicht einordnen kann, wenn doch die prediction_hours standardmäßig auf 48 Stunden stehen.

Dazu meine Fragen:

  • Stimmt meine Vermutung, dass das auch für die anderen Prognosen gilt?
  • Bevor ich das jetzt versuche umzusetzen: ist geplant, auch die Logik des /optimize Endpunkts anzupassen oder kann man sich in nächster Zeit auf die derzeitige Logik verlassen?

Und gerade fällt mir noch ein weiterer Punkt auf: in der Konfiguration kann man die Optimierung in einem definierten Intervall laufen lassen (ems_interval). Wohin (data_folder_path/data_output_subpath?) und mit welchem Namen (?) und in welchem Format (JSON?) wird das Optimierungsergebnis geschrieben?

Ganz generell zum Entwicklungsvorgehen:

  • Die "/v1"-Schnittstelle ist gerade in der Entwicklung
  • Die Schnittstellen ohne v1 (z.B. /optimize) sind eingefroren und sollen auf absehbare Zeit auch weiter so wie jetzt funktionieren. "Deprecated" steht da, weil keine Weiterentwicklung mehr erfolgen wird. Wir versuchen die Schnittstelle stabil zu halten, weil Andreas und Jörg nur diese Schnittstelle nutzen und sie auch in den Videos beschreiben.

Bei der "/v1"-Schnittstelle ist der Default-Startzeitpunkt der Abfrage (start datetime) das aktuelle Datum und die aktuelle Uhrzeit, evtl. gerundet auf das gewünschte Datenintervall (default eine Stunde). Falls der Endezeitpunkt nicht definiert ist, werden soviele Werte wie gerade vorhanden sind geliefert. Ansonsten kann man Start, Ende, Interval bei der Abfrage definieren.

Das aktuelle EOS im main branch kann bereits zyklisch einen "energy management run" ausführen. Der beinhaltet aber momentan nur das Update der Vorhersagen. Eine Optimierung wird nicht gestartet. Sieht man so auch im logging. Die Weiterentwicklung im PR#595 startet auch die Optimierung. Das Ergebnis der Optimierung kann dann mit den neuen Endpunkten zum Energiemanagement "/v1/energy-management/xxx" abgefragt werden. Es ist geplant sowohl das bestehende Format (wie bei "/optimize") als auch ein neues kommandoorientiertes Format ala. Datum+Uhrzeit+Kommando (z.B. Stelle Batterie auf Laden) zur Verfügung zu stellen.

Die automatische Optimierung erfordert, dass Alles was bis jetzt im Aufruf an "/optimize" übergeben wurde, durch die Konfiguration, Messwerte und Vorhersagen definiert ist. Es sind also Änderungen hier zu erwarten. Im PR#596 hat sich die Konfiguration weiterentwickelt und es gibt eine Vorhersage für fixe Einspeisetarife und eine Möglichkeit dynamische Einspeisetarife zu importieren. Die Messwertschnittstelle ist zu unflexible für das Ziel der automatischen Optimierung. Hier wird es im PR#596 noch Änderungen geben.

Danke Dir für die zeitnahe Erläuterung :+1:. Das Entwicklungsvorgehen weicht etwas von dem ab, wie ich es normalerweise kenne, erklärt dann aber einige aktuelle Gegebenheiten.

Das hatte ich auch im letzten Video von Jörg gehört und bei ihm nachgefragt, wie er mit der neuen API umgeht, aber leider bisher keine Antwort erhalten. Wenn die Beiden aber auch aktuell weiteren Content darauf aufbauen, entwickle ich das Tutorial ebenfalls auf dieser Basis und mache wie ursprünglich geplant weiter und ich erstelle später eine neue Version für die /v1-API, wenn sie reifer ist.

Ich hätte wie gesagt erwartet, dass die Anzahl der gelieferten Werte der Konfiguration von prediction_hours entspricht, zumindest im Maximum. Und es würde der Abwärtskompatibilität sehr zuträglich sein.

Damit ist dann wahrscheinlich der Hinweis "crippled version" im Log-Eintrag gemeint.

Top! Auf das kommandoorientierte Format bin ich sehr gespannt. Das wäre eine echte Hilfe, da die aktuelle Struktur unübersichtlich und schwer zu interpretieren ist (hatte ich glaube ich mal kommentiert und Vorschläge gemacht).

Je nach Entwicklung des Themas Netzentgelte wäre der dynamische Einspeisetarif natürlich interessant.

Es gab auch mal die Frage, ob ihr EOS auch an die neuen Strompreisintervalle von 15 Minuten anpasst, die ja nun kurzfristig verschoben wurden, aber zum 30.09. kommen werden. Macht ihr da was im Zuge der aktuellen Weiterentwicklung? Sonst würde EOS ab dem 01.10. nur noch suboptimale Ergebnisse liefern, wenn sich die Preise innerhalb der Stunde stärker ändern.

Um nicht mit der alten API anzufangen, versuche ich alles direkt mit der "/v1"- Schnittstelle hinzubekommen. Vorhersage für PV und Last funktioniert bereits:


Die Visualisierung habe ich der von Andreas nachempfunden.
Ich versuche nun erstmal meine Gesamtlast an EOS zu schicken. Ich schaffe es mit "/v1/measurement/value". Das könnte ich jetzt jede Stunde damit machen. Allerdings würde ich gerne initial auch "/v1/measurement/series" umzusetzen. Dort bekomme ich aber immer nur diese Response zurück:

{"detail":[{"type":"dict_type","loc":["body","data"],"msg":"Input should be a valid dictionary","input":[{"2025-06-30T11:00:00.000Z":0.22923004435545638},{"2025-06-30T12:00:00.000Z":0.22263251851098326},{"2025-06-30T13:00:00.000Z":0.7105537630404732},{"2025-06-30T14:00:00.000Z":0.31464015688866886},{"2025-06-30T15:00:00.000Z":0.9211528459258483},{"2025-06-30T16:00:00.000Z":0.7371729101101492},{"2025-06-30T17:00:00.000Z":0.5563316453525745},{"2025-06-30T18:00:00.000Z":0.8831583473576771},{"2025-06-30T19:00:00.000Z":0.28874935855369444},{"2025-06-30T20:00:00.000Z":0.920408734269035},{"2025-06-30T21:00:00.000Z":0.45607398712033137},{"2025-06-30T22:00:00.000Z":0.9531127836620423},{"2025-06-30T23:00:00.000Z":0.43497786792241466},{"2025-07-01T00:00:00.000Z":1.0084492221583994},{"2025-07-01T01:00:00.000Z":0.35820305297706584},{"2025-07-01T02:00:00.000Z":1.048997327158046},{"2025-07-01T03:00:00.000Z":0.33117202582768435},{"2025-07-01T04:00:00.000Z":0.4909131949417855},{"2025-07-01T05:00:00.000Z":0.9422623121171221},{"2025-07-01T06:00:00.000Z":0.2078493731640671},{"2025-07-01T07:00:00.000Z":3.2012213942574776},{"2025-07-01T08:00:00.000Z":3.578948786928323},{"2025-07-01T09:00:00.000Z":0.20714321959541132},{"2025-07-01T10:00:00.000Z":0.8815434426103823},{"2025-07-01T11:00:00.000Z":0.5862791314197018},{"2025-07-01T12:00:00.000Z":0.22409825742870465},{"2025-07-01T13:00:00.000Z":1.0514264120286254},{"2025-07-01T14:00:00.000Z":0.2193308132972212},{"2025-07-01T15:00:00.000Z":1.288625536814548},{"2025-07-01T16:00:00.000Z":0.31860678599425074},{"2025-07-01T17:00:00.000Z":0.8676894149569605},{"2025-07-01T18:00:00.000Z":0.6252600770780843},{"2025-07-01T19:00:00.000Z":0.576780528354476},{"2025-07-01T20:00:00.000Z":0.527941639078122},{"2025-07-01T21:00:00.000Z":0.6021899732978205},{"2025-07-01T22:00:00.000Z":0.7296302008239117},{"2025-07-01T23:00:00.000Z":0.6522656096091863},{"2025-07-02T00:00:00.000Z":0.7122819111692746},{"2025-07-02T01:00:00.000Z":0.6665203305546707},{"2025-07-02T02:00:00.000Z":0.7173795494471329},{"2025-07-02T03:00:00.000Z":0.7721261307513063},{"2025-07-02T04:00:00.000Z":0.6203734378731129},{"2025-07-02T05:00:00.000Z":0.6537588719589729},{"2025-07-02T06:00:00.000Z":0.1718075222009054},{"2025-07-02T07:00:00.000Z":0.1688346457665876},{"2025-07-02T08:00:00.000Z":0.2043442441964248},{"2025-07-02T09:00:00.000Z":0.9538867422402679},{"2025-07-02T10:00:00.000Z":1.9326427220526958}]}]}

Input soll ein dictionary sein. Mir erschließt sich aber aus der Dokumentation nicht, wie das dictionary aussehen muss. Ich schicke dort aktuell ein Array, weil ich das measurement schon als URL parameter angegeben habe:

http://192.168.0.112:8503/v1/measurement/series?key=load0_mr

Wie muss ich den Request anpassen?

Du solltest etwas wie hier verwenden:

curl -X 'PUT' \
  'http://127.0.0.1:8503/v1/measurement/series?key=load0_mr' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "data": {
     "2024-01-01T00:00:00+01:00": 1,
     "2024-01-02T00:00:00+01:00": 2,
     "2024-01-03T00:00:00+01:00": 3
  },
  "dtype": "float64",
  "tz": "Europe/Berlin"
}'

Einfacher, wenn man keine Pandas Serie verwenden muss/ will ist vielleicht:

curl -X 'PUT' \
  'http://127.0.0.1:8503/v1/measurement/data' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "start_datetime": "2024-01-01T00:00:00+01:00",
    "interval": "1 hour",
    "load0_mr": [1, 2, 3]
}'

Warum schluckt der EOS denn keine ISO 8601 Datum strings? Ich muss jetzt immer diesen Tanz in JSONata machen:

$fromMillis($toMillis($date.toISOString()), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01][Z]')

Also wäre nett, wenn EOS auch ISO 8601 date strings verdauen könnte. Aber es funktioniert zumindest erstmal.

"2024-01-01T00:00:00+01:00" ist ISO 8601. Sieht eher so aus als würdest du ursprünglich mit Unix epoch arbeiten. Falls das nicht funktioniert einfach ein Issue im GitHub repo aufmachen, oder noch besser einen pull request liefern.

Es war wohl schon zu spät gestern Abend. EOS schluckt einwandfrei "2025-07-01T07:00:00.000Z". Ich entschuldige mich vielmals!
Kaum macht man es richtig, schon geht es. Vielen Dank für den Support!

Neues Problem: Welche Einheit verwenden "/v1/prediction" und "/v1/measurement" bzw. welche sollen sie verwenden?
Wenn ich prediction API lese, steht dort "W" und wenn ich "/v1/prediction/series?key=load_mean_adjusted" lese, kommen dort Wh heraus.
Wenn ich measurement API lese, steht dort "kWh". Habe dort kWh hineingeschrieben, dann kommt aus "load_mean_adjusted" auf einmal auch kWh heraus.
Einen Bug dazu finde ich bisher nirgends.

Guter Punkt, hier gehen die Wünsche momentan auseinander. Andreas hätte gerne intern alle Energieangaben in Wh (pure SI-Einheiten). User sind wahrscheinlich mehr an kWh gewöhnt. Der Kompromiss ist, dass in der Konfiguration und bei der Messwerteeingabe kWh verwendet werden und dann eine "Umrechnung" erfolgt. Da kann es aber momentan noch "historische" Abweichungen geben. Die Einheiten sind die in der jeweiligen Dokumentation gelisteten.

Das konkrete Problem ist bei mir im Moment jedoch, dass die "/v1/prediction" API mit Key "load_mean_adjusted" nach einem Neustart Wh liefert und sobald ich einmal "/v1/measurement" mit kWh beschrieben habe, liefern "load_mean_adjusted" auch kWh und nicht mehr Wh.
Was wäre hier der konkrete Lösungsvorschlag? Erst das "measurement" beschreiben, damit dann aus der prediction load_mean_adjusted auch kWh heraus kommt?

Vielen Dank für die super Arbeit an EOS!!!

Ich hätte eine Frage zur Verwendung der v1-Schnittstelle. Ich würde gern die Vorhersage der Gesamtlast mit eigenen Werten realisieren.

So wie ich es verstanden habe kann ich meine historischen Daten per measurement übergeben und dann die Vorhersage als load_mean_adjust zurück bekommen.

Aber leider erwartet measurement Zählerwerte, also summierte Leistungen pro Stunde. Für einen Zählerstand ist das auch super, aber ich habe meinen Verbrauch nur als Leistung in W.

Gibt es hierzu auch einen Endpunkt oder eine Einstellung, bei der ich die historische Leistungen in W übergeben kann und EOS sie intern vorhält?

Ich stelle mir das so vor, dass ich alle 5min den aktuellen Verbrauch an EOS sende und daraus sich dann die Prognose berechnet.

Liebe Grüße

Das ist viel zu ungenau, wenn Du alle 5min die aktuelle Leistung als Grundlage für die Berechnung der Energie nimmst. Mathematisch ist die Energie das Integral der Leistung über die Zeit. Bildlich gesprochen ist es die Fläche unter der Kurve der Leistung.

Angenommen, Du hast eine getaktete Last, die 4min50s 10kW zieht, dann ist sie für 10s aus. Du nimmst alle 5min die aktuelle Leistung innerhalb der 10s. Damit wirst Du immer die hohe Last in der aktuellen Leistung verpassen, Deine Messung ist also vollkommen ungenau und die Prognose wird genauso fehlerbehaftet.

Und ja, es gibt solche Lasten. Das sind Mikrowellen, Kochplatten, Induktionsplatten usw. usf., die genauso arbeiten. Diese Lasten wirst Du alle nicht erfassen.

Meine Lösung dazu ist, ich packe meine aktuelle Leistungsmessung in der Frequenz in der sie per MQTT aus einem Victron Energie VenusOS kommt, in eine InfluxDB. Dann berechne ich per Abfrage das Integral dieser Leistung stundenweise:

SELECT integral("value")/3600/1000 FROM (SELECT value FROM "system/Ac/Consumption/{{payload}}/Power" WHERE time >= '{{rangeStart}}' AND time < '{{rangeEnd}}') GROUP BY time(1h) tz('Europe/Berlin')

wobei payload durch L1 bis L3 und rangeStart durch die volle letzte Stunde minus 48 Stunden und rangeEnd durch die letzte volle Stunde zu ersetzen sind. Da ich durch 3600s und 1000 teile wird aus Wattsekunden (Ws) Kilowattstunden (kWh).

@b0661 Nochmal meine Frage: Du erwähntest, dass Andreas gerne SI-Einheiten verwenden würde. Also die SI-Einheit für eine Energie ist 1 Joule oder 1 Ws, nicht 1 Wh, wie teilweise in EOS noch zu finden ist. Ferner habe ich den Fehler beschrieben, dass load_mean_adjusted nach Neustart Wh liefert und nach Befüllen von measurements mit kWh liefert es auf einmal kWh. Welche Einheit soll es bitte sein? 100Wh sind leider etwas völlig anderes als 100kWh.

Hallo kleini,

vielen Dank für deinen Hinweis.

Natürlich erhöht sich die Genauigkeit, wenn man sekündliche Werte über eine Stunde aufsummiert und dann für die Prognose verwendet.

In Home Assistant lässt sich ganz einfach ein gleitender Mittelwert über z. B. 5 Minuten berechnen. Damit werden die sekündlichen Messwerte der Solaranlage geglättet, wodurch kurzfristige Schwankungen automatisch berücksichtigt werden. In meinem Test lag die Abweichung gegenüber deiner Methode bei weniger als 3 %. Gleichzeitig spart man damit erheblich Speicherplatz, da keine hochfrequenten Rohdaten gespeichert werden müssen – und der Einsatz spezieller Datenbanken wie InfluxDB wird überflüssig.

Zu deiner Frage:
Ich liefere die Daten in Wh zu measurements und hatte bisher noch keine Probleme.

Grüße