NEWS
IOBroker Anbindung an einen Kostal Plenticore
-
Würde empfehlen, das dann nur einmal am Tag zwischen 6 und 8 auszuführen, bis ich das Problem gelöst habe.
-
@gjo said in IOBroker Anbindung an einen Kostal Plenticore:
@homeuser
Genau sowas habe ich mir vorgestellt. Wenn du das teilen könntest …
Vielen Dank
GrußDisclaimer und Erklärung:
Ich bin kein Javascript-Entwickler. Vielleicht sind manche Dinge daher sehr unschön gelöst. Außerdem ist es geschrieben nach dem Motto: Hauptsache es klappt.
UpdateJson(): Der erste Teil der Schleife erstellt ein Json aus den Forecast-Daten. Der zweite konsolidiert das etwas, um eine leicht verständliche Ansicht für den Rest der Familie zu haben.
UpdateFreeEnergy(): Berechnet wie viel Strom im Moment gerade übrig ist. Der "Moment" sind die letzten 10 Minuten, wobei die letzten drei doppelt gewichtet werden.Ich habe mal alles drin gelassen, falls es nützlich ist. Wenn nicht, ist es ja einfach zu löschen
schedule ("*/1 * * * *", UpdatePlenticore) function UpdatePlenticore() { // free energy must be updated first because it is used by UpdateJson() UpdateFreeEnergy(); UpdateJson(); } function UpdateJson() { let data = []; let consolidatedData = []; let time2; let power; let generated; let c = 0; // used to group always 3 hours in one let timeNow = new Date(Date.now()); let consolidatedPower = 0; let consolidatedStars = 0; let consolidatedTimeEnd = timeNow.getHours(); // default: if no full period is consolidated, start with now // set value for now (based on the calculated currently free energy) let freeEnergy = getState('0_userdata.0.Plenticore.FreeEnergy').val; consolidatedData.push({'time' : 'jetzt','power' : Math.round(freeEnergy) + " Wh", 'stars' : ((freeEnergy-200)/500)}); // Day 1 data.length = 0; for (let i = 1; i <= 20; i++) { let forecastHour = "plenticore.0.forecast.day1.power." + i + "h" // Day 1 if (existsState(forecastHour + '.time')) { let time = new Date(getState(forecastHour + '.time').val); // convert hourly forecast to JSON time2 = time.toLocaleTimeString(); power = getState(forecastHour + '.power').val; if (existsState(forecastHour + '.generated')) { generated = getState(forecastHour + '.generated').val; } else { generated = 0; } data.push({'time' : time2,'power' : Math.round(power), 'generated' : Math.round(generated)}); // consolidate to timespan and quality (JSON) // // check if the period is in the future (don't show forecast for past hours) if (time.getHours() > timeNow.getHours()) { consolidatedPower += power; if ( (c % 3) == 2) { consolidatedTimeEnd = time.getHours(); time2 = (time.getHours()-2) + " - " + consolidatedTimeEnd + " Uhr"; consolidatedStars = Math.round(consolidatedPower / 2000); // translate power in stars consolidatedData.push({'time' : time2,'power' : Math.round(consolidatedPower) + " Wh", 'stars' : consolidatedStars}); consolidatedPower = 0; // rest fo next timespan } c++; } } } // check if there a partially consolidated period pending if ( (c % 3) == 1) { time2 = (consolidatedTimeEnd + 1) + " Uhr"; consolidatedStars = Math.round(consolidatedPower / (2000/3)); // translate power in stars; use number of remaining items as factor consolidatedData.push({'time' : time2,'power' : Math.round(consolidatedPower) + " Wh", 'stars' : consolidatedStars}); } else if ( (c % 3) == 2) { time2 = (consolidatedTimeEnd + 1) + " - " + (consolidatedTimeEnd + 2) + " Uhr"; consolidatedStars = Math.round(consolidatedPower / ((2000*2)/3)); // translate power in stars; use number of remaining items as factor consolidatedData.push({'time' : time2,'power' : Math.round(consolidatedPower) + " Wh", 'stars' : consolidatedStars}); } setState('0_userdata.0.Plenticore.ForecastDay1', JSON.stringify(data), true); setState('0_userdata.0.Plenticore.ConsolidatedDay1', JSON.stringify(consolidatedData), true); // Day 2 c = 0; // used to group always 3 hours in one consolidatedPower = 0; consolidatedStars = 0; consolidatedTimeEnd = 0; data.length = 0; consolidatedData.length = 0; for (let i = 1; i <= 20; i++) { let forecastHour = "plenticore.0.forecast.day2.power." + i + "h" // Day 1 if (existsState(forecastHour + '.time')) { let time = new Date(getState(forecastHour + '.time').val); // convert hourly forecast to JSON time2 = time.toLocaleTimeString(); power = getState(forecastHour + '.power').val; data.push({'time' : time2,'power' : Math.round(power)}) // consolidate to timespan and quality (JSON) consolidatedPower += power; if ( (c % 3) == 2) { consolidatedTimeEnd = time.getHours(); time2 = (time.getHours()-2) + " - " + consolidatedTimeEnd + " Uhr"; consolidatedStars = Math.round(consolidatedPower / 2000); // translate power in stars consolidatedData.push({'time' : time2,'power' : Math.round(consolidatedPower) + " Wh", 'stars' : consolidatedStars}); consolidatedPower = 0; // rest fo next timespan } c++; } } if ( (c % 3) != 0) { // not all hours are pushed to the consolidation time2 = (consolidatedTimeEnd + 1) + " - " + (consolidatedTimeEnd + 1 + (c % 3) ) + " Uhr"; consolidatedStars = Math.round(consolidatedPower / 2000); // translate power in stars consolidatedData.push({'time' : time2,'power' : Math.round(consolidatedPower) + " Wh", 'stars' : consolidatedStars}); consolidatedPower = 0; // rest fo next timespan } setState('0_userdata.0.Plenticore.ForecastDay2', JSON.stringify(data), true); setState('0_userdata.0.Plenticore.ConsolidatedDay2', JSON.stringify(consolidatedData), true); } // Save free watt of past N minutes; calc average function UpdateFreeEnergy() { let freeEnergy = 0; let batterySoc = 0; const pastMinutes = 10; // with forst call, create the array are set values to 0 if ( typeof UpdateFreeEnergy.pastValues == 'undefined' ) { UpdateFreeEnergy.pastIndex = 0; UpdateFreeEnergy.pastValues= []; for (let i = 0; i < pastMinutes; i++) { UpdateFreeEnergy.pastValues[i] = 0; } } // calculate the current free value freeEnergy = getState('plenticore.0.devices.local.Pv_P').val; freeEnergy -= getState('plenticore.0.devices.local.Home_P').val; if (freeEnergy < 0) { freeEnergy = 0; } // put into array UpdateFreeEnergy.pastValues[UpdateFreeEnergy.pastIndex] = freeEnergy; // calc average of past values for (let i = 0; i < pastMinutes; i++) { //for the 3 most current values double the impact if ( (i == UpdateFreeEnergy.pastIndex) || (i == (UpdateFreeEnergy.pastIndex + pastMinutes - 1) % pastMinutes) || (i == (UpdateFreeEnergy.pastIndex + pastMinutes - 2) % pastMinutes) ){ freeEnergy = freeEnergy + 2 * UpdateFreeEnergy.pastValues[i]; } else { freeEnergy = freeEnergy + UpdateFreeEnergy.pastValues[i]; } } freeEnergy = freeEnergy / (pastMinutes + 3); // +3 for the doubled impact of the the 3 most current values // if the battery is below the defined minimum, the battery has priority; so there is no free energy // recommendation: // Use same value as in the settings of the plenticore adapter for "minimaler SoC zur Aktivierung des Batteriemanagements". // The plenticore adapter stops charging a little before the limit. So the value should be 2-3% lower. batterySoc = getState('plenticore.0.devices.local.battery.SoC').val; if (batterySoc <= 12) { freeEnergy = 0; } // save calculated average setState('0_userdata.0.Plenticore.FreeEnergy', freeEnergy, true); // inc counter for cyclic buffer UpdateFreeEnergy.pastIndex = (UpdateFreeEnergy.pastIndex + 1) % pastMinutes; }
-
@strathcole So, ich habe jetzt im git eine neue Version (nur dort), bei der ich die Vorhersage für den aktuellen Tag nur noch bis Sonnenaufgang aktualisiere.
-
@StrathCole: Ich bekomme immer folgenden Warning im iobroker Protokoll angezeigt:
plenticore.0
2021-11-30 16:12:16.165 warn Failed starting plenticore adapter (login sequence failed). Trying again in 30 seconds.
plenticore.0
2021-11-30 16:12:16.164 warn Login failed with code 0:
plenticore.0
2021-11-30 16:12:16.163 warn API request failed with error {"errno":"ECONNREFUSED","code":"ECONNREFUSED","syscall":"connect","address":"192.168.178.20","port":80}Was mache ich falsch? Falsch PW?
Freundlichen Gruß
HME -
@hme Hi, der Fehler bedeutet, dass auf der IP Adresse kein Port 80 verfügbar ist. Entweder ist es die falsche IP oder eine Firewall blockt Port 80 oder der WR lauscht nicht auf Port 80.
-
@strathcole many thx. Tatsächlich hab ich bei der Portfreigabe realisieren müssen, dass zwei Geräte die selbe IP nutzen...
Nice support.
-
@StrathCole
Hatte heute mal wieder den Fall dass etwas mit der Regenvorhersage nicht passte, was ja mal passieren kann. Aber der Adapter haut dann mehrfach eine nicht unerhebliche Menge an "Müll" in das Log:2021-12-04 05:28:23.512 - [33mwarn[39m: plenticore.0 (1269342) Processing cloud data failed: <div id="temp_graph"></div> <p class="graph-headline-compact">Mittelwind</p> <div id="wind_graph"></div> <div id="sun_graph"></div> <div id="clouds_graph"></div> <p class="graph-headline-compact">Niederschlag 3h + Summe (mm/Liter pro m²) + Niederschlagswahrscheinlichkeit <span style="color:#005288;margin-left: 20px;">●</span> Regen<span style="color:#7dbbea;margin-left: 10px;">●</span> Schnee</p> <div id="rain_graph"></div> <div id="rainsum_graph"></div> <div id="rainpop_graph"></div> <div id="humidity_graph"></div> <p class="graph-headline-compact">Luftdruck</p> <div id="pressure_graph"></div> <div id="visibility_graph"></div> <script type="text/javascript"> var hccompact_tempmax = -100; ]; var hccompact_sunsum=[ ]; var hccompact_rainsum=[ ]; var hclanding_sunrise = 8; var hclanding_sunset = 7; </script> 2021-12-04 05:28:23.528 - [33mwarn[39m: plenticore.0 (1269342) Could not process weather data.
Dieser Block hat sich 10 mal wiederholt.
-
"So, ich habe jetzt im git eine neue Version (nur dort), bei der ich die Vorhersage für den aktuellen Tag nur noch bis Sonnenaufgang aktualisiere."
@strathcole Jetzt muss ich ganz naiv fragen, wie ich das von dort installiere!? Aktuell habe ich keine Buildumgebung o.ä. auf meinem Rechner.
-
-
Nabend,
ich würde gerne die Ströme und Leistungen der einzelnen Phasen sehen.
Leider wird mir bei den entsprechenden Werten L1_I, L1_P, L2_I,.... nur eine Null angezeigt.
Die jeweiligen Spannungen L1_U,... kann ich jedoch sehen
Wo ist der Trick? -
@hme L1-3_I und _P sind bei mir auch alle 0. Anscheinend liefert der WR das nicht. Hab den EM300 derzeit nicht im Netzwerk. Vllt liefert dieser die gewünschten Werte.
-
@diginix Mein KSEM (KOSTAL Smart Energy Meter) ist im Netz und da kann ich die Werte auch schön live verfolgen. Leider hab ich dort aber nicht die Möglichkeit die Werte über einen längeren Zeitraum zu tracken o.ä..
-
@hme Lässt sich das nicht mit wget oder parser per Skript in iobroker holen?
Muss bei meinem mal ein Netzwerkkabel anstecken. Hatte das nur mal zum Test dran. Aber nicht weiter geschaut was ich davon in iobroker bekomme oder wie. -
@diginix das könnte durchaus möglich sein. Jedoch bin ich auf weitesgehend fertige Lösungen angewiesen, da mir die programmiertechnischen Kenntnisse schlicht fehlen.
-
@hme Hatte schon wieder vergessen dass der KSEM modbus kann. Dann sollte es mit dem Adapter und der Spec TQ_EM_Modbus_Slave.0013.pdf funktionieren.
-
@diginix sagte in IOBroker Anbindung an einen Kostal Plenticore:
@StrathCole
Hatte heute mal wieder den Fall dass etwas mit der Regenvorhersage nicht passte, was ja mal passieren kann. Aber der Adapter haut dann mehrfach eine nicht unerhebliche Menge an "Müll" in das Log:
@StrathCole
Heute gab es wieder mal Probleme mit Cloud, Rain und Rain Chance:2021-12-08 11:19:35.433 - warn: plenticore.0 (1269342) Processing cloud data failed
2021-12-08 11:19:35.441 - warn: plenticore.0 (1269342) Processing rain data failed
2021-12-08 11:19:35.441 - warn: plenticore.0 (1269342) Processing rain chance data failedDu lässt dann den html body mit ins Log werfen, klar um es analysieren zu können. Hab das "+ body" nun vorerst aus /opt/iobroker/node_modules/iobroker.plenticore/lib/weather.js auskommentiert.
-
@diginix Danke für den Hinweis, das sollte eigentlich wenn überhaupt nur im Debug-Modus kommen. Muss ich korrigieren.
-
@strathcole Stimmt, hab dem 3 Zeilen nun ".debug" als Loglevel gegeben. Dann ist ebenso Ruhe, aber bei Bedarf ist der volle Informationsgehalt verfügbar.
Kannst dir ja den html body aus meinem Zitat mal anschauen. Irgendwas passt deinem Parser da ja nicht. So tief hab ich aber nicht schauen wollen. -
@diginix Habe ich. Da sind tatsächlich keinerlei Werte drin.
-
@strathcole Ok, wenn gar nichts drin ist, dann kannst auch nichts anpassen. Hätte ja sein können, dass irgendwas ein bisher unbekannten Syntax hat.