NEWS
[Skript] Json mit Messdaten mittels SolarEdge-API abholen und Werte einzeln verarbeiten
-
Hallo zusammen,
ich möchte gerne Messdaten von der SolarEdge Webseite abholen und die Werte einzeln verarbeiten.
Das Abholen und Zwischenspeichern der Werte funktioniert soweit. Allerdings
stehe ich beim Abarbeiten der Werte wie der Ochs vor dem Berg, ich bekomme es nicht hin mich durch das Json-Objekt zu arbeiten...Hier das Skript mit dem ich die Daten abhole, Zwischenspeicher und abarbeiten möchte:
var gelesen='javascript.'+instance+'.SolarEdgeApi.ergebnisJson'; var url='https://monitoringapi.solaredge.com/site/528008/energyDetails.json?meters=PRODUCTION&timeUnit=MONTH&startTime=2019-01-01%2011:00:00&endTime=2019-04-28%2013:00:00&api_key=XXXXXXXXXXXXXXXXXXXXX'; createState(gelesen, { name: 'json_gelesen', type: 'string', write: true }); //lesen der Daten readJson(url, function(err,json) { if(!err) { setState(gelesen,json); log("ergebnis: "+json); } else { log("Fehler beim Auslesen des JSON. Keine Daten erhalten.","warn"); } }); // abarbeiten var result=getState(gelesen).val; log("starte:"); var result2=JSON.parse(result); for (i in result2.meters) { for (j in result2.meters[i].type) { log(result2.energyDetails.meters[i].type[j]); } } function readJson(url, callback) { request(url, function (err, state, body){ if (body) { var json = body; callback(null, json); } else { var error = "(" + err + ") ERROR bei Abfrage von: " + url; log(error, "warn"); callback(error, null); } }); }
Hier das Json Objekt:
{"energyDetails":{"timeUnit":"MONTH","unit":"Wh","meters":[{"type":"Consumption","values":[{"date":"2019-01-01 00:00:00","value":1272259.0},{"date":"2019-02-01 00:00:00","value":1143047.0},{"date":"2019-03-01 00:00:00","value":1173865.0},{"date":"2019-04-01 00:00:00","value":939571.0}]},{"type":"Purchased","values":[{"date":"2019-01-01 00:00:00","value":1135762.0},{"date":"2019-02-01 00:00:00","value":807658.0},{"date":"2019-03-01 00:00:00","value":792998.0},{"date":"2019-04-01 00:00:00","value":315214.0}]},{"type":"FeedIn","values":[{"date":"2019-01-01 00:00:00","value":5787.0},{"date":"2019-02-01 00:00:00","value":86750.0},{"date":"2019-03-01 00:00:00","value":140233.0},{"date":"2019-04-01 00:00:00","value":314715.0}]},{"type":"Production","values":[{"date":"2019-01-01 00:00:00","value":141309.0},{"date":"2019-02-01 00:00:00","value":419721.0},{"date":"2019-03-01 00:00:00","value":516164.0},{"date":"2019-04-01 00:00:00","value":893966.0}]},{"type":"SelfConsumption","values":[{"date":"2019-01-01 00:00:00","value":141309.0},{"date":"2019-02-01 00:00:00","value":419721.0},{"date":"2019-03-01 00:00:00","value":516164.0},{"date":"2019-04-01 00:00:00","value":929686.0}]}]}}
In "abarbeiten" wollte ich mir zunächst die verschiedenen Typen anzeigen lassen (also Production, Feed in etc...) und dann für jeden Typ die Wertepaare einzeln abarbeiten (z.B. in DB oder IO Broker Objekt schreiben)
- und daran scheitert es momentan Kann mir jemand erklären, wie ich die Schleife aufbauen muss um die Wertepaare einzeln durchzugehen ???
-
@ehome Ich stehe vor dem gleichen Problem- hast Du Dein Skript zum laufen bekommen und kannst mir helfen?
Leider habe ich von Java recht wenig Plan und würde mich über ein fertiges Skript freuen.
LG, Tim
-
ich hole mir zur Zeit nur die Gesamtproduktionsdaten ab.
Du musst das Skript aber anpassen, da ich für meine Werte eine
eigene Objekstruktur baue. (Versorgung.0.....)// // Abholen der livetime Daten Produktion via API // const PATH = 'Versorgung.0.SolarEdgeAPI.'; let ID_PROD=PATH+'ProduktionLifetime'; let ID_DELTA=PATH+'ProduktionDelta2Modbus'; let ID_MODBUSDATA='modbus.0.holdingRegisters.1.40094_I_AC_Energy_WH' let ID_CONVERTERSTATUS='modbus.0.holdingRegisters.1.40107_I_Status'/*Operation State*/ let api_key=getState(PATH+'apiKey').val; let logging=false; // erstellen des Objekts, wenn noch nicht vorhanden mk_prodlifetime(ID_PROD); mk_delta2modbus(ID_DELTA); // abholen der Daten nur, wenn PV produziert um Anzahl der API calls zu begrenzen // 4=prod getOverviewSolaredge(api_key); schedule('*/10 * * * *', function () { var statusPV=Number(getState(ID_CONVERTERSTATUS).val); tolog(logging,"StatusPV: "+statusPV); if (statusPV == 4) { tolog(logging,"Aktualisiere PV LifetimeProd"); getOverviewSolaredge(api_key); } }); function getOverviewSolaredge(akey){ var url = 'https://monitoringapi.solaredge.com/site/528008/overview.json?api_key='+akey; tolog(logging,"GET DATA FROM: "+url); var answer; request(url, function (err, state, body){ if (body) { tolog(logging,'Request - alles ok'); var obTyp=typeof(body); tolog(logging,"Reques return type:"+obTyp); tolog(logging,"response: "+state); if (testJSON(body) === true) { body=JSON.parse(body); var lifetimeProd=body.overview.lifeTimeData.energy/1000; setState(ID_PROD,lifetimeProd,true); tolog(logging,"get lifetime prod:"+lifetimeProd); } } else { log('Request meldet Fehler: ' + err, 'error'); } }); } function testJSON(text){ if (typeof text!=="string"){ return false; } try{ JSON.parse(text); return true; } catch (error){ return false; } } function mk_prodlifetime (path){ var obj = {}; obj.type = 'state'; obj.common = {}; obj.common.name = 'Lifetime production'; obj.common.type = 'number'; obj.common.role = 'value'; obj.common.unit = 'kWh' ; obj.common.read = true; obj.common.write = false; setzeObject(path, obj); } function tolog (logging,logText,logFileName='std') { if (logging===true ) { if (logFileName != 'std') { let ts = new Date() let millisec=ts.getMilliseconds() let datum = formatDate(ts, "YYYY-MM-DD hh:mm:ss.") + millisec + " \t"; let fn = "/opt/iobroker/log/"+logFileName; fs.appendFileSync(fn, datum + logText + "\n"); } else { log(logText) } } }
Die Funktion tolog ist bei mir eine globale Funktion, der Einfachheit halber habe ich sie mal einfach mit in das Skript hier gepackt.
Ich hoffe das hilft.
Gruß
Olli -
@ehome Wow, vielen Dank. Ich bastele mal.
Mich interessieren die Forecast Werte von Solcast und passe mir das Skript an.Mit der Basis wird es bestimmt klappen.
LG, Tim
-
@ehome sagte in [Skript] Json mit Messdaten mittels SolarEdge-API abholen und Werte einzeln verarbeiten:
request(url, function (err, state, body){
Hallo Olli,
ich bin in Java blutiger Anfänger und habe eine paar Fragen und möchte mir über die API die Batteriedaten holen.
Kann ich die URL als String aufbauen und wenn ja, wie?
Und wie kann ich per Skript den Zeitraum anpassen. Irgendwie ist das zu hoch für mich.So sieht der link dahin aus:
https://monitoringapi.solaredge.com/site/XXXXXXX/storageData.json?startTime=2020-11-15 07:40:00&endTime=2020-11-15 11:40:00&api_key=Ich habe mal was gebastelt.
// // Abholen der livetime Daten Batterie via API // const PATH = 'Versorgung.0.SolarEdgeAPI.'; let ID_battpow=PATH+'0_userdata.0.Eigene_Variablen.PV-Anlage.Batterie_Power'; let ID_battproz=PATH+'0_userdata.0.Eigene_Variablen.PV-Anlage.Batterie_Porzent'; let ID_battstat=PATH+'0_userdata.0.Eigene_Variablen.PV-Anlage.Batterie_Status'; let ID_CONVERTERSTATUS='modbus.0.holdingRegisters.40108_I_Status'/*Operation State*/ let api_key=getState(PATH+'apiKey').val; // abholen der Daten nur, wenn PV produziert um Anzahl der API calls zu begrenzen // 4=prod getOverviewSolaredge(api_key); schedule('*/10 * * * *', function () { var statusPV=Number(getState(ID_CONVERTERSTATUS).val); if (statusPV == 4) { getOverviewSolaredge(api_key); } }); function getOverviewSolaredge(akey){ var url = 'https://monitoringapi.solaredge.com/site/xxxxxxx/storageData.json?startTime='+Tag'%'+Jahr''+ Uhrzeit1'&endTime='+Tag'%'+Jahr''+ Uhrzeit2'&api_key='+akey; var answer; request(url, function (err, state, body){ body=JSON.parse(body); var batteriepower=body.storageData.batteries.telemetries.power; setState(ID_battpow,batteriepower,true); var batterieprozent=body.storageData.batteries.telemetries.batteryPercentageState; setState(ID_battproz,batterieprozent,true); var batteriestatus=body.storageData.batteries.telemetries.batteryState; setState(ID_battstat,batteriestatus,true); } }
Das kommt als Antwort wenn ich die Daten über den Browser anfrage:
{"storageData":{"batteryCount":1,"batteries":[{"nameplate":8000.0,"serialNumber":"XXXXX","modelNumber":"BYD Premium LVS 8.0","telemetryCount":48,"telemetries":[{"timeStamp":"2020-11-15 07:42:00","power":0.0,"batteryState":10,"lifeTimeEnergyDischarged":6842,"lifeTimeEnergyCharged":5859,"batteryPercentageState":10.0,"fullPackEnergyAvailable":8000.0,"internalTemp":19.0,"ACGridCharging":0.0},{"timeStamp":"2020-11-15 07:47:00","power":0.0,"batteryState":10,"lifeTimeEnergyDischarged":6842,"lifeTimeEnergyCharged":5859,"batteryPercentageState":10.0,"fullPackEnergyAvailable":8000.0,"internalTemp":19.0,"ACGridCharging":0.0},{"timeStamp":"2020-11-15
Ich bin für jede Hilfe dankbar.
Gruß
Daniel -
Hallo Daniel,
ich hole momentan nur den Gesamtwert und vergleiche ihn mit den Werten die ich aus dem Modus bekomme.
Aus der Anlage bekomme ich nur die Batteriewerte un den Status der Anlage sauber ausgelesen - sonst nur (für mich) unverständliche Werte.
Um irgendwie weiter zu kommen lese ich die vermeintliche Gesamtproduktion per Modus aus und bilde die Differenz zu dem Wert aus dem
Webinterface von Solar-Edge - hat mich aber auch nicht nicht weiter gebracht.
Da ich eine eigene Objektstruktur verwende und einige globale Funktionen benutze, habe ich versucht alles in ein Skript zusammen zu kopieren.
(Achtung bin auch eher Anfänger bezüglich JS) Da ich das Skript nicht testen kann ist es durchaus möglich, dass du noch etwas
"frickeln" musst. Aber es sollte dir eine Idee davon geben, wie du die Werte auslesen kannst.// // Abholen der livetime Daten Produktion via API // const akey='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; const PATH='Versorgung.0.SolarEdgeAPI.apiKey'; // erstellen des Objekte, wenn noch nicht vorhanden mk_prodlifetime(ID_PROD); mk_delta2modbus(ID_DELTA); mk_apikey(PATH); setState(PATH,akey,true); let ID_PROD=PATH+'ProduktionLifetime'; let ID_DELTA=PATH+'ProduktionDelta2Modbus'; let ID_MODBUSDATA='modbus.0.holdingRegisters.1.40094_I_AC_Energy_WH' let ID_CONVERTERSTATUS='modbus.0.holdingRegisters.1.40107_I_Status'/*Operation State*/ let api_key=getState(PATH+'apiKey').val; let logging=false; // abholen der Daten nur, wenn PV produziert um Anzahl der API calls zu begrenzen // 4=prod getOverviewSolaredge(api_key); schedule('*/10 * * * *', function () { var statusPV=Number(getState(ID_CONVERTERSTATUS).val); tolog(logging,"StatusPV: "+statusPV); if (statusPV == 4) { tolog(logging,"Aktualisiere PV LifetimeProd"); getOverviewSolaredge(api_key); } }); on({id:ID_PROD,change:'ne'}, function (obj) { setState(ID_DELTA,obj.state.val-(getState(ID_MODBUSDATA).val/1000)); }); function getOverviewSolaredge(akey){ var url = 'https://monitoringapi.solaredge.com/site/528008/overview.json?api_key='+akey; tolog(logging,"GET DATA FROM: "+url); var answer; request(url, function (err, state, body){ if (body) { tolog(logging,'Request - alles ok'); var obTyp=typeof(body); tolog(logging,"Reques return type:"+obTyp); tolog(logging,"response: "+state); if (testJSON(body) === true) { body=JSON.parse(body); var lifetimeProd=body.overview.lifeTimeData.energy/1000; setState(ID_PROD,lifetimeProd,true); tolog(logging,"get lifetime prod:"+lifetimeProd); } } else { log('Request meldet Fehler: ' + err, 'error'); } }); } function testJSON(text){ if (typeof text!=="string"){ return false; } try{ JSON.parse(text); return true; } catch (error){ return false; } } function mk_delta2modbus (path){ var obj = {}; obj.type = 'state'; obj.common = {}; obj.common.name = 'prodDelta2modbus'; obj.common.type = 'number'; obj.common.role = 'value'; obj.common.unit = 'kWh' ; obj.common.read = true; obj.common.write = false; setzeObject(path, obj); } function mk_prodlifetime (path){ var obj = {}; obj.type = 'state'; obj.common = {}; obj.common.name = 'Lifetime production'; obj.common.type = 'number'; obj.common.role = 'value'; obj.common.unit = 'kWh' ; obj.common.read = true; obj.common.write = false; setzeObject(path, obj); } function mk_apikey (id){ var obj = {}; obj.type = 'state'; obj.common = {}; obj.common.name = 'API api_key'; obj.common.role = 'value'; obj.common.read = true; obj.common.write = true; setzeObject(id, obj); } function setzeObject(id, obj) { log("ID: "+id); //if(getObject(path + idDev + '.status')) return; if (getObject(id)) { log("Objekt: "+id+" existiert lege es nicht erneut an"); } else { log("Objekt: "+id+" existiert nicht, lege es an"); setObject(id, obj, function(err) { if(err) log('Cannot write object: ' + err); else setState(id, obj.common.def); }); } } function tolog(logging,val) { if (logging===true) { log(val); } }
Gruß
Olli -
@ehome hallo Olli,
Wie kommst du an die Batteriewerte? Das ist das einzige was mir fehlt. Dann kann ich die Reste ausrechnen.
Grüße Daniel
-
Hat sich erledigt. Ich hole mir die Batteriedaten nun alle 5 Minuter ab. Ging dann mit blockly
-
Hi, bei mir habe ich folgendes eingetragen: