Forum: Haus & Smart Home OpenDTU WEB-api


von Mathias M. (atuditu)


Lesenswert?

Hallo,
ich habe zwei HM800 Wechselrichter an einer OpenDTU. Von meinem Laptop 
kann ich mit

curl --no-progress-meter http://192.168.0.153/api/livedata/status | jq

alle möglichen Livedaten in Form einer langen Liste auslesen, die so 
aussieht:

{
  "inverters": [
    {
      "serial": "114190651346",
      "name": "WR-1",
      "order": 0,
      "data_age": 0,
      "poll_enabled": true,
      "reachable": true,
      "producing": true,
      "limit_relative": 100,
      "limit_absolute": 800,
      "AC": {
        "0": {
          "Power": {
            "v": 323.7999878,
            "u": "W",
            "d": 1
          },
          "Voltage": {
            "v": 227.6999969,
            "u": "V",
            "d": 1
          },
             .
             .
             .
  ],
  "total": {
    "Power": {
      "v": 542.2999878,
      "u": "W",
      "d": 1
    },
    "YieldDay": {
      "v": 721,
      "u": "Wh",
      "d": 0
    },
    "YieldTotal": {
      "v": 611.6069946,
      "u": "kWh",
      "d": 3
    }
  },
  "hints": {
    "time_sync": false,
    "radio_problem": false,
    "default_password": false
  }
}


Mit

curl --no-progress-meter http://192.168.0.153/api/livedata/status | jq 
'.total | .Power.v'

erhalte ich die momentan gelieferte Leistung beider WR zusammen.

Ich hätte aber gerne die Leistungen beider Wechselrichter getrennt.

Mit

curl --no-progress-meter 
http://192.168.0.153/api/livedata/status?inv=114190651346 | jq

bekomme ich genau die selbe lange Liste. Die Doku zur WEB-api habe ich 
zwar gelesen, verstehe aber trotzdem nicht, wie ich an den Wert

      "AC": {
        "0": {
          "Power": {
            "v": 323.7999878

des Wechselrichters 114190651346 komme. Ich möchte die momentane 
Leistung (also hier 323.7999878) in eine Variable schreiben. Kann mir da 
bitte jemand weiterhelfen?

Oh, ich sehe gerade in der Vorschau, dass die Formatierung der Liste 
verloren gegangen ist. Ich weiß auch nicht, wie ich das verhindern kann.

von Michael H. (mha1)


Lesenswert?

Das Manual zu jd ist dein Freund.

https://jqlang.github.io/jq/manual

Und auf https://jqplay.org/ kannst du es dann direkt ausprobieren.

Mit .inverters[0].AC."0".Power.v kommst Du an den Wert des ersten 
Inverters.

Ich nutze für sowas meinen MQTT Broker (mosquitto). Da kann ich dann 
direkt auf die Werte zugreifen (ohne erst die JSON Antwort parsen zu 
müssen).

von Mathias M. (atuditu)


Lesenswert?

@mha1

Vielen Dank für Deine schnelle Antwort.
Das ist auch genau die Lösung, die ich gesucht habe. Das Doku-lesen ist 
ja, ach, so anstrengend. Es ist ja viel einfacher, stundenlang herum zu 
probieren, als fünf Minuten in die Doku zu schaun, oder?

von Mathias M. (atuditu)


Lesenswert?

Na ja, ich hätte mir ja eigentlich denken können, dass ich mich zu früh 
gefreut habe. Das mit "curl" funktioniert wunderbar auf der 
Befehlszeile, ich erhalte den richtigen Wert.
Aber diesen Wert möchte ich ja in einem Python-Script einer Variablen 
zuweisen, und Python kann mit "curl" wohl nichts anfangen.
Nach etwas Stöbern bin ich auf die requests-library gestoßen, und habe 
folgendes probiert:
1
#! /usr/bin/env python3
2
3
import requests
4
5
r = requests.get(f"http://192.168.0.153/api/livedata/status")
6
7
print(r.content)

Hiermit erhalte ich diese lange Liste, die aber auch enthält, was ich 
suche:

-----------------------------------------------------------
1
b'{"inverters":[{"serial":"114190651346","name":"WR-1","order":0,"data_age":1,"poll_enabled":true,"reachable":true,"producing":true,"limit_relative":100,"limit_absolute":800,"AC":{"0":{"Power":{"v":453.6000061,"u":"W","d":1},"Voltage":{"v":229.3999939,"u":"V","d":1},"Current":{"v":1.980000019,"u":"A","d":2},"Power DC":{"v":476.5,"u":"W","d":1},"YieldDay":{"v":990,"u":"Wh","d":0},"YieldTotal":{"v":358.7929993,"u":"kWh","d":3},"Frequency":{"v":49.97999954,"u":"Hz","d":2},"PowerFactor":{"v":1,"u":"","d":3},"ReactivePower":{"v":0,"u":"var","d":1},"Efficiency":{"v":95.19412231,"u":"%","d":3}}},"DC":{"0":{"name":{"u":"West"},"Power":{"v":221.1000061,"u":"W","d":1},"Voltage":{"v":25.70000076,"u":"V","d":1},"Current":{"v":8.609999657,"u":"A","d":2},"YieldDay":{"v":473,"u":"Wh","d":0},"YieldTotal":{"v":170.3939972,"u":"kWh","d":3},"Irradiation":{"v":48.59340668,"u":"%","d":3,"max":455}},"1":{"name":{"u":"Mitte"},"Power":{"v":255.3999939,"u":"W","d":1},"Voltage":{"v":27.79999924,"u":"V","d":1},"Current":{"v":9.180000305,"u":"A","d":2},"YieldDay":{"v":517,"u":"Wh","d":0},"YieldTotal":{"v":188.3990021,"u":"kWh","d":3},"Irradiation":{"v":56.13187027,"u":"%","d":3,"max":455}}},"INV":{"0":{"Temperature":{"v":48.90000153,"u":"\xc2\xb0C","d":1}}},"events":3},{"serial":"114190138728","name":"WR-2","order":1,"data_age":2,"poll_enabled":true,"reachable":true,"producing":true,"limit_relative":100,"limit_absolute":800,"AC":{"0":{"Power":{"v":352.2000122,"u":"W","d":1},"Voltage":{"v":230.3999939,"u":"V","d":1},"Current":{"v":1.529999971,"u":"A","d":2},"Power DC":{"v":370,"u":"W","d":1},"YieldDay":{"v":640,"u":"Wh","d":0},"YieldTotal":{"v":260.0679932,"u":"kWh","d":3},"Frequency":{"v":49.97999954,"u":"Hz","d":2},"PowerFactor":{"v":1,"u":"","d":3},"ReactivePower":{"v":0.300000012,"u":"var","d":1},"Efficiency":{"v":95.18919373,"u":"%","d":3}}},"DC":{"0":{"name":{"u":"Balkon"},"Power":{"v":116.4000015,"u":"W","d":1},"Voltage":{"v":31.79999924,"u":"V","d":1},"Current":{"v":3.660000086,"u":"A","d":2},"YieldDay":{"v":128,"u":"Wh","d":0},"YieldTotal":{"v":67.64900208,"u":"kWh","d":3},"Irradiation":{"v":58.20000076,"u":"%","d":3,"max":200}},"1":{"name":{"u":"Ost"},"Power":{"v":253.6000061,"u":"W","d":1},"Voltage":{"v":27.70000076,"u":"V","d":1},"Current":{"v":9.170000076,"u":"A","d":2},"YieldDay":{"v":512,"u":"Wh","d":0},"YieldTotal":{"v":192.4190063,"u":"kWh","d":3},"Irradiation":{"v":55.73626709,"u":"%","d":3,"max":455}}},"INV":{"0":{"Temperature":{"v":43.29999924,"u":"\xc2\xb0C","d":1}}},"events":1}],"total":{"Power":{"v":805.8000488,"u":"W","d":1},"YieldDay":{"v":1630,"u":"Wh","d":0},"YieldTotal":{"v":618.8609619,"u":"kWh","d":3}},"hints":{"time_sync":false,"radio_problem":false,"default_password":true}}'
-------------------------------------------------------------

Sieht ja schon mal gut aus. ich brauche aus der Zeile

"AC":{"0":{"Power":{"v":453.6000061,"u":"W","d":1}

also diesen Wert 453.6.
Dann habe ich (analog zur curl-Zeile) folgendes versucht:
1
r = requests.get(f"http://192.168.0.153/api/livedata/status").json()['.inverters[0].AC."0".Power.v']
bekomme aber damit den Fehler:
1
KeyError: '.inverters[0].AC."0".Power.v'
Natürlich habe ich in die requests Doku geschaut, aber auch hier wird 
ein Grundwissen vorausgesetzt, das ich einfach nicht habe. Ich kann 
{},[],(),:,' nicht richtig interpretieren. Ich sehe zwar, dass ein 
Fehler aufgetreten ist, aber ich weiß nicht, wie ich ihn vermeiden kann. 
Vermutlich ist das ganz einfach, man muss nur wissen, wie.

Wie lautet die alte Weisheit?:
1
Wissen ist Macht!
2
Weißt' nix?
3
Macht nix!
4
Frag halt!
Das mache ich dann hiermit.
Kann mir jemand den richtigen Tip geben?

von Uwe L. (ul5255)


Lesenswert?

vllt. so?

r = requests.get(f"...").json()['inverters'][0]['AC']['0']['Power']['v']

von Mathias M. (atuditu)


Lesenswert?

@Uwe L.

Nö,
1
TypeError: list indices must be integers or slices, not str
Lasse ich bei der ersten 0 die Hochkommata weg:
1
AttributeError: 'float' object has no attribute 'status_code'
Also mache ich die Hochkommas da wieder hin und entferne sie bei der 
zweiten 0.
1
TypeError: list indices must be integers or slices, not str

Mache ich sie bei beiden weg:
1
KeyError: 0

???

von Uwe L. (ul5255)


Lesenswert?

gerade online (https://www.online-python.com/kM5vqwXzlA) ausprobiert:

import json
x = 
json.loads(b'{"inverters":[{"serial":"114190651346","name":"WR-1","order 
":0,"data_age":1,"poll_enabled":true,"reachable":true,"producing":true," 
limit_relative":100,"limit_absolute":800,"AC":{"0":{"Power":{"v":453.600 
0061,"u":"W","d":1},"Voltage":{"v":229.3999939,"u":"V","d":1},"Current": 
{"v":1.980000019,"u":"A","d":2},"Power 
DC":{"v":476.5,"u":"W","d":1},"YieldDay":{"v":990,"u":"Wh","d":0},"Yield 
Total":{"v":358.7929993,"u":"kWh","d":3},"Frequency":{"v":49.97999954,"u 
":"Hz","d":2},"PowerFactor":{"v":1,"u":"","d":3},"ReactivePower":{"v":0, 
"u":"var","d":1},"Efficiency":{"v":95.19412231,"u":"%","d":3}}},"DC":{"0 
":{"name":{"u":"West"},"Power":{"v":221.1000061,"u":"W","d":1},"Voltage" 
:{"v":25.70000076,"u":"V","d":1},"Current":{"v":8.609999657,"u":"A","d": 
2},"YieldDay":{"v":473,"u":"Wh","d":0},"YieldTotal":{"v":170.3939972,"u" 
:"kWh","d":3},"Irradiation":{"v":48.59340668,"u":"%","d":3,"max":455}}," 
1":{"name":{"u":"Mitte"},"Power":{"v":255.3999939,"u":"W","d":1},"Voltag 
e":{"v":27.79999924,"u":"V","d":1},"Current":{"v":9.180000305,"u":"A","d 
":2},"YieldDay":{"v":517,"u":"Wh","d":0},"YieldTotal":{"v":188.3990021," 
u":"kWh","d":3},"Irradiation":{"v":56.13187027,"u":"%","d":3,"max":455}} 
},"INV":{"0":{"Temperature":{"v":48.90000153,"u":"\xc2\xb0C","d":1}}},"e 
vents":3},{"serial":"114190138728","name":"WR-2","order":1,"data_age":2, 
"poll_enabled":true,"reachable":true,"producing":true,"limit_relative":1 
00,"limit_absolute":800,"AC":{"0":{"Power":{"v":352.2000122,"u":"W","d": 
1},"Voltage":{"v":230.3999939,"u":"V","d":1},"Current":{"v":1.529999971, 
"u":"A","d":2},"Power 
DC":{"v":370,"u":"W","d":1},"YieldDay":{"v":640,"u":"Wh","d":0},"YieldTo 
tal":{"v":260.0679932,"u":"kWh","d":3},"Frequency":{"v":49.97999954,"u": 
"Hz","d":2},"PowerFactor":{"v":1,"u":"","d":3},"ReactivePower":{"v":0.30 
0000012,"u":"var","d":1},"Efficiency":{"v":95.18919373,"u":"%","d":3}}}, 
"DC":{"0":{"name":{"u":"Balkon"},"Power":{"v":116.4000015,"u":"W","d":1} 
,"Voltage":{"v":31.79999924,"u":"V","d":1},"Current":{"v":3.660000086,"u 
":"A","d":2},"YieldDay":{"v":128,"u":"Wh","d":0},"YieldTotal":{"v":67.64 
900208,"u":"kWh","d":3},"Irradiation":{"v":58.20000076,"u":"%","d":3,"ma 
x":200}},"1":{"name":{"u":"Ost"},"Power":{"v":253.6000061,"u":"W","d":1} 
,"Voltage":{"v":27.70000076,"u":"V","d":1},"Current":{"v":9.170000076,"u 
":"A","d":2},"YieldDay":{"v":512,"u":"Wh","d":0},"YieldTotal":{"v":192.4 
190063,"u":"kWh","d":3},"Irradiation":{"v":55.73626709,"u":"%","d":3,"ma 
x":455}}},"INV":{"0":{"Temperature":{"v":43.29999924,"u":"\xc2\xb0C","d" 
:1}}},"events":1}],"total":{"Power":{"v":805.8000488,"u":"W","d":1},"Yie 
ldDay":{"v":1630,"u":"Wh","d":0},"YieldTotal":{"v":618.8609619,"u":"kWh" 
,"d":3}},"hints":{"time_sync":false,"radio_problem":false,"default_passw 
ord":true}}')
print(x['inverters'][0]['AC']['0']['Power']['v'])
# gibt aus: 453.60000 ....

von Mathias M. (atuditu)


Lesenswert?

@Uwe L.

Ja, das war's, das geht bei mir jetzt auch. Der Knackpunkt war wohl das 
fehlende "import json" und die "json.loads" Anweisung.

Merkwürdig finde ich allerdings, dass ich im gleichen Script schon auf 
zwei unterschiedliche shellys zugreife (ein- und dreiphasiger 
Leistungsmesser).
Auch hier benutze ich die requests-library und json, und das 
funktioniert, ohne dass ich explizit json importieren musste.

Nur zur Info:
den einphasigen shelly lese ich so aus:
1
sh_1=requests.get(f'http://ipaddr/rpc/PM1.GetStatus?id=0').json()["apower"]
und den dreiphasigen so:
1
sh_3=requests.get(f'http://ipaddr/rpc/EM.GetStatus?id=0').json()["total_act_power"]
Die entsprechenden Zeilen habe ich irgendwo im Netz gefunden, alleine 
wäre ich da nie drauf gekommen. Diese Zeilen habe ich mir zum Vorbild 
genommen, um auch auf den Wechselrichter (über OpenDTU) zuzugreifen. 
Aber das war wohl nichts.

Dir ganz herzlichen Dank, jetzt kann ich endlich weiterbasteln, das 
nächste Problem wartet schon auf mich (und die 
mikrocontroller-Gemeinde).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.