Das Titelbild

Tesla Powerwall 2 API

Kategoriebild: Technik

Die Tesla Powerwall 2 besitzt eine praktische API, um aktuelle Werte auszulesen.

Die API der Tesla Powerwall 2

Auch wenn der technische Support hier leider wenig Auskunft gibt bzw. geben kann (oder geben darf?), die Tesla Powerwall 2 hat eine eingebaute API, aus der man auch ohne Anmeldung die wichtigsten Daten abrufen kann.

Einfache Daten zum aktuellen Zustand

Die folgenden URLs sind mir bisher bekannt, um Informationen abzurufen:

https://<IP-Adresse>/api/meters/aggregates
Die Informationen, welche Spannung anliegen und welche Ströme fließen, u.a.
https://<IP-Adresse>/api/system_status/grid_status
Anschluss zum Stromnetz
https://<IP-Adresse>/api/sitemaster
Da bin ich noch etwas unsicher
https://<IP-Adresse>/api/system_status/soe
Ladestand der Batterie

Als IP-Adresse muss natürlich die IP-Adresse des Gateways im lokalen LAN verwendet werden. Die eigentlich interessanten Daten stehen dabei in in den aggregates. Den Inhalt kann man sich z.B. mit curl (Achtung: den Schalter -k nicht vergessen, sonst gibt es Probleme mit dem ungültigen SSL-Zertifikat) anzeigen lassen; bei mir hat das Gateway die IP 192.168.0.100 bekommen, also sehen bei mir Aufruf und Code wie folgt aus:

curl -ks https://192.168.0.100/api/meters/aggregates |jq -CS
{
  "battery": {
    "energy_exported": 160460,
    "energy_imported": 187300,
    "frequency": 50.016999999999996,
    "i_a_current": 0,
    "i_b_current": 0,
    "i_c_current": 0,
    "instant_apparent_power": 630.3173803727769,
    "instant_average_voltage": 229.60000000000002,
    "instant_power": -630,
    "instant_reactive_power": -20,
    "instant_total_current": 13.200000000000001,
    "last_communication_time": "2020-10-24T13:23:54.390379678+02:00",
    "timeout": 1500000000
  },
  "load": {
    "energy_exported": 0,
    "energy_imported": 269405,
    "frequency": 0,
    "i_a_current": 0,
    "i_b_current": 0,
    "i_c_current": 0,
    "instant_apparent_power": 660.4578904063453,
    "instant_average_voltage": 401.36236013524405,
    "instant_power": 593.75,
    "instant_reactive_power": -289.25,
    "instant_total_current": 1.4793365272217567,
    "last_communication_time": "2020-10-24T13:23:54.390191188+02:00",
    "timeout": 1500000000
  },
  "site": {
    "energy_exported": 189607,
    "energy_imported": 60006,
    "frequency": 0,
    "i_a_current": 0,
    "i_b_current": 0,
    "i_c_current": 0,
    "instant_apparent_power": 243.00823031329617,
    "instant_average_voltage": 401.36236013524405,
    "instant_power": 2,
    "instant_reactive_power": -243,
    "instant_total_current": 7.420000000000001,
    "last_communication_time": "2020-10-24T13:23:54.390672663+02:00",
    "timeout": 1500000000
  },
  "solar": {
    "energy_exported": 428674,
    "energy_imported": 2828,
    "frequency": 0,
    "i_a_current": 0,
    "i_b_current": 0,
    "i_c_current": 0,
    "instant_apparent_power": 1214.6587998281657,
    "instant_average_voltage": 401.36813363793595,
    "instant_power": 1214,
    "instant_reactive_power": -40,
    "instant_total_current": 5.306,
    "last_communication_time": "2020-10-24T13:23:54.390191188+02:00",
    "timeout": 1500000000
  }
}

Die anderen URLs funktionieren analog, liefern allerdings deutlich weniger Daten. Der Eintrag battery steht für den Tesla-Speicher, der Eintrag load steht für den Hausverbrauch, der Eintrag site steht für das Stromnetz und der Eintrag solar steht für die Phovoltaik-Anlage. Interessant sind hier insbesondere die jeweiligen Einträge instant_power, die die jeweilige momentane Leisung in Watt angibt. Hierbei ist auch das Vorzeichen zu beachten: Bei load und solar sollte die instant_power immer positiv sein, sonst stimmt etwas nicht; bei battery und site gibt ein positives Vorzeichen an, dass der Speicher entlädt bzw. Strom aus dem Strom aus dem Stromnetz bezogen wird; analog bedeutet ein negatives Vorzeichen, dass der Speicher geladen wird bzw. Strom ins Stromnetz eingespeist wird.

