DISCLAIMER: Ich beschreibe hier meine Erfahrungen beim Aufbau einer Solaranlage mit Speicher im DIY Verfahren und übernehme keine Verantwortung für das von euch realisierte Konstrukt. Use at your own risk! Bedenkt, dass elektrischer Strom unter Umständen auch lebensgefährlich oder gar tödlich verletzen kann. Arbeiten am Stromnetz des eigenen Haushalts besser einem ausgebildeten Elektiker überlassen.
Inhalt
Was
Eine Einspeiseregelung hat den Zweck, immer genau so viel Strom aus einer Batterie ins Hausnetz zu füttern, wie im selben Augenblick verbraucht wird. Zumindest bis die Leistungsgrenze des Wechselrichters erreicht ist. Alles darüber hinaus kommt aus dem Netz vom Energieversorger. Mit einem 600W Wechselrichter zur Einspeisung ist mein Ziel eher die Abdeckung der Grundlast im Haushalt. Und das idealerweise in all den Stunden, in denen kein oder zu wenig Solarstrom erzeugt wird.
Ich hatte mir ganz am Anfang meiner Solarexperimente einen Hoymiles HM-600 Wechselrichter zugelegt. Aber der Appetit kommt mit dem Essen, weshalb ich dann sehr schnell auf einen HMS-1600 aufgerüstet habe. Der HM-600 war also übrig, um ihn für die Batterie-Einspeisung zweckzuentfremden.
Funfact: Übrig war auch das openDTU Interface zum Wechselrichter und zwar aus einem ganz trivialen Grund: Die neueren Hoymiles Wechselrichter mit der Kennung HMS haben einen anderen Funkstandard, der ein anderes Funkinterface benötigt. Dieses gibt es zusammen mit dem openDTU Bausatz für wenig Geld bei Blinkyparts. Nun ist dieser CMT2300A Funkchip so winzig und fummelig, dass ich es einfach nicht geschafft habe, das Teil so auf die Platine zu löten, dass es hinterher auch funktioniert hat.(Update: Inzwischen gibt es den Chip bei Blinkyparts auch verlötet). Ich habe mich seinerzeit auf die Suche nach einem anderen Anbieter gemacht bei dem der Chip schon montiert war und bin bei wechselrichter-versand.de fündig geworden. Leider wird das Teil dort nicht mehr verkauft. Die zuerst gekaufte OpenDTU kann ich nun in Verbindung mit dem NRF Funkmodul prima für die Einspeisung verwenden. Das Display sieht im Sicherungskasten auch ganz schick aus.
Wann – Einspeisestrategie
Bezüglich der Strategie, also wann wird eingespeist, gibt es viele Möglichkeiten. Man könnte zum Besispiel immer einspeisen, wenn der gerade produzierte Solarstrom nicht ausreicht oder nur dann, wenn kein Solarstrom produziert wird. Oder nur zu bestimmten Tageszeiten, zum Beispiel, wenn der Stromtarif besonders teuer ist. Und so weiter. Ich habe mich vorerst auf die ersten beiden Strategien beschränkt.
Die Einspeise-Strategie wird über einen Drop-Down Node realisiert. Zum Persisitieren wird die Strategie entsprechend weggespeichert und bei Neustart wieder eingelesen. Zur späteren Verwendung, wird eine Flow Variable erzeugt.
Anschließend wird alle 30 Sekunden entschieden, ob der Batterie-WR an- oder ausgeschaltet werden oder sein Status unverändert bleiben soll.
Das geschieht im Node "Einspeisung-Basics":
Die Entscheidung wird wie folgt getroffen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
let strategy = msg.payload; let socMinimum = flow.get("minSoc"); // untere Entladegrenze des Akkus let soc = global.get("SoC"); //State of Charge let consump =global.get("gpowerTotal"); //aktueller Netzbezug/Überschuss let solarProd = global.get("solarProducing"); //status Solarproduktion let setWRStatus=1; let canDo = 1 // Genereller Ausschluss --> WR wird nicht eingeschaltet wenn: // SoC unter Minimum if (soc <= socMinimum) { setWRStatus = 0; canDo=0; } //bei Batterieladen keine Einspeisung if (global.get("chargeWatt")>0) { setWRStatus=0; canDo=0 } if (consump < -20 && solarProd > 0) // bei niedrigem Export verhindern, dass WR anspringt. Morgens { setWRStatus = 0; canDo = 0; } // Ende genereller Ausschluss //wenn generell möglich: Aktion gemäß Strategieauswahl if (canDo == 1) { if (strategy == 0) // WR "Aus" gesetzt { setWRStatus=0 } else if (strategy == 1) // Nach Bedarf - Nullimport { setWRStatus = 1; } else if (strategy == 2) // nach Bedarf wenn kein Solarertrag { if (solarProd == 1) { setWRStatus = 0; } else { setWRStatus = 1; } } } msg.payload = setWRStatus; return msg; |
Anschließend wird anhand der Payload (1/0) verzweigt und der WR an oder ausgeschaltet. Nicht dargestellt ist die Logik zum Einschalten der Batterie und andere Features. Da euer Setup sich mit einiger Sicherheit von meinem unterscheidet, macht es hier (anders als z.B. bei den Viessman API Flows) wenig Sinn, das 1 zu 1 vorzugeben. Jetzt ist euer Hirnschmalz gefragt.
Wieviel – Leistungssteuerung
Mathematik ist nicht unbedingt meine Stärke, wenn es über die Grundrechenarten hinausgeht. Die Frage war: Wie passe ich die Leistung des Einspeise Wechselrichters an meinen Verbrauch an?
Eine Bezugsgröße ist der Strom, der aus dem Netz gezogen wird – dieser soll möglichst bei Null oder knapp darüber liegen. Dadurch, dass ich mit der Einspeisung diese Bezugsgröße laufend ändere und ich auch keine Voraussage über den gerade benötigten Strom (Licht an, Herd aus…) oder die gerade herrschende Solarprodukton machen kann, wird es schnell sehr kompliziert – finde ich.
Ich habe mit verschiedenen Algorithmen und auch mit einem PID Regler Verfahren experimentiert und bin zu keinem Ergebnis gekommen. Zuviel Mathematik. Auch die PID Nodes die man in Node-Red einbauen kann, haben mich eher verwirrt.
Dann bin ich von "Der Kanal" bei Youtube auf einen guten Ansatz gebracht worden. Christian Waller hat in seinem Beitrag zwar ein Ladegerät angesteuert und keinen Wechselrichter – dazu noch mit IO Broker 😖- aber der Ansatz war ausgesprochen zielführend: Ich nenne es Iterativ Dynamische Nachführung.
Etwas Theorie
Benötigt werden im Grunde 2 Werte: Der aktuelle Bezug aus dem Netz und die aktuelle Leistung des Wechselrichters. Sehr stark vereinfacht sieht das dann so aus.
Beispiel: Die Endlosschleife prüft laufend, ob der bezogene Strom aus den Netz über Null liegt – wenn ja, wird die Leistung des Wechselrichters um 1% erhöht. Dadurch ändert sich der Netzbezug – er wird kleiner. Der Vorgang wird so lange wiederholt, bis der Netzbezug Null ist. Liegt der Netzbezug unter Null wird mit negativem Vorzeichen geregelt.
Jetzt könnte man fragen, warum nimmt man nicht einfach die Differenz und regelt den Wechselrichter auf einen Schlag so aus, dass der Netzbezug Null ist?
Darum: Nehmen wir an, der Netzbezug liegt bei 30W. Die Leistung des WR wird deshalb in einem Schritt um 30W erhöht. Der Netzbezug ist danach auf Null aber der WR liefert immer noch 30W zusätzlich. Aufgrund der Regelungsträgheit des Systems im Allgemeinen und des Wechselrichters im Besonderen, kann die Erhöhung nicht augenblicklich zurückgefahren werden – die Regelung überschießt und es werden jetzt 30W ins Netz eingespeist. Flugs wird mit -30W gegengesteuert und der Überschuss ist wieder da. So geht es hin und her bis sich irgend einer der anderen Parameter unabhängig davon ändert (z.B. Licht an).
Der Stromverbrauch im Haushalt ändert sich laufend. Es kommt also zu sehr starken und unerwünschten Ausschlägen nach oben (WR speist zuviel ein, das Zuviel geht ins Netz) oder nach unten (WR speist zu wenig ein und es wird Strom aus dem Netz bezogen).
Das passiert mehrmals in wenigen Sekunden und die Stromverlaufskurve sieht dann aus wie ein Oszillogramm von Beethovens Fünfter Symphonie. Das ist ineffizient und stresst die Komponenten.
Natürlich ist der im Flussdiagramm dargestellte Algorithmus mit +-1% Anpassung viel zu langsam. Also wird die Änderungsrate abhängig von der Differenz zum Zielwert größer oder kleiner gewählt aber eben nicht um den absoluten Differenzbetrag.
Anwendungsbeispiel
Basierend auf der oben erwähnten Anregung durch "Der Kanal" habe ich folgende Regelung gebaut. Eine Besonderheit bei den Hoymiles Wechselrichtern ist, dass die Regelung über Prozentwerte besser funktioniert als über die absolute Leistung in Watt, da die interne Regelungs prozentgenau ( dh.h. beim HM-600 auf 6W genau) erfolgt. Die minimale Leistung des verwendeten Hoymiles 600 liegt bei 2% also 12W.
Die Logik lässt sich auf jeden Wechselrichter anwenden, der über eine API, MQTT oder sonstwie fernsteuerbar ist.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
let feed = flow.get("feedWRLimit"); // Leistungseinstellung des WR auslesen let power = global.get("gpowerTotal"); // aktueller Netzbezug bzw. Überschuss let maxFeedProz=flow.get("maxfeed")/6; //im Dashboard eingestellte oder tatsächliche Maximalleistung des WR //maxFeedProz wird errechnet z.B. HM-600 -->Einstellung 300 --> 300/600*100=50% let feedWRActive = flow.get("feedWRActive"); // Status des Einspeise WR (1/0) // ACHTUNG: feed = PROZENTWERTE zwischen 0 und 100% // power = Netzbezug/Überschuss in WATT(!) // msg.ff ist optional zum debuggen if (feedWRActive = 1) // Schleife läuft nur, wenn WR aktiv ist { if (power >= 6) // eigentlich redundant, reduziert aber die Anzahl if Abfragen { if (power >= 150) { msg.ff=20; feed=feed +20; } else if (power >= 100) { msg.ff=15; feed=feed + 15; } else if (power >= 50) { msg.ff=8; feed=feed + 8; } else if (power >= 25) { msg.ff=3; feed = feed + 2; } else if (power >= 10) { msg.ff=1; feed+1; } else if (power >0) { msg.ff=1; feed++; } else if (power =0) { msg.ff="BINGO!!!"; // wird nicht vorkommen } } else if (power < 0) //power < 0 also Einspeisung ins ENEL Netz { if (power <= -150) { msg.ff=-20; feed = feed - 20; } else if (power <= -100) { msg.ff=-15; feed = feed - 15; } else if (power <= -50) { msg.ff=-8; feed = feed - 8; } else if (power <= -25) { msg.ff=-5; feed = feed - 5; } else if (power <= -10) { msg.ff=-4; feed = feed-4; } else if (power <3) { msg.ff=-1; feed--; } } } if (feed > maxFeedProz) //PROZENT!! { feed = maxFeedProz; } else if (feed < 0) { feed = 2; } msg.power=power; msg.payload = feed; flow.set("feedWRLimit",feed); return msg; |
Erläuterung:
feed bzw. flow.feedWRLimit ist ein Prozentwert und repräsentiert die aktuell dem WR übermittelte bzw. zu übermittelnde Leistung in Prozent. Die von mir angegebenen Prozentwerte gelten für meinen 600W Wechselrichter. Bei anderen WR Leistungen müsst ihr die Prozentwerte entsprechend anpassen!
power bzw. global.gpowerTotal ist der aktuelle Strombezug oder Überschuss vom Netz in Watt. Ausgelesen über den Strommesser – bei mir ein Shelly 3EM.
maxFeedProz bzw. flow.maxfeed ist die Leistungsbegrenzung, die ich entweder über das Dashboard eingegeben habe oder die maximale Leistung des Wechselrichters.
Auf der Plus Seite (zu hoher Netzbezug) fängt die Regelung an, wenn mehr als 6 Watt aus dem Netz bezogen werden. Null Watt hat sich nicht bewährt, die Regelung wird "zittrig".
Abhängig von der Differenz des Netzbezugs zum Zielwert wird mit entsprechenden stärkeren oder schwächeren Leistungserhöhungen gegengesteuert.
Beispiel:
Ist der Netzbezug gleich oder höher als 150W, wird die Leistung feed um 20% (entspricht 120W) erhöht.
Bei 100W Überschreitung wird feed um 15% (= 90W) erhöht und so fort. Je niedriger der Netzbezug desto kleiner die Änderung. Irgendwann ist der Netzbezug nahe Null und die Regelung hört auf, so lange sich der Zustand nicht ändert.
Bei negativem Netzbezug (Überschuss und Einspeisung ins Netz) passiert dasselbe nur mit umgekehrten Vorzeichen.
Je nach eurer eigenen Situation müsst ihr mit den Anpassungswerten etwas spielen, damit eine möglichst glatte Anpassungskurve entsteht.
Alternativen
Das obige Javascript bzw. der NR Function-Node kommt vielleicht etwas "hölzern" daher, da hier in Stufen reguliert wird und nicht kontinuierlich. Immerhin hat das Stufenkonzept den Vorteil, dass ich bei starker Abweichung vom Sollwert einen proportional viel höheren Korrekturwert einstellen kann, als bei einer strikt linearen Steuerung – bei der ich z.B. die Differenz immer auf 60% dämpfe und als Anpassungswert einspiele.
Eine lineare Korrektur des Steuerparameters sähe so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
let korrektur = 0; let feed = flow.get("feedWRLimit"); // Leistungseinstellung des WR auslesen let power = global.get("gpowerTotal"); // aktueller Netzbezug bzw. Überschuss let maxFeedProz=flow.get("maxfeed")/6; //im Dashboard eingestellte oder tatsächliche Maximalleistung des WR //maxFeedProz wird errechnet z.B. HM-600 -->Einstellung 300 --> 300/600*100=50% let feedWRActive = flow.get("feedWRActive"); // Status des Einspeise WR (1/0) // ACHTUNG: feed = PROZENTWERTE zwischen 0 und 100% // power = Netzbezug/Überschuss in WATT(!) // msg.ff ist optional zum debuggen if (feedWRActive = 1) // Schleife läuft nur, wenn WR aktiv ist { let korrektur = power/6 * 0.6 //Leistung in WR% mal Dämpfung (Attenuation) feed = Math.round(feed + korrektur); } if (feed > maxFeedProz) //PROZENT!! { feed = maxFeedProz; } else if (feed < 0) { feed = 2; } msg.power=power; msg.payload = feed; //zum debuggen msg.korrektur = korrektur; //zum debuggen flow.set("feedWRLimit",feed); return msg; |
Da wir ja möglichst einen Netzbezug von Null haben wollen ist der Zielwert logischerweise auch Null. Die Differenz zwischen Soll und Ist ist also gleich dem Netzbezug.
Der Korrekturwert errechnet sich aus dem in %WR Leistung umgerechneten Netzbezug /Einspeisung multipliziert mit einem passenden Dämpfungsfaktor – hier 60%.
Beispiel: Die Abweichung beträgt +120W bzw. 20%
–> Korrekturwert ist also 20% * 0,6 = 12%
Das Javascript ist nun sehr viel überschaubarer und auch ein paar Microsekunden schneller abgearbeitet. Der optimale Dämpfungswert muss durch Ausprobieren herausgefunden werden. Je größer, desto schneller ist der Zielwert erreicht aber desto leichter überschießt die Regelung.
Man könnte sich auch anstatt einer linearen Dämpfung (Attenuation) auch eine geometrische Funktion überlegen – mir ist das zuviel Mathematik, zumal meine Methode für den Hausgebrauch ausreicht.
Umsetzung
Getriggert wird der Regelungs-Node durch das von mir so vorgegebene MQTT Topic batterie/WR/114183112536/status/limit_relative also die relative Leistung des Wechselrichters, die ca. alle 5 Sekunden upgedated wird. Ihr habt sicher eine andere Topicbezeichnung am Start. Schöner wäre natürlich ein schnellerer Takt aber da macht die openDTU leider nicht mit – aber die Regelung ist trotzdem hinreichend genau.
Der Output läuft bei mir noch über einen Filter, der die Message nur bei geänderten Werten weiterleitet. Damit wird der Wechselrichter nicht laufend mit demselben Wert beaufschlagt.
Der nachfolgende "Gate" Node dient dazu, den Wechselrichter logisch abzukoppeln, wenn er nicht benötigt wird. Sonst wird die den Wechselrichter gerne mal unnötig aufweckt. Hätte hätte ich sicher auch eleganter lösen können – aber es funktioniert.
Woher – der Akku
Wie schon andernorts geschildert, habe ich zwei Pylontech US2000C mit 48V und insgesamt theoretisch 4800Wh im Einsatz. Der Hoymiles Wechselrichter zieht – wenn er kann – auch im ausgeschalteten Zustand ca. 2 Watt aus dem Akku. Das fand ich irgendwie blöd – gerade in der dunkleren Jahreszeit kommt es auf jedes Watt an. Deshalb habe ich eine Steuerung für die Akkus gebaut, die das verhindert. Der Akkustatus wird über eine kleine HW Komponente ausgelesen, die ebenfalls in diesem Beitrag beschrieben ist und Links zur Anleitung enthält.
Keine Komplettlösung
Ich zeige oben nur die Node Darstellung meines Setups und nicht die komplette Lösung als Node Red JSON. Es müssen eine Menge Parameter quer übers System eingelesen und in Kontext Variable gesteckt werden. Das zu dokumentieren ist ausgesprochen aufwändig und macht auch wenig Sinn, da es bei euch mit Sicherheit anders aussieht als bei mir.
Bei Interesse stelle ich das JSON gerne zur Verfügung, kann aber nur wenig Support leisten.
Bei Fragen zu den Prinzipien der Steuerung (wie hast du das … gelöst?) etc. helfe ich gerne weiter.
Hi Chris,
bin auch gerade dabei meine Nulleinspeisung zu programmieren. Darf ich deinen Flow bekommen, das wäre toll?
VLG; André
ist unterwegs…
Hi,
beschäftige mich grade mit Nulleinspeisung für die Nacht mit HM-800 und Growatt Noach2000. Würde es gerne in node red umsetzen und wäre für deinen flow sehr dankbar.
lg
Joachim
ist unterwegs…
Hallo Chris,
Du hast genau das gebaut, was ich vor mir habe – wenn auch mit einem HM1500.
Ich wäre Dir sehr dankbar, wenn Du den kompletten Flow mit mir teilen könntest.
Gruß,
ULI
Aber gerne doch… kommt per Mail.
VG
Chris
Hallo Chris,
ich habe deinen Beitrag sehr interessiert gelesen. Ich bin zur Zeit am verzweifeln für eine vernünftige Nulleinspeisung hin zubekommen. Ich wäre an Deiner lösung sehr interessiert. Ist es noch möglich den Flow zubekommen?
Grüße Walter
Kommt per Mail und dazu noch das JSON für den Überschuss Limiter. Vllt kannst du damit was anfangen…
VG
Chris
Super Arbeit!
Würde mich ebenfalls gerne inspirieren lassen, aktuell ist allerdings noch kein Akku vorhanden, sprich aktuell nur für den Zero Export.
Hoymiles WR, AhoyDTU und ShellyPro3em sind vorhanden.
Vielen Dank
ist unterwegs. Viel Spaß noch…
Hallo Chris,
vielen Dank für das Dokumentieren und Vorstellen Deiner Lösung. Ich bin auch über die Videos von Offys Kanal auf das Thema Nulleinspeisung mit Solarspeicher gekommen. Da ich den HM-600 nach Upgrade auf einen 'größeren' WR übrig habe, gefällt mir Dein Lösungsansatz, den HM-600 als Einspeise-WR zu nutzen sehr gut.
Würdest Du mir Deinen Node Flow als Ausgangsbasis zur Verfügung stellen?
Greetinx, Udo
kommt sogleich.
Viel Spaß damit
Chris
Mahlzeit,
der Script gefällt mir. Könnte ich auch eine Kopie bekommen?
Danke
Kommt in Kürze per Mail.
VG
Chris
Hallo Chris,
danke für den sehr interessanten Beitrag. Könnte ich mit dir Kontakt aufnehmen um dir mein Problem zu schildern? Ansonsten hätten ich auch Interesse an deinen Flow. Vielleicht kannst du mir diesen zukommen lassen. Vielen Dank im voraus.
Beste Grüße
Ulf
Kommt gleich…
Moin,
danke dir für den interessanten Beitrag. Ich würde deinen Flow gerne als Inspiration für mein eigenes Projekt verwenden. Würdest du mir den Flow als JSON zuschicken?
Danke dir im voraus!
Beste Grüße
Seb
Ist unterwegs
Moin,
der Flow ist der Hammer und könnte mir wirklich weiterhelfen.
Sofern du ihn teilen würdest, melde dich bitte bei mir …
Habe zwar Deye und einen BLuepalm 2,2 KWh im Einsatz aber ich hoffe das umgebaut zu bekommen 🙂
Beste Grüße,
Snot
ist unterwegs an deine Email Adresse 🙂
Hi Chris,
Deine Lösung sieht echt gut aus. Die würde ich gerne als Basis verwenden.
Magst Du mir die bitte auch zusenden?
Grüße SSC
Gerade verschickt
VG
Chris