Datendownload Auflösung

Hallo,

Ich nutze die Volkszaehler Software auf einem Raspberry Pi und betreibe so meinen eigenen Stromzähler. Ich würde gerne die Daten der BEG/EEG in 15 Minuten Auflösung herunterladen, um sie im Volkszaehler neben meinen Verbrauchs- und Produktionsdaten grafisch darzustellen. Derzeit scheint das nur für Periode “Tag” möglich. “Monatlich” wäre aus meiner Sicht aber sinnvoll, um das rasch und mit geringem Aufwand erledigen zu können. Könnte man diese Änderung andenken?

Martin

1 „Gefällt mir“

Auch ich hätte Interesse, die Daten vor allem vollautomatisch herunterzuladen. Ich habe mir eine influxdb mit den Verbrauchs- und Einspeisungsdaten gebastelt, die ich derzeit händisch einmal im Monat mit den Monatsdaten aus der Energie Steiermark befülle.

Wäre natürlich super, wenn ich die gesammelten Daten mit Viertelstundenwerten inklusive der EEG und BEG Anteile herunterladen könnte. Wenn das händisch erfolgen muss, sollten zumindest monatliche Downloads möglich sein.

Am schönsten wäre es, wenn ich diesen Download automatisieren könnte. Dann könnte es durchaus auch auf Tagesbasis erfolgen.

Ein möglicher Weg wäre, dass in der Anzeige der Daten auch pro Zählpunkt ein Userkey und API-Key abfragbar ist, mit dem es möglich ist, automatisiert per Webservice die Werte eines Tages als csv oder von mir aus auch json oder xml Datei herunterzuladen. Dabei sollte ein Indikator mitkommen, ob schon eine 100%ige Verteilung erfolgt ist, falls wieder mal ein Netzbetreiber mit den Daten säumig ist. Ich stelle mir vor, dass nach einem Monat automatisiert der jeweilige Tag des Vormonats abgefragt wird, bei nicht 100%iger Abdeckung jeweils 1 Woche / Monat später nochmal, bis 100% für jeden Tag erreicht ist.

Dann könnten diese Daten automatisiert in die influxdb eingespeichert werden, sodass alle beliebigen Auswertungen mit Grafana möglich sind. Dabei denke ich an Kostenauswertungen oder z. B. Statistiken zur Verteilung von Prozentwerten, zu welcher Tageszeit die prozentmässig höchste Abnahme durch EEG und BEG gegeben ist, um planmäßig die Entladung des Speichers zu steuern.

Ihr habt ja die genauen Werte und ein Webservice zm Download sollte nicht zu schwer zu programmieren sein. Und mit Userkey, Apikey und Zählpunktnummer sollte auch eine Abfrage hinreichend securitymässig abgesichert sein, sodass Fremdzugriff ausgeschlossen ist. Zur Erhöhung der Sicherheit könnte auch z.B. der Userkey über einen anderen Weg mitgeteilt werden, sodass nicht alle Keys durch Hacken des Zugangs zur Datenanzeige erfahrbar sind.

3 „Gefällt mir“

Genau solche Anfragen mag ich. :slight_smile:
Wir haben inzwischen unsere Timescale Umstellung (SQLite –> PostgreSQL –> Timescale) abgeschlossen und jetzt sind solche Anfragen leichter zu behandeln.

Mal schauen, wann @berhir sich dafür etwas Zeit nehmen kann.

2 „Gefällt mir“

Eine API über die Mitglieder ihre Daten einfach abfragen können ist definitiv etwas das wir anbieten wollen. Aus Zeitgründen wird es aber noch ein bisschen dauern.

So wie ich das lese, haben wir hier einige Mitglieder mit guten technischen Verständnis. Ihr könnt also auch einfach unsere bestehende API verwenden, in dem ihr das Auth Cookie aus dem Browser nehmt. Die Daten werden vermutlich nicht so einfach zu verstehen sein, aber indem man vergleicht was im Mitgliederportal angezeigt wird, sollte es möglich sein. Damit sollten sich alle genannten Anforderungen umsetzen lassen.

