Huawei Wechselrichter in Clever-PV einbinden

Begonnen von Wazzil, 10 September 2023, 13:01:44

Vorheriges Thema - Nächstes Thema

Wazzil

Hallo zusammen,

bei mir läuft eine PV mit Batterie und Huawei Wechselrichter die Daten frage ich direkt in fhem über Modbus am Wechselrichter ab.
Die ermittelten Daten möchte ich anschließend an die Push API von Clever-PV senden https://docs.clever-pv.com/electricmeter/push-api. Dies muss im json Format als Block mit allen Werten erfolgen und daran scheitere ich momentan.

Mein Ansatz war, das ich die Werte per httpmod alle x Sekunden an die Push API übermittel. Das Problem ist allerdings, das ich auf diesem Weg immer nur einen einzelnen Wert übermitteln kann und die anderen Werte werden dann als null angenommen. Dadurch wird der Überschuss falsch berechnet und die Steuerung funktioniert of nicht bzw. schaltet zu oft ab, obwohl Überschuss vorhanden ist.

Die api benötigt die folgenden Werte:
{
"watt": -1000,
"producingWatt": 1500,
"soc": 75,
"chargingPower": 500,
"powerStorageState": 1
}

Meine Lösung sieht momentan so aus, wobei "CleverPV" der httpmod ist:
define atCleverPV at +*00:00:20 { \
my $w=(ReadingsVal("Sun2000","PM_Momentanleistung_W",0));; \
my $p=(ReadingsVal("Sun2000","WR_Eingangsleistung_Solar_W",0));; \
my $s=(ReadingsVal("Sun2000","ESS_SoC",0));; \
my $c=(ReadingsVal("Sun2000","ESU1_Momentanleistung_W",0));; \
my $e=(ReadingsVal("Sun2000","ESS_Charging",0));; \
fhem ("set CleverPV PM_Momentanleistung_W $w ;; \
               set CleverPV WR_Eingangsleistung_Solar_W $p ;; \
       set CleverPV ESS_SoC $s ;; \
       set CleverPV ESU1_Momentanleistung_W $c ;; \
       set CleverPV ESS_Status $e") \
}

Daher meine Frage, hat jemand eine Idee, wie ich einen json String mit allen benötigten Werten übermitteln kann?


ch.eick

Moin,
wie sieht denn Dein CleverPV Device aus?
Im at Device machst Du ja 5 einzel Aufrufe, wie baust Du die denn dann zusammen, bevor Du es an CleverPV sendest?

Du könntest den json String mit Deinem at zuerst zusammen bauen und als reading ins CleverPV schreiben, danach käme dann der Set CleverPV aufruf, der es per httpmod versendet.
Das json könntest Du mit einem sprintf() zusammensetzen.
sprintf('{"watt": %s,"producingWatt": %s,"soc": %s,"chargingPower": %s,"powerStorageState": %s}',$w, $p, $s, $c, $e)
# test
sprintf('{"watt": %s,"producingWatt": %s,"soc": %s,"chargingPower": %s,"powerStorageState": %s}',-1, 2, 3, 4, 5)

VG  Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Wazzil

Hallo Christian,

danke für deine schnelle Antwort. Diese Varianten hatte ich auch schon ausprobiert, den ganzen String zu übermitteln erschien mir auch logisch. Ich weiß aber nicht wieso das nicht funktioniert. Wenn ich das ganze so umstelle, dann werden keine Werte mehr übermittelt:

define CleverPV HTTPMOD https://push.clever-pv.com/api/v1/f5af3997-db37-44fb-e40b-08da7846257b/electricMeters/key 1800
attr CleverPV showBody 1
attr CleverPV showError 1
attr CleverPV verbose 5
attr CleverPV room Zentrale->Solar,Zentrale->Devices

attr CleverPV set01Name PV_Status
attr CleverPV set01Header Content-Type: application/json
attr CleverPV set01Data $val