Da curl auch in PHP verfügbar ist, können diese Daten also auch auf einer (lokalen) PHP-Webseite ausgelesen und entsprechend dargestellt werden. Somit können – ein kleines bisschen technisches Verständnis vorausgesetzt – auch individuelle Dashboards gebaut werden und man ist nicht abhängig von der Tesla-App.

Darüber hinaus lassen sich (offensichtlich) auch weitere Daten aus der API auslesen, wie z.B. die akuellen Spannungen; die ca. 400 Volt beziehen sich dabei natürlich auf den dreiphasigen Strom (230 * √3). Hier ließe sich also theoretisch auch ein Spannungsabfall im öffentlichen Stromnetz o.ä. ablesen.

Die weiteren Werte werde ich weiterhin beobachten, um diese genauer zuzuordnen; wer bereits genauere Informationen hat, darf mir gerne eine E-Mail schreiben. instant_total_current ist beispielsweise wahrscheinlich die Stromstärke.

Die History-Chart

Wer die Tesla-App benutzt hat, kennt ja die Tageschart. Ich wüsste schon gerne, ob man die entsprechenden Daten auch direkt aus dem Gateway bekommt; anscheinend bekommt man diese allerdings nur aus dem Internet von Tesla. Meine Vermutung: das Gateway hat nicht genug Speicher, sodass die Daten auf einen Tesla-Server übertragen werden, von wo sie die App dann wiederum abruft. An die Daten kommt man via cUrl mit dem etwas längeren Aufruf (aus Sicherheitsgründen anonymisiert):

curl --http2 -X GET -s -H "Host:owner-api.teslamotors.com" -H "content-type:application/json; charset=utf-8" -H "x-txid:{TXID}" -H "user-agent:Mozilla/5.0 (Linux; Android 8.1.0; Moto G (5) Build/OPP28.85-19-4-2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/86.0.4240.110 Mobile Safari/537.36" -H "x-tesla-user-agent:TeslaApp/3.10.8-421/adff2e065/android/8.1.0" -H "authorization:Bearer qts-{BEARER}" -H "accept-encoding:gzip" "https://owner-api.teslamotors.com/api/1/energy_sites/{ID}/calendar_history?kind=power&period=day&time_zone=Europe%2FBerlin&end_date={DATE}T11%3A59%3A59.999Z" |gzip -d |jq

Dabei sind die folgenden Variablen zu ersetzen:

{TXID}
Die TXID (s.u.)
{BEARER}
Bearer-Token (s.u.)
{ID}
Die Anlagen-ID als numerischer Wert (s.u.)
{DATE}
Das aktuelle Datum im Format YYYY-MM-DD

Außerdem können natürlich auch Useragent und Handymodell angepasst werden; da ich hier kein Sicherheitsrisiko sehe, habe ich meine Daten einfach drin gelassen. Das Datum anzupassen, dürfte wahrscheinlich kein Problem darstellen. Schwieriger ist es jedoch mit den ersten drei Werten. Diese konnte ich nur via Man-in-the-Middle-Attack aus der App abgreifen – bitte hier selbst einmal eine Suchmaschine der Wahl bemühen, wie man das entsprechend bewerkstelligt; ein Tipp: ein gerootetes Handy ist bei Android 8 nicht notwendig, auch wenn viele Apps etwas anderes behaupten.

Eine Kleinigkeit noch, die mir bei der Programmierung erst zufällig nach einiger Zeit aufgefallen ist: Liefert obiger Aufruf nur einen Wert in der Historie zurück, dann ist das einfach ein JSON-String im Klartext; erst ab zwei Werten ist das Ergebnis scheinbar gzip-komprimiert. Aktuell nutze ich dafür folgendes PHP-try-catch (nicht schön, aber es funktioniert):

$contents = getUrl($url, $cookie=null, $headers=$headers);
try {
  $valuestoday = json_decode(gzdecode($contents), TRUE)['response']['time_series'];
}
catch (Exception $e) {
  $valuestoday = json_decode($contents, TRUE)['response']['time_series'];
}