Bis es eine sauber dokumentierte API gibt, wird es wie gesagt noch etwas dauern.

6 „Gefällt mir“

Hallo, Danke für den Hinweis mit dem Cookie. Das hat sehr gut funktioniert. Falls jemand interessiert ist, hier die wichtigsten Schritte:

  • Im Browser (bei mir: Firefox) F12 drücken und das Portal aufrufen.
  • Unter Netzwerkanalyse sieht man unter “Datei” die GET Aufrufe, für die jeweiligen Abfragen. Interessant sind die Key=Value Paare.
  • Unter XHR/Kopfzeilen findet man den Eintrag “Cookie: ”, er beginnt mit “portal.jwtToken=…”
  • Mit diesem Wissen kann man nun Abfragen zB mit curl senden. Beispiel:
  • Der Output im JSON Format lässt sich wunderbar verarbeiten.

Vielen Dank

11 „Gefällt mir“

F12 funktioniert auch im EDGE :grin:
Ich binde das ganze gerade in HomeAssistant ein - wird ein nettes experimentelles Dashboard werden :upside_down_face:
@berhir Danke für den Tipp!

1 „Gefällt mir“


Und schaut im ersten Entwurf so aus - aber Achtung - nicht bereinigt um fehlende Abrechnungen o.ä.
Im nächsten Schritt werde ich das bereinigen und liebevoll einer KI zur Prognose der Abdeckung des Eigenverbrauches und Abnahme der Produktion übergeben.
Ist wirklich nett :grin: :upside_down_face:

7 „Gefällt mir“

Das sieht ja cool aus :slight_smile:
Das schreit ja fast nach einem HomeAssistant Addon :wink:

4 „Gefällt mir“

Danke für die Erklärung für den Download. Das funktioniert prächtig und lässt sich im Homeassistant via restful integration auch gut automatisieren. Wenn ihr auf der homepage noch irgendwo einen Platz finden könnt und den Downloadlink und das Cookie zum kopieren unterbringen könnt, dann müsste man auch nicht den Trick mit der Browser-Netzwerkanalyse veranstalten, um zum halboffiziellen api zu kommen. Man kann die heruntergeladenen json Daten gut einspeichern.

Einfacher wäre es, wenn die csv-Downloadfunktion auch über einen https Get aufrufbar wäre. Das löst ihr aber so viel ich sehe über javascript Funktionen auf der homepage, womit ich es nicht automatisieren kann. Aber ich müsste sowieso zum Einspeichern in die Statistik Datenbank den csv File umschreiben für die import statistics integration. Da ist es einfacher, gleich mit den json-Daten die nötigen csv-files selbst zu bauen.

Ich bin gerade dabei, mir dafür eine Automation zu bauen. Der Download funktioniert schon.

Was mir noch nicht ganz klar ist, ist wo welche Daten stehen. Es wäre schön, wenn ihr irgendwo eine Erklärung zu den einzelnen Werten verfügbar macht.

Es sind fast zu viele json Daten. Ich habe zwar Vermutungen, was wo steht, aber wenn es eine Aufstellung gäbe, welches json-Feld den Werten im csv entspricht, wäre mir schon geholfen. Ich nehme an es sind die xxxxComplete-Werte. Weiters nehme ich an, die Werte sind erst endgültig, wenn die 6 xxxxFaulty-Werte alle false sind.

Wäre schön, falls ihr dann ein offizielles api baut, wenn es möglichst ähnlich aufgebaut ist.

Ich hab das für meine Graphen wie folgt realisiert. Die offizielle API dauert ja anscheinend noch eine Weile…
XXXXX muss ersetzt werden :wink:
Und die jeweiligen Teile in die entsprechende YAML

Configuration.yaml

---------------------------------------------------------

:electric_plug: EG Austria REST Sensor

---------------------------------------------------------