define atCleverPV at +*00:00:20 { \
my $s=sprintf("\{\"watt\": %.0f, \"producingWatt\": %d, \"soc\": %d, \"chargingPower\": %d, \"powerStorageState\": %s\}", \
ReadingsVal("Sun2000","PM_Momentanleistung_W",0), \
ReadingsVal("Sun2000","WR_Eingangsleistung_Solar_W",0), \
ReadingsVal("Sun2000","ESS_SoC",0), \
ReadingsVal("Sun2000","ESU1_Momentanleistung_W",0), \
ReadingsVal("Sun2000","ESS_Status",0) \
) ;; \
fhem ("set CleverPV PV_Status $s") ;; \
}
attr atCleverPV2 room Zentrale->Solar,Zentrale->Devices

Der Event Monitor spuckt nur den at Aufruf aus:

2023-09-10 20:59:56 at atCleverPV Next: 21:00:16




Meine ursprünglichen Fassung sieht so aus:
define CleverPV HTTPMOD https://push.clever-pv.com/api/v1/f5af3997-db37-44fb-e40b-08da7846257b/electricMeters/key 1800
attr CleverPV showBody 1
attr CleverPV showError 1
attr CleverPV verbose 5
attr CleverPV room Zentrale->Solar,Zentrale->Devices

attr CleverPV set01Name PM_Momentanleistung_W
attr CleverPV set01Header Content-Type: application/json
attr CleverPV set01Data {"watt":$val}

attr CleverPV set02Name WR_Eingangsleistung_Solar_W
attr CleverPV set02Header Content-Type: application/json
attr CleverPV set02Data {"producingWatt":$val}

attr CleverPV set03Name ESS_SoC
attr CleverPV set03Header Content-Type: application/json
attr CleverPV set03Data {"soc":$val}

attr CleverPV set04Name ESU1_Momentanleistung_W
attr CleverPV set04Header Content-Type: application/json
attr CleverPV set04Data {"chargingPower":$val}

attr CleverPV set05Name ESS_Status
attr CleverPV set05Header Content-Type: application/json
attr CleverPV set05Data {"powerStorageState":$val}


define atCleverPV at +*00:00:20 { \
my $w=(ReadingsVal("Sun2000","PM_Momentanleistung_W",0));; \
my $p=(ReadingsVal("Sun2000","WR_Eingangsleistung_Solar_W",0));; \
my $s=(ReadingsVal("Sun2000","ESS_SoC",0));; \
my $c=(ReadingsVal("Sun2000","ESU1_Momentanleistung_W",0));; \
my $e=(ReadingsVal("Sun2000","ESS_Status",0));; \
fhem ("set CleverPV PM_Momentanleistung_W $w ;; \
   set CleverPV WR_Eingangsleistung_Solar_W $p ;; \
   set CleverPV ESS_SoC $s ;; \
   set CleverPV ESU1_Momentanleistung_W $c ;; \
   set CleverPV ESS_Status $e") ;; \
}


Dann werden die Werte einzeln übermittelt und ich bekomme die folgende Ausgabe im Event Monitor:

2023-09-10 21:06:03 HTTPMOD CleverPV PM_Momentanleistung_W 27
2023-09-10 21:06:03 HTTPMOD CleverPV WR_Eingangsleistung_Solar_W 0
2023-09-10 21:06:03 HTTPMOD CleverPV ESS_SoC 75
2023-09-10 21:06:03 HTTPMOD CleverPV ESU1_Momentanleistung_W -938
2023-09-10 21:06:03 HTTPMOD CleverPV ESS_Status 2
2023-09-10 21:06:03 at atCleverPV Next: 21:06:22


ch.eick

#3
Moin,

in Deinem CleverPV sehe ich fast keine httpmod attribute für den Set Aufruf. Hast Du da schon etwas erfelgreich übermitteln können?

Du kannst das JSON natürlich auch im HTTPMOD Device zusammen setzen, da kann man auch Perl verwenden und es wird übersichtlicher. Im at wäre dann nur das Timing, wobei ich da lieber ein DOIF verwende, was mir dann auch die Fhemweb Oberfläche mit uiTable bietet.

Bei Deinem ursprünglichen CleverPV wird ja auch pro Set nur ein Wert übermittelt, da vermute ich, dass durch die einzelaufrufe sich das httpmod mit der API in timeouts verzetteln wird. Die set Aufrufe sind bestimmt zu schnell hintereinander.
Mach hier doch mal beim data das JSON komplett rein, was Du später mit Perl und replace noch vor dem Aufruf dynamisch zusammen setzen kannst.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Wazzil

