Seit längerer Zeit schon lese ich die Daten meiner SMA Solaranlage über Modbus aus und verarbeite sie in HomeMatic weiter (siehe dazu auch viewtopic.php?f=31&t=47813&hilit=Sunny+ ... ge#p478866).
Leider besitzt aber die Wallbox "SMA EV Charger 22" bisher keine Modbus Schnittstelle (Stand 27.02.22) und ein Zugriff der Daten blieb mir somit verwehrt.
Nach einigen Recherchen im Internet habe ich dann eine Lösung gefunden, die Daten des SMA EV Charger 22 über die JSON-API-Schnittstelle der Wallbox mit HomeMatic auszulesen. Ein entsprechender curl Aufrufe an die Wallbox und Verarbeitung der Antworten macht die aktuelle Betriebsdaten als auch die Einstellparameter des Gerätes zugänglich.
Auf dem gleichen Weg lassen sich so auch Parameter der Wallbox ändern und z.B. die gewünschte Lademenge und Zielzeit. Die dadurch entstehenden Anwendungsmöglichkeiten für die Automatisierung sind vielfältig.
Die Implementierung in HomeMatic habe ich wie folgt realisiert:
- 1. Hauptrogramm zum Abfragen von
- a. Zugriffs-Token der Wallbox
b. Aktuelle Betriebsdaten
3. Zusatzprogramme zum Ändern von Parametern- a. Setzen von Lademenge und Ladedauer
b. Ändern der Betriebsart der Wallbox (z.B. auf Optimiertes Laden)
- a. Zugriffs-Token der Wallbox
SMA EV Access IP = IP Adresse der Wallbox im Format "http://192.168.123.xx"
SMA EV Access USER = User ID zum Zugriff auf die Wallbox
SMA EV Access PASSWORD = Zugehöriges Passwort
SMA EV Meldung = Meldungen/Feedback aus den Programmen zur Anzeige im verwendeten GUI
SMA EV Ladevorgang Energiemenge (Werteliste) = -Auswählen-;1 kWh;2 kWh;3 kWh;4 kWh;5 kWh;6 kWh;…
SMA EV Ladevorgang Dauer (Werteliste) = -Auswählen-;1 Std.;2 Std.;3 Std.;4 Std.;5 Std.;6 Std.;7 Std.;…
Ein erster Test
Mit nachfolgendem Skript habe ich mir den Zugriff auf die Wallboxdaten erarbeitet.
Es ermittelt den Zugriffs-Token und liest dann die Daten aus der Wallbox.
Um die im JSON Format empfangenen Daten besser analysieren zu können, werden in einem Testprogramm die einzelnen Kanäle aufgelistet
Code: Alles auswählen
! Test Skript zum Lesen und Schreiben von Daten vom SMA EV Charger 22
! !! Nicht für den operativen Einsatz vorgesehen !!
! --------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string USER = dom.GetObject("SMA EV Access USER").Value();
string PASSWORD= dom.GetObject("SMA EV Access PASSWORD").Value();
string sToken = "";
var s = "";
WriteLine("------------------------------------------------------");
WriteLine("- 1. Access Token bei Wallbox abfragen -")
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl "#IP#"/api/v1/token -d 'grant_type=password&username="#USER#"&password="#PASSWORD#"' | jq .access_token");
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "") {WriteLine("- No Access Token received -"); quit;}
sToken = " -H 'Authorization: Bearer '" # lGetOut.Replace("\"", ""); ! "
WriteLine("Token = " #sToken);
WriteLine("------------------------------------------------------");
WriteLine("- 2. Aktuelle Daten von Wallbox abfragen -");
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl "#IP#"/api/v1/measurements/live/ -d '[{\"componentId\":\"IGULD:SELF\"}]'" # sToken);
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
! WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "") {WriteLine("- No Data received -"); quit;}
! Alle Objekte der Antwort auflisten
var i = 0;
var sText = lGetOut.StrValueByIndex("{\"channelId\":", i);
while (sText <> "")
{
WriteLine(i # " = " # sText);
i = i + 1;
sText = lGetOut.StrValueByIndex("{\"channelId\":", i);
}
Nachdem das Testprogramm fehlerfrei funktionierte, habe ich mich an das operative Version gemacht.
Lesen der Betriebsdaten
Das Hauptprogramm wird zyklisch jede Minute ausgeführt, bestimmt dabei jeweils das aktuelle Zugriffs-Token und liest die Betriebsdaten .
Code: Alles auswählen
! HomeMatic
! Skript zum Auslesen der Daten einer SMA EV Charger 22 Wallbox.
!
! Die benötigten Daten werden in die entsprechenden Systemvariablen gespeichert.
! Falls Access Token oder Daten nicht gelesen werden können, bricht das Skript ab.
!
! 02.02.22 ED: Initial Version
! 17.02.22 ED: Direktabruf mir "curl" ohne Shell Script
! ----------------------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string USER = dom.GetObject("SMA EV Access USER").Value();
string PASSWORD= dom.GetObject("SMA EV Access PASSWORD").Value();
string sToken = "";
var s = "";
WriteLine("------------------------------------------------------");
WriteLine("- 1. Access Token bei Wallbox abfragen -")
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl "#IP#"/api/v1/token -d 'grant_type=password&username="#USER#"&password="#PASSWORD#"' | jq .access_token");
WriteLine ("sCurl = " # sCurl); ! Debug
system.Exec( sCurl, &lGetOut,&lGetErr);
! WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "")
{
s = "Token lesen fehlgeschlagen"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
quit;
}
! Token für weiter verwendung aufbereiten
sToken = " -H 'Authorization: Bearer '" # lGetOut.Replace("\"", ""); ! "
! Token in Systemvariable zwischenspeichern
dom.GetObject("SMA EV Token").State(sToken);
WriteLine("------------------------------------------------------");
WriteLine("- 2. Aktuelle Daten von Wallbox abfragen -");
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl "#IP#"/api/v1/measurements/live/ -d '[{\"componentId\":\"IGULD:SELF\"}]'" # sToken);
WriteLine ("sCurl = " # sCurl); ! Debug
system.Exec( sCurl, &lGetOut,&lGetErr);
! WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "")
{
s = "Daten lesen fehlgeschlagen"; WriteLine(s);
!dom.GetObject("SMA EV Meldung").State(s);
quit;
}
! 3. Data Parser (Daten extrahieren)
! ------------------------------
! Einzelschritte des Parsers, um Prinzip verständlich zu machen
! s = lGetOut.StrValueByIndex("Measurement.ChaSess.WhIn", 1); WriteLine("s1= "# s);
! s = s.StrValueByIndex("},", 0); WriteLine("s2= "# s);
! s = s.StrValueByIndex("\"value\":", 1); WriteLine("s3= "# s);
! s = s.StrValueByIndex("}]", 0).Substr(7, s.Length());
! WriteLine("ChaSess.WhIn= "# s);
! ------------------------------
s = lGetOut.StrValueByIndex("Measurement.ChaSess.WhIn", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("ChaSess.WhIn= "# s);
dom.GetObject("SMA EV Energie Ladevorgang").State( s.ToFloat()/1000 );
s = lGetOut.StrValueByIndex("Measurement.Chrg.ModSw", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Chrg.ModSw= "# s);
if (s==4950) {dom.GetObject("SMA EV Drehschalter").State(1);} else {dom.GetObject("SMA EV Drehschalter").State(0);}
s = lGetOut.StrValueByIndex("Measurement.GridMs.A.phsA", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.A.phsA= "# s);
dom.GetObject("SMA EV Netzstrom Phs L1").State(s.ToFloat()*-1);
s = lGetOut.StrValueByIndex("Measurement.GridMs.A.phsB", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.A.phsB= "# s);
dom.GetObject("SMA EV Netzstrom Phs L2").State(s.ToFloat()*-1);
s = lGetOut.StrValueByIndex("Measurement.GridMs.A.phsC", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.A.phsC= "# s);
dom.GetObject("SMA EV Netzstrom Phs L3").State(s.ToFloat()*-1);
s = lGetOut.StrValueByIndex("Measurement.GridMs.Hz", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.Hz= "# s);
dom.GetObject("SMA EV Netzfrequenz").State(s);
s = lGetOut.StrValueByIndex("Measurement.GridMs.PhV.phsA", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.PhV.phsA= "# s);
dom.GetObject("SMA EV Netzspannung Phs L1").State(s);
s = lGetOut.StrValueByIndex("Measurement.GridMs.PhV.phsB", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.PhV.phsB= "# s);
dom.GetObject("SMA EV Netzspannung Phs L2").State(s);
s = lGetOut.StrValueByIndex("Measurement.GridMs.PhV.phsC", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.PhV.phsC= "# s);
dom.GetObject("SMA EV Netzspannung Phs L3").State(s);
! s = lGetOut.StrValueByIndex("Measurement.GridMs.TotPF", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.TotPF= "# s);
! s = lGetOut.StrValueByIndex("Measurement.GridMs.TotVA", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.TotVA= "# s);
! s = lGetOut.StrValueByIndex("Measurement.GridMs.TotVAr", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.TotVAr= "# s);
! s = lGetOut.StrValueByIndex("Measurement.InOut.GI1", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("InOut.GI1= "# s);
! s = lGetOut.StrValueByIndex("Measurement.Metering.GridMs.TotWIn", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Metering.GridMs.TotWIn= "# s);
s = lGetOut.StrValueByIndex("Measurement.Metering.GridMs.TotWIn.ChaSta", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.TotWIn.ChaSta= "# s);
dom.GetObject("SMA EV Leistung Ladestation").State(s.ToFloat()/1000);
! s = lGetOut.StrValueByIndex("Measurement.Metering.GridMs.TotWhIn", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Metering.GridMs.TotWhIn= "# s);
s = lGetOut.StrValueByIndex("Measurement.Metering.GridMs.TotWhIn.ChaSta", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("GridMs.TotWhIn.ChaSta= "# s);
dom.GetObject("SMA EV Zählerstand Ladestation").State(s.ToFloat()/1000);
s = lGetOut.StrValueByIndex("Measurement.Operation.EVeh.ChaStt", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Operation.EVeh.ChaStt= "# s);
dom.GetObject("SMA EV Status Ladevorgang").State(s.ToInteger()-200111); ! Element aus Werteliste
! s = lGetOut.StrValueByIndex("Measurement.Operation.EVeh.Health", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Operation.EVeh.Health= "# s);
s = lGetOut.StrValueByIndex("Measurement.Operation.Evt.Msg", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Operation.Evt.Msg= "# s);
dom.GetObject("SMA EV Zustandsmeldung").State(s);
s = lGetOut.StrValueByIndex("Measurement.Operation.Health", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Operation.Health= "# s);
if (s.ToInteger() == 307) {s="Ok";}
dom.GetObject("SMA EV Zustand").State(s);
! s = lGetOut.StrValueByIndex("Measurement.Operation.WMaxLimSrc", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("Operation.WMaxLimSrc= "# s);
s = "Daten lesen erfolgreich"; WriteLine(s);
WriteLine("- fertig -");
Zugegeben, mein "JSON Parser" ist rudimentär, funktioniert aber bestens.
Die Kanalnamen und deren Bedeutung können übrigens im GUI der Wallbox unter Momentanwerte leicht herausgefunden werden.
Lesen der Einstellparameter
Der im Hauptprogramm ermittelte Zugriffs-Token wird übernommen und die Einstellparameter in einem separaten Programm ausgelesen.
Hier das Testprogramm für das Lesen der Parameter
Code: Alles auswählen
! Test Skript zum Lesen und Schreiben von Daten vom SMA EV Charger 22
! !! Nicht für den operativen Einsatz vorgesehen !!
! --------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string USER = dom.GetObject("SMA EV Access USER").Value();
string PASSWORD= dom.GetObject("SMA EV Access PASSWORD").Value();
string sToken = "";
var s = "";
WriteLine("------------------------------------------------------");
WriteLine("- 1. Access Token bei Wallbox abfragen -")
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl "#IP#"/api/v1/token -d 'grant_type=password&username="#USER#"&password="#PASSWORD#"' | jq .access_token");
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "") {WriteLine("- No Access Token received -"); quit;}
sToken = " -H 'Authorization: Bearer '" # lGetOut.Replace("\"", ""); ! "
WriteLine("Token = " #sToken);
WriteLine("------------------------------------------------------");
WriteLine("- 2. Parameter von Wallbox abfragen -");
string lGetOut = ""; string lGetErr = "";
string sCurl = ("curl -s -k -X 'POST' "#IP#"/api/v1/parameters/search/ -H 'Content-Type: application/json' -H 'Referer: http://$IP/webui/Plant:1,IGULD:SELF/configuration/view-parameters' -d '{\"queryItems\":[{\"componentId\":\"IGULD:SELF\"}]}'" # sToken);
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
!WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "") {WriteLine("- No Data received -"); quit;}
! Alle Objekte der Antwort auflisten
var i = 0;
var sText = lGetOut.StrValueByIndex("{\"channelId\":", i);
while (sText <> "")
{
WriteLine(i # " = " # sText);
i = i + 1;
sText = lGetOut.StrValueByIndex("{\"channelId\":", i);
}
Da meine Wallbox automatische Firmware-Updates durchführt, überwache ich zusätzlich die Firmware auf Änderungen und protokolliere das ggf. Reiner Neugier.
Hier das operative Programm
Code: Alles auswählen
! HomeMatic
! Skript zum Auslesen der Parameter einer SMA EV Charger 22 Wallbox.
! Da der Access Token zyklisch beim Lesen der Daten (anderes HM Programm)
! gelesen wird, kann hier der Token aus der Systemvariable gelesen werden.
!
! Die benötigten Parameter werden in die entsprechenden Systemvariablen gespeichert.
!
! 17.02.22 ED: Initial Version
! ----------------------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string lGetOut = "";
string lGetErr = "";
string sCurl = "";
var s = "";
var s1 = "";
var n = "";
var v = "";
var i = 0;
! Access Token aus Systemvariable übernehmen
WriteLine("------------------------------------------------------");
string sToken = dom.GetObject("SMA EV Token").Value();
WriteLine("Access Token= " # sToken)
WriteLine("------------------------------------------------------");
sCurl = ("curl -s -k -X 'POST' "#IP#"/api/v1/parameters/search/ -H 'Content-Type: application/json' -H 'Referer: http://$IP/webui/Plant:1,IGULD:SELF/configuration/view-parameters' -d '{\"queryItems\":[{\"componentId\":\"IGULD:SELF\"}]}'" # sToken);
! WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
!WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetOut == "")
{
s = "Parameter lesen fehlgeschlagen"; WriteLine(s);
!dom.GetObject("SMA EV Meldung").State(s);
quit;
}
! 2. Parameter Parser (Daten extrahieren)
! ---------------------------------------
! Einzelschritte des Parsers, um Prinzip verständlich zu machen
! s = lGetOut.StrValueByIndex("Parameter.Chrg.ActChaMod", 1); WriteLine("s1= "# s);
! s = s.StrValueByIndex("},", 0); WriteLine("s2= "# s);
! s = s.StrValueByIndex("\"value\":", 1); WriteLine("s3= "# s);
! s = s.StrValueByIndex("}]", 0).Substr(7, s.Length()); WriteLine("s4= "# s);
! s = s.Replace("\"", ""); ! Am Schluss Anführungszeichen entfernen
! WriteLine("Parameter.Chrg.ActChaMod= "# s);
! ------------------------------
s = lGetOut.StrValueByIndex("Parameter.Chrg.ActChaMod", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine("Parameter.Chrg.ActChaMod= "# s); !"
dom.GetObject("SMA EV Betriebsart_int").State( s.ToString(0) );
dom.GetObject("SMA EV Betriebsart").State( s.ToInteger()-4718 ); ! Übersetzung in Werteliste
s = lGetOut.StrValueByIndex("Parameter.Chrg.Plan.DurTmm", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine("Parameter.Chrg.Plan.DurTmm= "# s); !"
dom.GetObject("SMA EV Ladevorgang Dauer_int").State(s.ToString(0));
dom.GetObject("SMA EV Ladevorgang Dauer").State(s.ToInteger()/60); ! In Stunden, d.h. Index innerhalb Werteliste umrechnen
s = lGetOut.StrValueByIndex("Parameter.Chrg.Plan.En", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine("Parameter.Chrg.Plan.En= "# s); !"
dom.GetObject("SMA EV Ladevorgang Energiemenge_int").State(s.ToString(1));
! Aktuelle Einstellung von kWh in Index innerhalb Werteliste umrechnen
i = s.ToInteger(); if ((i > 10) && (i <= 50)){i = ((i-10)/5) + 10; } elseif ((i > 50) && (i <= 100)){i = ((i-50)/10) + 18; } elseif ((i < 0) || (i > 100)){i = 0; }
dom.GetObject("SMA EV Ladevorgang Energiemenge").State(i);
s = lGetOut.StrValueByIndex("Parameter.Chrg.Plan.StopTm", 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine("Parameter.Chrg.Plan.StopTm= "# s # " -- " # s.ToInteger().ToTime()); !"
dom.GetObject("SMA EV Ladevorgang Ende_int").State(s.ToString(0));
dom.GetObject("SMA EV Ladevorgang Ende").State(s.ToInteger().ToTime().Format("%d.%m.%Y %H:%M"));
! SW Versionen überprüfen und informieren bei Änderung
n = "Parameter.Nameplate.ChrgCtrl.SwRevTxt";
v = "SMA EV Vers. Ladecontroller"; ! Zugehörige Systemvariable
s = lGetOut.StrValueByIndex(n, 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine(n # "= "# s); !"
if (s <> dom.GetObject( v ).Value())
{
s1 = "SW Version geändert: "# n # " -Alt: " # dom.GetObject( v ).Value() # " -Neu: " # s;
dom.GetObject( v ).State(s);
dom.GetObject( "P:Info" ).State(s1);
dom.GetObject("@HomeNotification").State("Änderung: " # v # " " # system.Date("%H:%M"));
}
n = "Parameter.Nameplate.CmpOS.SwRev"; ! EV Parameter
v = "SMA EV Vers. Betriebssystem"; ! Zugehörige Systemvariable
s = lGetOut.StrValueByIndex(n, 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine(n # "= "# s); !"
if (s <> dom.GetObject( v ).Value())
{
s1 = "SW Version geändert: "# n # " -Alt: " # dom.GetObject( v ).Value() # " -Neu: " # s;
dom.GetObject( v ).State(s);
dom.GetObject( "P:Info" ).State(s1);
dom.GetObject("@HomeNotification").State("Änderung: " # v # " " # system.Date("%H:%M"));
}
n = "Parameter.SwCmp.CmpEnnexOS.Frwk.SwRev"; ! EV Parameter
v = "SMA EV Vers. ennexOS"; ! Zugehörige Systemvariable
s = lGetOut.StrValueByIndex(n, 1); s = s.StrValueByIndex("},", 0).StrValueByIndex("\"value\":", 1).StrValueByIndex("}]", 0).Substr(7, s.Length()); s=s.Replace("\"", ""); WriteLine(n # "= "# s); !"
if (s <> dom.GetObject( v ).Value())
{
s1 = "SW Version geändert: "# n # " -Alt: " # dom.GetObject( v ).Value() # " -Neu: " # s;
dom.GetObject( v ).State(s);
dom.GetObject( "P:Info" ).State(s1);
dom.GetObject("@HomeNotification").State("Änderung: " # v # " " # system.Date("%H:%M"));
}
s = "Parameter lesen erfolgreich"; WriteLine(s);
WriteLine("- fertig -");
Als nächstes geht es an das Verändern von Parametern. Ich möchte manuell und automatisch die Betriebsart der Wallbox umstellen und den Ladevorgang steuern können.
Dafür sind lediglich drei Parameter der Wallbox relevant,
1. die gewünscht Energiemenge (Parameter.Chrg.Plan.En)
2. das gewünschte Ende des Ladevorgangs (Parameter.Chrg.Plan.StopTm)
3. der Betriebsmodus der Wallbox (Parameter.Chrg.ActChaMod)
Sendet man die ersten zwei Parameter an die Wallbox, ändert diese selbständig den Betriebsmodus auf "Laden mit Vorgabe" und beginnt bzw. plant den Ladevorgang entsprechend ein.
Für die Vorgabe verwende ich zwei Systemvariablen vom Typ Werteliste
- SMA EV Ladevorgang Energiemenge Werteliste -Auswählen-;1 kWh;2 kWh;3 kWh;4 kWh;5 kWh;6 kWh;…
SMA EV Ladevorgang Dauer Werteliste -Auswählen-;1 Std.;2 Std.;3 Std.;4 Std.;5 Std.;6 Std.;7 Std.;…
Hier das operative Programm
Code: Alles auswählen
! HomeMatic
! Skript zum Setzen folgender Parameter einer SMA EV Charger 22 Wallbox
! 1. Energiemenge (Systemvariable: SMA EV Ladevorgang Energiemenge)
! 2. Zielzeit (Systemvariable: SMA EV Ladevorgang Ende + aktuelles Datem und Uhrzeit)
!
! 20.02.22 ED: Initial Version
! 16.03.22 ED: Aufruf mit Zeitstempel und Länge
! ----------------------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string lGetOut = "";
string lGetErr = "";
string sCurl = "";
var s = "";
var i = 0;
! Access Token aus Systemvariable übernehmen
WriteLine("------------------------------------------------------");
string sToken = dom.GetObject("SMA EV Token").Value();
WriteLine("Access Token= " # sToken)
WriteLine("------------------------------------------------------");
WriteLine("- 1. Parameter an Wallbox senden -");
var iPlanEn = 0; ! kWh
var iPlanDurTmm = 0; ! Min
var iPlanStopTm = 0; ! Zeit
! Aktueller Zeitstempel in GMT
var GMT=((currenttime.Format("%z").ToInteger())/-100)*60*60; ! Korrekturwert in Sekunden für Umrechnung in GMT
var sTimestamp = (currenttime+GMT).Format("%Y-%m-%dT%H:%M:%S.000Z"); ! Formatierte Ausgabe
WriteLine("Timestamp: "#sTimestamp);
!JSON Datenstring-Template mit Platzhalter xxx=Ladedauer; yyy=Energiemenge; ttt=Zeitstempel
string sData = "{\"values\":[";
sData = sData # "{\"channelId\":\"Parameter.Chrg.Plan.DurTmm\",\"timestamp\":\"ttt\",\"value\":xxx},";
sData = sData # "{\"channelId\":\"Parameter.Chrg.Plan.En\",\"timestamp\":\"ttt\",\"value\":yyy}";
sData = sData # "]}";
iPlanEn = dom.GetObject("SMA EV Ladevorgang Energiemenge").Value(); ! Index aus Werteliste Energiemenge
WriteLine("-Energiemenge = " # iPlanEn # " kWh");
i = dom.GetObject("SMA EV Ladevorgang Dauer").Value(); ! Index aus Werteliste (Stunden)
iPlanStopTm = currenttime.ToInteger() + (i.ToInteger()*60*60); ! Aktuelle Zeit + Index in Minuten
WriteLine("Index: "#i# " -Zielzeit = " # iPlanStopTm # " >> " # iPlanStopTm.ToTime().Format("%d.%m.%Y %H:%M"));
! Platzhalter durch Daten ersetzen
sData = sData.Replace("xxx",i.ToString(0));
sData = sData.Replace("yyy",iPlanEn.ToString(0));
sData = sData.Replace("ttt",sTimestamp);
! Länge des Datenpakets bestimmen
var iDataLen = sData.Length();
WriteLine("Data = " # sData # " Länge = " # iDataLen);
! Vollständigen String für curl Aufruf zusammenstellen
sCurl = "curl -s -k -X 'PUT' "#IP#"/api/v1/parameters/IGULD:SELF ";
sCurl = sCurl # "-H 'Content-Type: application/json' ";
sCurl = sCurl # "-H 'Referer: "#IP#"/webui/Plant:1,IGULD:SELF/configuration/view-parameters' ";
sCurl = sCurl # "-H 'Content-Length: " # iDataLen.ToInteger() # "' ";
sCurl = sCurl # "-d '" # sData # "' " # sToken;
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetErr <> "")
{
s = "Parameter schreiben fehlgeschlagen"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
else
{
s = "Laden mit Zeit- und Energievorgabe"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
WriteLine("- fertig -");
- Sofortiges Laden (Energiemenge 20kWh, Dauer 1 Std)
Code: Alles auswählen
! HomeMatic
! Skript setzt Parameter einer SMA EV Charger 22 Wallbox so, dass sie umgehend mit
! dem Laden beginnt
! 1. Energiemenge (Systemvariable: SMA EV Ladevorgang Energiemenge)
! 2. Zielzeit (Systemvariable: SMA EV Ladevorgang Ende + aktuelles Datem und Uhrzeit)
!
! 25.02.22 ED: Initial Version
! 16.03.22 ED: Aufruf mit Zeitstempel und Länge
! ----------------------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string lGetOut = "";
string lGetErr = "";
string sCurl = "";
var s = "";
var i = 0;
! Access Token aus Systemvariable übernehmen
WriteLine("------------------------------------------------------");
string sToken = dom.GetObject("SMA EV Token").Value();
WriteLine("Access Token= " # sToken)
WriteLine("------------------------------------------------------");
WriteLine("- 1. Parameter an Wallbox senden -");
var iPlanEn = 20; ! kWh
var iPlanDurTmm = 60; ! Min
var iPlanStopTm = 0; ! Zeit
! Aktueller Zeitstempel in GMT
var GMT=((currenttime.Format("%z").ToInteger())/-100)*60*60; ! Korrekturwert in Sekunden für Umrechnung in GMT
var sTimestamp = (currenttime+GMT).Format("%Y-%m-%dT%H:%M:%S.000Z"); ! Formatierte Ausgabe
WriteLine("Timestamp: "#sTimestamp);
!JSON Datenstring-Template mit Platzhalter xxx=Ladedauer; yyy=Energiemenge; ttt=Zeitstempel
string sData = "{\"values\":[";
sData = sData # "{\"channelId\":\"Parameter.Chrg.Plan.DurTmm\",\"timestamp\":\"ttt\",\"value\":xxx},";
sData = sData # "{\"channelId\":\"Parameter.Chrg.Plan.En\",\"timestamp\":\"ttt\",\"value\":yyy}";
sData = sData # "]}";
WriteLine("-Energiemenge = " # iPlanEn # " kWh");
iPlanStopTm = currenttime.ToInteger() + (iPlanDurTmm.ToInteger()*60); ! Aktuelle Zeit + Zeitvorgabe
WriteLine("Dauer: "#iPlanDurTmm# " -Zielzeit = " # iPlanStopTm # " >> " # iPlanStopTm.ToTime().Format("%d.%m.%Y %H:%M"));
! Platzhalter im Template durch Daten ersetzen
sData = sData.Replace("xxx",iPlanDurTmm.ToString(0));
sData = sData.Replace("yyy",iPlanEn.ToString(0));
sData = sData.Replace("ttt",sTimestamp);
! Länge des Datenpakets bestimmen
var iDataLen = sData.Length();
WriteLine("Data = " # sData # " Länge = " # iDataLen);
! Vollständigen String für curl Aufruf zusammenstellen
sCurl = "curl -s -k -X 'PUT' "#IP#"/api/v1/parameters/IGULD:SELF ";
sCurl = sCurl # "-H 'Content-Type: application/json' ";
sCurl = sCurl # "-H 'Referer: "#IP#"/webui/Plant:1,IGULD:SELF/configuration/view-parameters' ";
sCurl = sCurl # "-H 'Content-Length: " # iDataLen.ToInteger() # "' ";
sCurl = sCurl # "-d '" # sData # "' " # sToken;
WriteLine ("sCurl = " # sCurl);
system.Exec( sCurl, &lGetOut,&lGetErr);
WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetErr <> "")
{
s = "Parameter schreiben fehlgeschlagen"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
else
{
s = "Sofortiges Laden aktiviert"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
WriteLine("- fertig -");
Code: Alles auswählen
! HomeMatic
! Skript zum Setzen folgender Parameter einer SMA EV Charger 22 Wallbox
! 1. Betriebsart Ladevorgang auf 4719 (Optimiertes Laden)
!
! 20.02.22 ED: Initial Version
! ----------------------------------------------------------------------------------
string IP = dom.GetObject("SMA EV Access IP").Value();
string lGetOut = "";
string lGetErr = "";
string sCurl = "";
var s = "";
var i = 0;
! Access Token aus Systemvariable übernehmen
WriteLine("------------------------------------------------------");
string sToken = dom.GetObject("SMA EV Token").Value();
WriteLine("Access Token= " # sToken)
WriteLine("------------------------------------------------------");
WriteLine("- 1. Parameter an Wallbox senden -");
!JSON Datenstring mit Platzhalter xxx=Energiemenge; yyy=Zielzeit
sData = " -d '{\"values\":[{\"channelId\":\"Parameter.Chrg.ActChaMod\",\"value\":\"4719\"}]}' ";
! Vollständigen String für curl Aufruf zusammenstellen
sCurl = ("curl -s -k -X 'PUT' "#IP#"/api/v1/parameters/IGULD:SELF -H 'Content-Type: application/json' -H 'Referer: "#IP#"/webui/Plant:1,IGULD:SELF/configuration/view-parameters' "# sData # sToken );
system.Exec( sCurl, &lGetOut,&lGetErr);
WriteLine("Out = " # lGetOut); WriteLine("Err = " # lGetErr);
if (lGetErr <> "")
{
s = "Parameter schreiben fehlgeschlagen"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
else
{
s = "Optimiertes Laden aktiviert"; WriteLine(s);
dom.GetObject("SMA EV Meldung").State(s);
}
WriteLine("- fertig -");
Die Wallbox ist auf zu schnell aufeinander folgende Änderungen empfindlich. Ich hatte beim Testen Situationen, bei denen die Wallbox nicht mehr geladen und erst nach aus- und wieder Einstecken am Fahrzeug wieder normal funktioniert hat. Entsprechend braucht es beim Timing der Programme noch Optimierungen.
Ausblick
Als nächstes möchte ich nun noch den Ladezustand der Fahrzeugbatterie erfassen und dann in Automatisierungsaufgaben verwenden, z.B. "Fahrzeug ist morgens um 7:00 immer für mindestens 40km geladen".
Das Fahrzeug ist ein Mercedes. Ob ich die Daten gelesen bekommen und wie das ggf. funktioniert, werde ich in einem separaten Projekt berichten.