rest:

  • resource: !secret eg_austria_energy_url
    method: GET
    headers:
    Cookie: !secret eg_austria_cookie
    scan_interval: 3600
    sensor:
    • name: „eg_austria_raw“
      unique_id: eg_austria_raw
      value_template: „{{ value_json.totalConsumption | float(0) }}“
      unit_of_measurement: „kWh“
      json_attributes:
      • totalConsumption
      • totalConsumptionFromCommunity
      • totalGeneration
      • totalGenerationToCommunity
      • totalEarnings
      • totalSpendings
      • totalConsumptionEnergyMix
      • consumptionDataPoints
      • generationDataPoints

---------------------------------------------------------

Secrets.yaml
eg_austria_cookie: „portal.jwtToken=XXXXX“
eg_austria_energy_url: „https://portal.eg-austria.at/api/v1/portal/member/XXXXX/energy-data?period=Year&aggregation=Month&startDate=2025-01-01&ecIds=CC100087&ecIds=RC103548&mpIds=421&mpIds=422“

---------------------------------------------------------

Dashboard

views:

  • title: EG Austria
    path: eg-austria
    icon: mdi:solar-power
    cards:
    • type: custom:apexcharts-card
      header:
      show: true
      title: EG Austria – Monatsverbrauch 2025
      show_states: false
      graph_span: 365d
      span:
      start: year
      apex_config:
      dataLabels:
      enabled: true
      all_series_config:
      show:
      legend_value: false
      series:
      • entity: sensor.eg_austria_raw
        name: Gesamtverbrauch
        type: column
        unit: kWh
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = (p.consumptionComplete ?? p.consumption);
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });
      • entity: sensor.eg_austria_raw
        name: Verbrauch aus Community
        type: column
        unit: kWh
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = p.consumptionFromCommunity;
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });
    • type: custom:apexcharts-card
      header:
      show: true
      title: EG Austria – Monatliche Kosten 2025
      show_states: false
      graph_span: 365d
      span:
      start: year
      apex_config:
      dataLabels:
      enabled: true
      all_series_config:
      show:
      legend_value: false
      series:
      • entity: sensor.eg_austria_raw
        name: Kosten (spendings)
        type: column
        unit: €
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = (p.spendingsComplete ?? p.spendings);
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });
    • type: custom:apexcharts-card
      header:
      show: true
      title: EG Austria – Energie-Mix Community 2025
      show_states: false
      graph_span: 365d
      span:
      start: year
      apex_config:
      yaxis:
      max: 100
      min: 0
      all_series_config:
      show:
      legend_value: false
      series:
      • entity: sensor.eg_austria_raw
        name: Sonne
        type: line
        unit: ‚%‘
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal && p.energyMix)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = p.energyMix.sun;
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });
      • entity: sensor.eg_austria_raw
        name: Wind
        type: line
        unit: ‚%‘
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal && p.energyMix)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = p.energyMix.wind;
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });
      • entity: sensor.eg_austria_raw
        name: Wasser
        type: line
        unit: ‚%‘
        data_generator: |
        let points = entity.attributes.consumptionDataPoints || ;
        points = points
        .filter(p => p.dateTimeFromLocal && p.energyMix)
        .sort((a, b) => new Date(a.dateTimeFromLocal) - new Date(b.dateTimeFromLocal));
        return points.map(p => {
        const x = p.dateTimeFromLocal;
        const val = p.energyMix.water;
        const y = (val === undefined || val === null) ? null : val;
        return [x, y];
        });

4 „Gefällt mir“

Ich denke in eine andere Richtung. Ich arbeite an einer Lösung in 2 Richtungen:

Ich möchte automatisch die Daten des Jahres im Stundenformat herunterladen und in 2 Formate umwandeln:

  1. In ein csv-Format für Excel Auswertungen und mit bestehenden Daten aus Vorjahren kombinieren.
  2. In ein anderes csv-Format umwandeln, das ich mit der Import statistics integration direkt in die ( stündlichen ) Langzeitstatistiken des Homeassistant importieren kann, um auch im HA Jahresstatistiken ziehen zu können.

Wenn ich fertig bin, werde ich auch hier den Code einstellen.

2 „Gefällt mir“

Derzeit hätte ich 3 Wünsche an das API-Christkind, auch wenn es doch wieder einige Zeit hin ist:

  • Cookie renewal, wie es z.B. bei den APIs einiger Fahrzeughersteller notwendig ist: derzeit muss man alle heiligen Zeiten das Cookie aus der Netzwerkanalyse klauben. Lästig, aber unhübsch. Vermutlich in Kombination mit Passwort-Login sinnvoll.
  • Größeres Zeitfenster beim Viertelstundendownload: derzeit loope ich über die letzten x-Tage. In ein Limit bin ich noch nicht gelaufen, aber man will ja nett zum Server sein :slight_smile:
  • API-Punkt mit den Tagen die noch nicht komplett vorhanden sind als Liste - dann würde man sich das loopen über die letzten x-Tage sparen und könnte nur regelmäßigen diese exakten Tage fetchen.

Ansonsten komme ich ganz gut zurecht mit der API - auch ohne schöne Doku. Es gab mal ein Wiki in dem solche Sachen zusammengetragen wurden, existiert das noch?

2 „Gefällt mir“

very cool - hast du da Grafana im Einsatz?
Schaut wirklich gut aus, und deine Wünsche Teile ich :upside_down_face: hab die gleichen :grin:

Ja, bei mir geht das json den Weg über telegraf in eine influxdb worauf Grafana zugreift.

Crontab erzeugt einmal am Tag das json:

#!/bin/ksh

file=/tmp/egaustria_day_curl.json
echo "" > $file

start="2025-06-01"
end="2025-06-10"

start_sec=$(date -j -f "%Y-%m-%d" "$start" +%s)
end_sec=$(date -j -f "%Y-%m-%d" "$end" +%s)

while [[ $start_sec -le $end_sec ]]; do
  current=$(date -j -r "$start_sec" +"%Y-%m-%d")

  curl -fsS "https://portal.eg-austria.at/api/v1/portal/member/[Mitgliedsnummer]/energy-data?period=Day&aggregation=FifteenMinutes&startDate=$current&ecIds=[CCID]&ecIds=[RCID]&mpIds=[MPID]&mpIds=[MPID]" \
  -H 'Cookie: portal.jwtToken=[Token]' \
  >> $file

  start_sec=$(( start_sec + 86400 ))
done

Vorsicht, das ganze Jahr an Viertelstundendaten hat 40 bis 50 MB. Mehr als einmal am Tag würde ich das wohl nicht abholen (wäre wohl auch sinnlos). Oder gäbe es einen besseren Weg? Wie gesagt, in ein Limit was die Anzahl der Aufrufe betrifft, bin ich noch nicht gelaufen. Vielleicht ist meine Vorsicht aber auch unbegründet. :slight_smile:

1 „Gefällt mir“

Ist an dem api etwas geändert worden ?

Seit kurzem funktionieren meine Download calls nicht mehr. Ich bekomme RC=401 Unauthorized.

Ich habe im Firefox das (geänderte) cookie portal.jwtToken rausgesucht, aber das half nichts.

Die API funktioniert hier unverändert.

Zumindest nicht absichtlich.

Wir hatten aber einige Momente, wo es Verbindungsprobleme gab und da könntest du so einen Zeitpunkt erwischt haben.

Funktioniert es jetzt wieder?

Tut mir leid, da habe ich euch zu Unrecht verdächtigt. Mittlerweile habe ich den Grund herausgefunden. Offenbar trat da im Jänner ein Fehler in der Implementierung der restful integration von homeassistant auf. Als ich mit curl den fehler nachstellte und es mit denselben parametern funktionierte bin ich dahintergekommen. Ich habe die download automatisierung auf curl umgestellt und es flutscht wieder. Mein issue ist noch offen, also gibt es für den download mit restful derzeit noch keine Lösung.

1 „Gefällt mir“