Ich fürchte soweit verstehe ich das httpmod einfach nicht. Die Commandref ist bezüglich der set Befehle recht dürftig und zu den attributen finde ich nichts brauchbares, da die Beschreibungen sich immer auf get beziehen und wie der empfangene String verarbeitet werden kann. Mir ist nicht klar wie ich das auf set Befehle anwenden kann.
So wie ich das verstanden habe, kann ich aber immer nur einen einzigen numerischen Wert übermitteln.
Aber warum funktioniert das problemlos: attr CleverPV set01Data {"watt":$val}Mit einem konkreten Wert hingegen aber nicht: attr CleverPV set01Data {"watt":123}Und ebensowenig kann ich per Readingsval dann die Werte einsetzen, geschweige denn das komplette Json Argument zusammenbasteln.

ch.eick

#5
Zitat von: Wazzil am 12 September 2023, 08:12:17Und ebensowenig kann ich per Readingsval dann die Werte einsetzen, geschweige denn das komplette Json Argument zusammenbasteln.
Moin,

hier mal ein Beispiel, für Deine Laufrichtung im httpmod
defmod CleverPV HTTPMOD https://push.clever-pv.com/api/v1/f5af3997-db37-44fb-e40b-08da7846257b/electricMeters/key none
attr CleverPV replacement01Mode expression
attr CleverPV replacement01Regex %PV_Status_JSON%
attr CleverPV replacement01Value {my $WR_1="Sun2000";; \
  my $w=ReadingsVal("$WR_1","PM_Momentanleistung_W",0);; \
  my $p=ReadingsVal("$WR_1","WR_Eingangsleistung_Solar_W",0);; \
  my $s=ReadingsVal("$WR_1","ESS_SoC",0);; \
  my $c=ReadingsVal("$WR_1","ESU1_Momentanleistung_W",0);; \
  my $e=ReadingsVal("$WR_1","ESS_Charging",0);; \
  sprintf('{"watt": %s,"producingWatt": %s,"soc": %s,"chargingPower": %s,"powerStorageState": %s}',$w, $p, $s, $c, $e);; \
 }
attr CleverPV room Zentrale->Solar,Zentrale->Devices
attr CleverPV set01Data %PV_Status_JSON%
attr CleverPV set01Header Content-Type: application/json
attr CleverPV set01Name PV_Status
attr CleverPV set01NoArg 1
attr CleverPV showBody 1
attr CleverPV showError 1
attr CleverPV verbose 5

Hier ein Ausschnitt aus dem verbose 5 Log
2023.09.12 17:01:25.901 4: CleverPV: HandleSendQueue sends set01 with timeout 2 to https://push.clever-pv.com/api/v1/f5af3997-db37-44fb-e40b-08da7846257b/electricMeters/key,
data: {"watt": 0,"producingWatt": 0,"soc": 0,"chargingPower": 0,"powerStorageState": 0},
header: Content-Type: application/json
2023.09.12 17:01:26.117 5: CleverPV: ReadCallback called from __ANON__
2023.09.12 17:01:26.117 4: CleverPV: Read callback: request type was set01 retry 0,
header: HTTP/1.1 403 Forbidden
Content-Type: text/plain; charset=utf-8
Request-Context: appId=cid-v1:ab789df1-c5a5-4649-a8d0-03fcd908b2a2
X-Cache: CONFIG_NOCACHE
X-Azure-Ref: 0Rn0AZQAAAACdtV63K/bJQK9iaCk1EkzmQkVSMzBFREdFMDQxNgBkNzE2OWVmNy05YjVlLTQ1YmEtODlmNi04ODZjMjk1YmM5MjQ=
Date: Tue, 12 Sep 2023 15:01:25 GMT
Connection: close, body length 47
2023.09.12 17:01:26.118 5: CleverPV: Read callback: body
❌ You are not allowed to access this api. ❌

Jetzt noch eine kleine Frage, warum gehst Du über CleverPV, wenn Du mit FHEM auch alles lokal erledigen könntest?

VG  Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Wazzil

Hallo Christian,

danke für das Beispiel. Allerdings verstehe ich nicht, warum du den "Umweg" über Regex gehst. Kann ich den String denn dann nicht direkt im data Attribut zusammenfügen? So in etwa hatte ich das auch schon einmal probiert, allerdings ohne das NoArgs, das war vermutlich der Fehler.

Und entschuldige die blöde Frage: wie trigger ich den CleverPV denn jetzt? Ich bin davon ausgegangen, das ich ein Intervall setzen muss, das hast du hier auf "none" gesetzt. Ich verstehe zwar, wie ich über den perl Aufruf einen Wert setzen kann, wenn ich ein set Attribut mit Wert aufrufe. Aber wie kann ich hier das set Attribut "PV_Status" aufrufen?

Die Fehlermeldung bekommst du übrigens, weil ich dir den key im Beispiel nicht angegeben habe.

Clever-PV nutze ich aus zwei Gründen:
1. will ich das Rad nicht neu erfinden, ich hatte angefangen mit einer eigenen Logik, aber schnell festgestellt, das das sehr aufwändig wird.
2. Ich kann über fhem mit fhempy meine Walbox nicht so steuern, wie ich es benötige um die Ladeleistung an den PV Überschuss anzupassen. Mit fhempy konnte ich die Wallbox lediglich mit einer eingestellten Leistung laden lassen und pausieren wenn zu wenig von der PV Anlage kam. Clever-PV hat das Problem perfekt gelöst, die Ladeleistung passt sich exakt dem Überschuss an, je nach Pkw geht damit sogar eine Phasenumschaltung.

ch.eick

#7
Zitat von: Wazzil am 12 September 2023, 23:22:29Hallo Christian,

danke für das Beispiel. Allerdings verstehe ich nicht, warum du den "Umweg" über Regex gehst. Kann ich den String denn dann nicht direkt im data Attribut zusammenfügen? So in etwa hatte ich das auch schon einmal probiert, allerdings ohne das NoArgs, das war vermutlich der Fehler.
Wenn man im data auch direkt regex angeben kann, dann geht das natürlich auch da. Ich hatte das Beispiel recht schnell zusammen kopiert und nicht auf Schönheit getrimmt.

EDIT: Im data wird kein Perl ausgeführt, hier mal die Stelle im Log, der Perl Code bleibt einfach so erhalten.
data: {my $WR_1="Sun2000";
  my $w=ReadingsVal("$WR_1","PM_Momentanleistung_W",0);
  my $p=ReadingsVal("$WR_1","WR_Eingangsleistung_Solar_W",0);
  my $s=ReadingsVal("$WR_1","ESS_SoC",0);
  my $c=ReadingsVal("$WR_1","ESU1_Momentanleistung_W",0);
  my $e=ReadingsVal("$WR_1","ESS_Charging",0);
  sprintf('{"watt": %s,"producingWatt": %s,"soc": %s,"chargingPower": %s,"powerStorageState": %s}',$w, $p, $s, $c, $e);
 },
Man kann natürlich den data String auch im at zusammen setzen und dann komplett an das set übergeben, dadurch ist es jedoch etwas unübersichtlicher, weil man im httpmod den String nicht sehen kann.

ZitatUnd entschuldige die blöde Frage: wie trigger ich den CleverPV denn jetzt? Ich bin davon ausgegangen, das ich ein Intervall setzen muss, das hast du hier auf "none" gesetzt. Ich verstehe zwar, wie ich über den perl Aufruf einen Wert setzen kann, wenn ich ein set Attribut mit Wert aufrufe. Aber wie kann ich hier das set Attribut "PV_Status" aufrufen?

Die Fehlermeldung bekommst du übrigens, weil ich dir den key im Beispiel nicht angegeben habe.
Das wäre ein Aufruf z.B. aus einem at oder DOIF
set CleverPV PV_Status
Das none kannst Du ja wieder durch eine Zeit ersetzen, das triggert jedoch nicht individuelle set definitionen. Die müsstest Du dann man als generische Attribute ausprobieren und schauen, ob das dann verwendet wird. Als Default wäre das natürlich dann sehr schön und würde kein at oder DOIF benötigen.
Du kannst ja dann Dein Endergebnis mal posten.

EDIT: Hier wäre dann jetzt mal ein Beispiel ohne ein set Attribut, aber mit einem Default requestData.
   Das kann man dann mit einem Intervall ausführen lassen und es würde ohne ein AT oder DOIF zyklisch
   die Daten zu CleverPV senden.
defmod CleverPV HTTPMOD https://push.clever-pv.com/api/v1/f5af3997-db37-44fb-e40b-08da7846257b/electricMeters/key 60
attr CleverPV DbLogExclude .*
attr CleverPV replacement01Mode expression
attr CleverPV replacement01Regex %PV_Status_JSON%
attr CleverPV replacement01Value {my $WR_1="Sun2000";; \
  my $w=ReadingsVal("$WR_1","PM_Momentanleistung_W",0);; \
  my $p=ReadingsVal("$WR_1","WR_Eingangsleistung_Solar_W",0);; \
  my $s=ReadingsVal("$WR_1","ESS_SoC",0);; \
  my $c=ReadingsVal("$WR_1","ESU1_Momentanleistung_W",0);; \
  my $e=ReadingsVal("$WR_1","ESS_Charging",0);; \
  sprintf('{"watt": %s,"producingWatt": %s,"soc": %s,"chargingPower": %s,"powerStorageState": %s}',$w, $p, $s, $c, $e);; \
 }
attr CleverPV requestData %PV_Status_JSON%
attr CleverPV requestHeader1 Content-Type: application/json

attr CleverPV room Zentrale->Solar,Zentrale->Devices
attr CleverPV showBody 1
attr CleverPV showError 1
attr CleverPV verbose 5


ZitatClever-PV nutze ich aus zwei Gründen:
1. will ich das Rad nicht neu erfinden, ich hatte angefangen mit einer eigenen Logik, aber schnell festgestellt, das das sehr aufwändig wird.
2. Ich kann über fhem mit fhempy meine Walbox nicht so steuern, wie ich es benötige um die Ladeleistung an den PV Überschuss anzupassen. Mit fhempy konnte ich die Wallbox lediglich mit einer eingestellten Leistung laden lassen und pausieren wenn zu wenig von der PV Anlage kam. Clever-PV hat das Problem perfekt gelöst, die Ladeleistung passt sich exakt dem Überschuss an, je nach Pkw geht damit sogar eine Phasenumschaltung.
Okay, es gibt ja hier bereits viele Muster und auch komplexe Lösungen :-)
Meine openWB ist ja direkt mit MQTT eingebunden und lässt keine Wünsche offen.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Wazzil

Hallo Christian,

sorry für die späte Rückmeldung, wir waren die letzen Wochen im Urlaub und ich hab mir das heute erst anschauen können.
Nachdem bisher leider auch deine Vorschläge nicht funktioniert hatten – es wurden einfach keine Werte übertragen und ich habe keine Ahnung, wie ich von der Gegenseite einen Status bekomme, habe ich grad deinen modifizierten Vorschlag getestet:

Zitat von: ch.eick am 13 September 2023, 13:38:57EDIT: Hier wäre dann jetzt mal ein Beispiel ohne ein set Attribut, aber mit einem Default requestData.
  Das kann man dann mit einem Intervall ausführen lassen und es würde ohne ein AT oder DOIF zyklisch
  die Daten zu CleverPV senden.

Das schien der entscheidende Punkt zu sein. Mit deinem Code – hab ich so eingesetzt – funktioniert die Übermittlung der Werte tadellos. Ich hab allerdings immer noch keine Ahnung was hier passiert. Das httpmod ist mir im Bezug auf die Übertragung von Daten ein Rätsel. Warum sollte das mit set nicht genau so funktionieren?!

Danke für deine Geduld :-)

ch.eick

Wie gesagt, beim set müsstest Du separat selber triggern.
Man kann jedoch auch mehrere set noch ergänzen, je nach dem was man alles lösen möchte. Soll nur so wie jetzt zyklisch gesendet werden, dann reicht es doch.
Welche Status sollen den noch abgefragt werden? Für Fehler müsste man die http Rückmeldung kennen und diese dann auswerten.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick