Einleitung
Stell dir vor, du könntest fast jede Kilowattstunde deines Balkonkraftwerks nutzen, ohne signifikante Energiemengen ins Netz einzuspeisen. Genau das habe ich mit einem Setup aus zwei 430W PV-Modulen, verbunden mit einem Zendure HUB1200 Speichersystem und einem AB2000 Speicher, erreicht. Der Schlüssel dazu? Ein durchdachtes Energiemanagement mittels Home Assistant, das überschüssige Energie nicht nur speichert, sondern auch intelligent verteilt.
Mein System verwendet einen Hoymiles Mikrowechselrichter mit 800W Leistung, und der Stromverbrauch wird durch einen Shelly 3EM gemessen, der nahtlos in den Home Assistant integriert ist. Obwohl die Zendure App fortschrittliche Funktionen wie den CT Modus bietet, der den Hausbedarf ermittelt und die Ausgangsleistung entsprechend anpasst, erreichte sie nicht die Perfektion, die ich mir wünschte. Das inspirierte mich zur Entwicklung meiner eigenen Methode, die ich „Dynamische Nulleinspeisung“ nenne – ein Ansatz, der über die traditionelle Nulleinspeisung hinausgeht. Diese Methode passt die Energieversorgung dynamisch an den tatsächlichen Bedarf an und nutzt die volle Kapazität des Speichers optimal aus, um die Einspeisung ins Netz so gering wie möglich zu halten.
Es ist wichtig zu betonen, dass dies keine weltweite Neuheit ist, sondern eine effektive Anpassung und Regelung speziell für dieses Setup, die dazu beiträgt, Energie effizienter zu nutzen.
Haftungsausschluss
Die Informationen in diesem Blogbeitrag sind sorgfältig recherchiert, jedoch übernehme ich keine Haftung für die Richtigkeit und Vollständigkeit der Inhalte. Dieser Beitrag stellt keine Werbung dar; die erwähnten Produkte und Technologien nutze ich selbst und empfehle sie basierend auf meinen Erfahrungen ohne finanzielle Anreize.
Wann macht Nulleinspeisung Sinn?
Nulleinspeisung ist besonders sinnvoll, wenn du die volle Kontrolle über deine erzeugte Solarenergie haben möchtest und gesetzliche oder netztechnische Einschränkungen bestehen. Seit Mai 2024 dürfen in Deutschland PV-Anlagen bis zu einer Leistung von 800W betrieben werden, ohne dass eine Anmeldung beim Netzversorger erforderlich ist; eine Meldung beim Marktstammdatenregister (MaStR) bleibt jedoch notwendig. Dies macht kleinere Anlagen attraktiver, kann aber auch bei größeren Installationen sinnvoll sein, wenn die lokale Netzkapazität begrenzt ist oder spezielle Vorschriften eine Nulleinspeisung erfordern. Systeme mit Speichern bieten den Vorteil, dass nicht sofort verbrauchte Energie gespeichert und später genutzt werden kann, was die Unabhängigkeit vom Stromnetz erhöht und die Energieeffizienz verbessert. Die dynamische Nulleinspeisung, wie in meinem Setup verwendet, maximiert die Nutzung dieser Solarenergie durch präzise Steuerung des Energieflusses entsprechend dem aktuellen Verbrauch, was besonders bei schwankendem Energiebedarf vorteilhaft ist.
Wann lohnt sich Nulleinspeisung nicht?
Die Entscheidung gegen eine Nulleinspeisung kann bei Balkonkraftwerken sinnvoll sein, insbesondere wenn kein Speichersystem vorhanden ist. In solchen Fällen kann der überschüssig produzierte Strom vollständig ins Netz eingespeist werden. Da Balkonkraftwerke in der Regel eine geringe Leistung aufweisen, ist die Einspeisevergütung oft zu niedrig, um signifikante finanzielle Vorteile zu bringen. Zudem können zusätzliche Kosten durch die Miete eines Zweirichtungszählers (Messstellenentgelt) entstehen, welche die geringen Einnahmen aus der Einspeisevergütung möglicherweise nicht aufwiegen. Diese finanziellen Aspekte machen es weniger attraktiv, in ein aufwändiges System zur Nulleinspeisung zu investieren, wenn die Anlage klein ist und keine Speicherlösung integriert ist.
Letztendlich hängt die Entscheidung, ob eine Nulleinspeisung implementiert wird oder nicht, stark von den individuellen Präferenzen, dem Energiebedarf und den örtlichen Gegebenheiten ab. Es empfiehlt sich, sowohl die einmaligen als auch die laufenden Kosten gegen den tatsächlichen Nutzen abzuwägen, um die beste Entscheidung für die persönliche Situation zu treffen.
Funktionsweise der Nulleinspeisung
Die Nulleinspeisung, funktioniert wie ein intelligentes System, das den aktuellen Strombedarf kontinuierlich erfasst und die Ausgangsleistung des Wechselrichters entsprechend anpasst. Durch diese Anpassung wird der Netzbezug auf nahezu Null reduziert. Ich habe die Ausgangsleistung speziell an meine Bedürfnisse angepasst und so konfiguriert, dass sie eine vorgegebene maximale Einspeisegrenze nicht überschreitet. Dieser Ansatz schont nicht nur das Material des Speichers und der Komponenten, sondern berücksichtigt auch den Ladezustand des Speichers, indem der Wechselrichter bei bestimmten SoC-Grenzwerten (State of Charge) gestoppt oder aktiviert wird.
Um das Energiemanagementsystem flexibel zu gestalten, habe ich ein seperates Frontend für das Home Assistant Dashboard erstellt. Dieses Frontend ermöglicht es mir, Parameter einfach einzustellen und einen detaillierten Einblick in den aktuellen Zustand des Systems zu erhalten. Die Benutzeroberfläche ist darauf ausgelegt, eine Visualisierung der Energieflüsse und Systemzustände zu bieten und macht es einfach, Anpassungen vorzunehmen, um die Effizienz und Effektivität des Systems kontinuierlich zu optimieren.
Im folgenden Verlaufsdiagramm werden vier wichtige Datenpunkte meines Energiemanagementsystems dargestellt: der Netzbezug in Orange, die Ausgangsleistung des HMS-800-2T Wechselrichters in Rot, die durch die Nulleinspeisung reguliert wird, die Leistung des HM-300-1T, eines zusätzlichen Balkonkraftwerks, in Weiß und der SoC-Wert (State of Charge) des Speichers in Grün. Die Darstellung umfasst einen Zeitraum von einem Tag.
Das Diagramm zeigt deutlich, wie die Nulleinspeisung mit dem Netzbezug gekoppelt und aktiv geregelt wird. Besonders auffällig ist, wie die Leistung des HMS-800-2T angepasst wird – heruntergeregelt oder sogar abgeschaltet (beispielsweise zwischen 10:30 Uhr und 11:30 Uhr), wenn das kleinere Balkonkraftwerk HM-300-1T genug Energie bereitstellt, um den aktuellen Bedarf zu decken.
Zurzeit ist die maximale Leistungsgrenze auf etwa 128 Watt eingestellt. Es ist ebenfalls zu beobachten, dass das Einspeisen stets einige Watt unterhalb des bezogenen Stroms liegt. Dies ist einerseits auf die Auflösung der Leistungseinstellung des Wechselrichters zurückzuführen – 1% entspricht 8 Watt – und andererseits darauf, dass der eingestellte Leistungswert immer leicht von der tatsächlichen Ausgangsleistung des Wechselrichters abweicht. Dies ist jedoch kein Problem für mich; der Hauptfokus liegt darauf, keinen Überschuss ins Netz zu speisen.
Dieses Zusammenspiel der verschiedenen Energiequellen optimiert den Gesamtenergieverbrauch und reduziert die Abhängigkeit vom öffentlichen Stromnetz, was zu einer effizienteren und kostengünstigeren Energieverwaltung führt.
Kein Plug-and-Play System: Bedingungen, Wissen und benötigte Komponenten
Für eine effiziente Umsetzung der dynamischen Nulleinspeisung benötigst du einiges an Technik und Know-how. Hier eine Übersicht der notwendigen Komponenten und Fähigkeiten:
- PV-Anlage und Speichersystem: Die Grundlage bildet deine Photovoltaikanlage zusammen mit einem leistungsfähigen Speichersystem.
- Energiezähler für den Hausverbrauch: Geräte wie der Shelly 3EM messen deinen gesamten Hausverbrauch.
- Energiezähler nach dem Wechselrichter: Zum Beispiel der Shelly Plus PM Mini, der den Energiefluss direkt nach dem Wechselrichter erfasst.
- openDTU zur Steuerung des Wechselrichters: Ein wichtiger Bestandteil zur Kommunikation und Steuerung deines Wechselrichters.
- Home Assistant und NodeRed: Diese Plattformen ermöglichen es dir, das gesamte System zu programmieren und zu überwachen.
- Programmierkenntnisse in JavaScript, YAML und Markdown: Diese Skills helfen dir, die notwendigen Skripte und Konfigurationen zu erstellen und ggf. anzupassen.
- MQTT-Zugang zum Zendure Broker: Notwendig, um aktuelle Daten wie den SoC-Stand zu beziehen.
- Freude am Basteln, Forschen und Testen: Ohne diese Begeisterung wird es schwer, die Herausforderungen zu meistern.
Dieses Setup ist kein einfaches Plug-and-Play System. Es erfordert sowohl software- als auch hardwareseitig einen gewissen Aufwand zur Datenbeschaffung. Beispielsweise musst du den MQTT Broker von Zendure integrieren, um Zugriff auf die Daten des Zendure SolarFlows HUB1200 zu erhalten und den Ladezustand des Speichers zu erfassen. Eine gute Anleitung dazu findest du hier: Anleitung zum Einbinden des Zendure SolarFlow Superbase in Home Assistant. Auch das Bauen einer openDTU ist erforderlich, um mit dem Wechselrichter kommunizieren zu können und die Leistung variabel anzupassen. Hierfür gibt es bereits fertige und kostengünstige Bausätze im Netz, wodurch sich der Zusammenbau einer openDTU in Grenzen hält.
Benötigte Entitäten und Helfer im Home Assistant
Um das System der Nulleinspeisung effizient zu steuern, benötigst du eine Reihe von Entitäten und Helfern in Home Assistant. Diese dienen als Grundlage für die Berechnungen, die zur Anpassung der Energieflüsse erforderlich sind.
Bitte beachte, dass die Namen der Entitäten und Helfer, die ich für mein System verwendet habe, spezifisch für meine Konfiguration sind. In deinem eigenen Home Assistant Setup kannst und solltest du die Namen der Entitäten und Helfer entsprechend deinen Präferenzen und Anforderungen anpassen.
Hier ist eine Liste der spezifischen Helfer, die ich für mein Setup verwendet habe:
Helfer:
- Ausschaltschwelle Wechselrichter (%): Bestimmt den SoC-Wert (State of Charge), bei dem der Wechselrichter abschalten soll, um die Batterie zu schonen.
- Einschaltschwelle Wechselrichter (%): Legt fest, bei welchem SoC-Wert der Wechselrichter wieder aktiviert wird, um die Energieversorgung zu gewährleisten.
- Maximale Ausgangsleistung Wechselrichter (W): Definiert die Höchstleistung, die der Wechselrichter ausgeben darf (z. B. 800W für den HMS-800-2T).
- Maximale Ausgangsleistung (%) bei SoC 100 %: Gibt an, wie hoch die Ausgangsleistung des Wechselrichters sein darf, wenn der Speicher voll geladen ist.
- Maximale Leistung Nulleinspeisung Wechselrichter (%): Definiert den oberen Leistungsbereich, der für die Anpassung der Grundlast zur Verfügung steht.
- Minimale Leistung Nulleinspeisung Wechselrichter (%): Bestimmt den unteren Leistungsbereich, der zur Anpassung der Grundlast genutzt werden kann.
- Statische Ausgangsleistung Wechselrichter (%): Die feste Ausgangsleistung des Wechselrichters, wenn die Nulleinspeisung deaktiviert ist.
- Status Nulleinspeisung: Schalter zum Aktivieren (1) oder Deaktivieren (0) der Nulleinspeisung.
- Trigger Nulleinspeisung: Ein zeitlicher Trigger, der bestimmt, wie oft die Berechnungen zur Anpassung der Ausgangsleistung stattfinden sollen (z. B. alle 60 Sekunden).
Entitäten:
Leistungsentitäten:
- Netto Stromverbrauch: Dies ist der Stromverbrauch, der aktuell in der Wohnung benötigt wird und setzt sich aus der generierten PV-Leistung und dem Verbrauch durch die Haushaltsgeräte zusammen.
- Brutto Stromverbrauch: Dies entspricht der Strommenge, die aus dem öffentlichen Netz bezogen wird.
- Wechselrichterleistungen: Diese Entität erfasst die Leistungen von einer oder zwei PV-Anlagen.
- Gesamtleistung weiterer Erzeugungsanlagen: Beispielsweise die Leistung einer weiteren PV-Anlage.
Diese Entitäten habe ich in derconfiguration.yaml
angelegt, um die Leistungswerte zu berechnen.
Entitäten zur Überwachung und Steuerung der Hardware:
- Status der OpenDTU: Zeigt an, ob die DTU online oder offline ist.
- Status Batterie: Liefert den aktuellen Ladezustand des Speichers.
- Status Wechselrichter Produktion: Gibt an, ob der Wechselrichter gerade Strom produziert.
- Status Wechselrichter Erreichbarkeit: Zeigt an, ob der Wechselrichter erreichbar ist (AN oder AUS).
- Restart Inverter: Für den Neustart des Wechselrichters.
- Leistungslimit Inverter: Zum Setzen der berechneten prozentualen Ausgangsleistung des Wechselrichters.
- Inverter An: und
- Inverter Aus: Diese Schalter dienen zum Ein- und Ausschalten des Wechselrichters.
Diese Entitäten sendet oder empfängt die OpenDTU über das Nachrichtenprotokoll MQTT.
Parameter- und Informationskarte im Home Assistant
Um die Steuerung der Nulleinspeisung in deinem Home Assistant zu verwalten, ist es sinnvoll, spezielle Karten im Dashboard einzurichten. Diese Karten ermöglichen es dir, schnell und einfach die notwendigen Parameter anzupassen und wichtige Systeminformationen zu überblicken, ohne tief in die Systemkonfiguration eintauchen zu müssen. Dies spart Zeit und ermöglicht eine effiziente Verwaltung deines Energiemanagementsystems.
Parameterkarte
Die Parameterkarte habe ich in einem separaten Tab des Home Assistant Dashboards eingerichtet. Diese interaktive Karte ermöglicht es dir, die Parameter, die der Algorithmus für die Berechnung benötigt, bequem anzupassen.
Bei aktivierter Nulleinspeisung werden die Parameter für das dynamische Nulleinspeisen angezeigt, wird diese deaktiviert, so kann nur eine statische Ausgangsleistung des Wechselrichters einngestellt werden.
Informationskarte
Direkt unter der Parameterkarte befindet sich die Informationskarte, die wichtige Daten wie Leistungswerte und den Status der OpenDTU oder des Wechselrichters anzeigt. Dies bietet dir einen schnellen Überblick über den aktuellen Zustand deines Systems.
Notwendige Frontend-Erweiterungen
Um diese Karten zu erstellen, benötigst du ein paar kleine Frontend-Erweiterungen, die du über den HACS-Store beziehen kannst:
- card-mod: Ermöglicht dir, das Aussehen deiner Karten individuell anzupassen.
- Number Box: Erlaubt die Anzeige von Nummern in einer benutzerfreundlichen Box, ideal für die Einstellung von Parametern.
YAML Code für die Parameter- und Infokarte
Hier ist ein Beispiel des YAML-Codes, den ich verwendet habe, um die Karte für meine Konfiguration zu erstellen. Du kannst diesen gerne kopieren, solltest aber die verschiedenen Entitätsnamen durch deine ersetzen.
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
type: vertical-stack cards: - type: markdown content: | ### <center>Einstellung - Nulleinspeisung</center> - type: conditional conditions: [] card: type: custom:numberbox-card border: true entity: input_number.maximale_ausgangsleistung_wechselrichter step: 50 icon: false unit: W min: 200 max: 2000 name: Inverter Typ (max. Leistung) delay: 5000 - show_name: true show_icon: false type: button tap_action: action: toggle show_state: true entity: input_boolean.status_nulleinspeisung name: Nulleinspeisung - type: conditional conditions: - condition: state entity: input_boolean.status_nulleinspeisung state: 'on' card: type: horizontal-stack cards: - type: markdown card_mod: style: | ha-card { display: flex; flex-direction: column; justify-content: center; } ha-markdown { margin: 0; } content: | Leistungsbereich Inverter - type: horizontal-stack cards: - type: custom:numberbox-card border: true entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter name: false icon: false unit: '%' min: 1 max: 100 step: 1 max_entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"von ({{ (states('input_number.minimale_leistung_nulleinspeisung_wechselrichter') | int * (states('input_number.maximale_ausgangsleistung_wechselrichter') | int / 100)) | int}} W)";display:block!important} - type: custom:numberbox-card border: true entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter name: false icon: false unit: '%' min: 1 max: 100 step: 1 min_entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"bis ({{ (states('input_number.maximale_leistung_nulleinspeisung_wechselrichter') | int * (states('input_number.maximale_ausgangsleistung_wechselrichter') | int / 100)) | int}} W)";display:block!important} - type: conditional conditions: - condition: state entity: input_boolean.status_nulleinspeisung state: 'on' card: type: horizontal-stack cards: - type: markdown content: | Schaltschwelle Inverter card_mod: style: | ha-card { display: flex; flex-direction: column; justify-content: center; } ha-markdown { margin: 0; } - type: horizontal-stack cards: - type: custom:numberbox-card border: true entity: input_number.ausschaltschwelle_wechselrichter name: false icon: false unit: '%' min: 1 max: 100 step: 1 min_entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter max_entity: input_number.einschaltschwelle_wechselrichter card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"AUS bei SoC";display:block!important} - type: custom:numberbox-card border: true entity: input_number.einschaltschwelle_wechselrichter name: false icon: false unit: '%' min: 1 max: 100 step: 1 max_entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter min_entity: input_number.ausschaltschwelle_wechselrichter card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"EIN bei SoC";display:block!important} - type: conditional conditions: - condition: state entity: input_boolean.status_nulleinspeisung state: 'on' card: type: horizontal-stack cards: - type: markdown card_mod: style: | ha-card { display: flex; flex-direction: column; justify-content: center; } ha-markdown { margin: 0; } content: | Leistung bei SoC 100% - type: horizontal-stack cards: - type: custom:numberbox-card border: true entity: input_number.maximale_leistung_wenn_soc_100 name: false step: 1 icon: false unit: '%' min: 1 max: 100 card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"bis ({{ (states('input_number.maximale_leistung_wenn_soc_100') | int * (states('input_number.maximale_ausgangsleistung_wechselrichter') | int / 100)) | int}} W)";display:block!important} - type: conditional conditions: - condition: state entity: input_boolean.status_nulleinspeisung state: 'off' card: type: horizontal-stack cards: - type: markdown card_mod: style: | ha-card { display: flex; flex-direction: column; justify-content: center; } ha-markdown { margin: 0; } content: | Inverterleistung statisch - type: horizontal-stack cards: - type: custom:numberbox-card border: true entity: input_number.statische_leistung_wechselrichter name: false step: 1 icon: false unit: '%' min: 1 max: 100 card_mod: style: > .body{display:block!important} .body::before{text-align:center;font-size:12px;content:"bis ({{ (states('input_number.statische_leistung_wechselrichter') | int * (states('input_number.maximale_ausgangsleistung_wechselrichter') | int / 100)) | int}} W)";display:block!important} - type: conditional conditions: [] card: type: custom:numberbox-card border: true entity: input_number.trigger_nulleinspeisung name: Aktualisiere Ausgangsleistung aller step: 10 icon: false unit: s min: 10 max: 600 - type: markdown content: > ||| | :--- | :--- | | ***Leistungswerte*** || | Stromverbrauch: | **{{ states('sensor.power_consumption') | int }} W** | | Netzbezug: | **{{ states('sensor.power_current') | int }} W** | | Inverterleistung WEST: | **{{ states('sensor.power_pv_1') | int }} W** | | Inverterleistung SÜD: | **{{ states('sensor.power_pv_2') | int }} W** | |<br>|<br>| | ***Status*** | | | {% if states('input_boolean.status_nulleinspeisung') == 'on' %} | | Nulleinspeisung: | <font color="green">Aktiviert</font> | | openDTU erreichbar: | {% if states('binary_sensor.opendtu_168e58_status') == 'on' %}<font color="green">Onine</font>{% else %}<font color="red">Offline</font>{% endif %} | | Inverter Grenzwert: | **{{ states('number.hms_800_2t_limit_persistent_relative') | int }} %** (**{{ states('number.hms_800_2t_limit_persistent_absolute') | int }} W**) | | Inverter produzierend: | {% if states('binary_sensor.hms_800_2t_producing') == 'on' %}<font color="green">An</font>{% else %}<font color="red">Aus</font>{% endif %} | | Inverter erreichbar: | {% if states('binary_sensor.hms_800_2t_reachable') == 'on' %}<font color="green">An</font>{% else %}<font color="red">Aus</font>{% endif %} | | SoC Speicher: | **{{ states('sensor.solarflow_solarflow_electriclevel') | int }} %** ({% if states('sensor.solarflow_pv_system_packstate') == '0' %}Standby{% elif states('sensor.solarflow_pv_system_packstate') == '1' %}Lädt{% elif states('sensor.solarflow_pv_system_packstate') == '2' %}Entlädt{% else %}Unbekannter Status{% endif %}) | | {% else %} | | Nulleinspeisung: | <font color="red">Deaktiviert</font> | | openDTU erreichbar: | {% if states('binary_sensor.opendtu_168e58_status') == 'on' %}<font color="green">Onine</font>{% else %}<font color="red">Offline</font>{% endif %} | | Inverter Grenzwert: | **{{ states('number.hms_800_2t_limit_persistent_relative') | int }} %** (**{{ states('number.hms_800_2t_limit_persistent_absolute') | int }} W**) | | Inverter produzierend: | {% if states('binary_sensor.hms_800_2t_producing') == 'on' %}<font color="green">An</font>{% else %}<font color="red">Aus</font>{% endif %} | | Inverter erreichbar: | {% if states('binary_sensor.hms_800_2t_reachable') == 'on' %}<font color="green">An</font>{% else %}<font color="red">Aus</font>{% endif %} | | SoC Speicher: | **{{ states('sensor.solarflow_solarflow_electriclevel') | int }} %** ({% if states('sensor.solarflow_pv_system_packstate') == '0' %}Standby{% elif states('sensor.solarflow_pv_system_packstate') == '1' %}Lädt{% elif states('sensor.solarflow_pv_system_packstate') == '2' %}Entlädt{% else %}Unbekannter Status{% endif %}) | | {% endif %} | |
NodeRed: Nulleinspeisung automatisieren
Home Assistant bietet zwar ein leistungsstarkes Automatisierungspaket, das für die meisten Anwendungsfälle ausreichend ist, aber bei sehr komplexen Logiken und spezifischen Berechnungen stößt es an seine Grenzen. Für solche Fälle bevorzuge ich NodeRed. Die Visualisierung von Funktionen durch das Verdrahtungsprinzip macht Prozesse übersichtlich und leicht nachvollziehbar. NodeRed lässt sich direkt über den Add-On Store in Home Assistant installieren, was die Integration enorm erleichtert.
Im Zentrum meiner Logiksteuerung in NodeRed steht der Flow, der die Leistungsparameter für den Wechselrichter steuert.
Der Flow beginnt mit dem Auslesen der relevanten Entitäten durch den „get entities“ Node, welcher Statusmeldungen, Leistungswerte, Ereignisse und Parameter erfasst. Diese Daten werden mittels eines Timers regelmäßig abgerufen und zunächst in einem „join“ Node gesammelt. Die so aggregierten Daten werden anschließend in einem „function“ Node formatiert, der sie in ein verarbeitbares Array umwandelt. Ein weiterer „function“ Node nimmt sich dieser formatierten Daten an, berechnet den neuen Leistungswert des Wechselrichters und steuert dessen Aktivierung sowie Deaktivierung.
Ein optionaler Trigger sorgt zusätzlich dafür, dass der Wechselrichter einmal täglich – üblicherweise nachts – neu gestartet wird. Dieses Vorgehen habe ich implementiert, nachdem ich feststellte, dass der Wechselrichter nach einigen Tagen keine Verbindung mehr zur openDTU aufbaute; ein täglicher Neustart hat dieses Kommunikationsproblem effektiv behoben.
Funktionsplan Steuerlogik Nulleinspeisung
NodeRed Flow im JSON-Format
Meinen aktuellen NodeRed-Flow kannst du dir hier kopieren und bei dir im NodeRed importieren.
Wichtig: Beachte bitte die Hinweise und Kommentare im Flow. Für einen funktionsfähigen Flow solltest du die Entitätsnamen durch deine ersetzen.
1 |
[{"id":"5cf6489d8647b69b","type":"group","z":"0e707f1c81961f61","name":"Nulleinspeisung V1.1 07/2024","style":{"label":true},"nodes":["5739c3f29a1ea937","2a0d4e251064647e","43543a987662b3e9","fad7c9c2783c3c71","0fcfe0261c10f67b","f88f79c827a2930a","26d3c5306d0fef5a","a26c4f5925b4b643","ad417c320b10bec2","f04101965e727af7","a66ee53700d3b369","d6b25c71f48ed382","57723b0bd889f0a7","c30d48f36fd7725f","8e132e8321cb3baa","025246c4ded22275","4477233b9b0acab6","6dd893d2c26e82bd"],"x":64,"y":633,"w":1768,"h":934},{"id":"5739c3f29a1ea937","type":"inject","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Trigger Inverter Neustart","props":[{"p":"payload"}],"repeat":"","crontab":"00 00 * * *","once":false,"onceDelay":"6","topic":"","payload":"","payloadType":"date","x":1210,"y":720,"wires":[["deaadefc156e85aa"]]},{"id":"2a0d4e251064647e","type":"link in","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Trigger","links":["43543a987662b3e9"],"x":105,"y":800,"wires":[["0c751d1f7106fbac","7bc91d8fa3f7b22e","a40310948a72c042","76ebd024cdeebcd2"]]},{"id":"43543a987662b3e9","type":"link out","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Trigger","mode":"link","links":["2a0d4e251064647e","a26c4f5925b4b643","ad417c320b10bec2"],"x":565,"y":700,"wires":[]},{"id":"fad7c9c2783c3c71","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Parameter","style":{"label":true},"nodes":["32b1de89d46895e9","aefb0da329db14a4","e1d732b9ed882ed0","19be0c6bf86240de","ba1bdf21e0e554c0","c446955a546e1dfe","63dba39c9a6e7814","18357dd483a9022e"],"x":154,"y":1179,"w":432,"h":362},{"id":"32b1de89d46895e9","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Minimale Leistung Nulleinspeisung Wechselrichter","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.minimale_leistung_nulleinspeisung_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":370,"y":1420,"wires":[["f04101965e727af7"]]},{"id":"aefb0da329db14a4","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Ausschaltschwelle Inverter ","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.ausschaltschwelle_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":300,"y":1220,"wires":[["f04101965e727af7"]]},{"id":"e1d732b9ed882ed0","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Einschaltschwelle Inverter ","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.einschaltschwelle_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":290,"y":1260,"wires":[["f04101965e727af7"]]},{"id":"19be0c6bf86240de","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Maximale Ausgangsleistung Inverter ","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.maximale_ausgangsleistung_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":330,"y":1460,"wires":[["f04101965e727af7"]]},{"id":"ba1bdf21e0e554c0","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Maximale Leistung Nulleinspeisung Wechselrichter","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.maximale_leistung_nulleinspeisung_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":370,"y":1380,"wires":[["f04101965e727af7"]]},{"id":"c446955a546e1dfe","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Maximale Leistung wenn SoC 100%","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.maximale_leistung_wenn_soc_100","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":330,"y":1340,"wires":[["f04101965e727af7"]]},{"id":"63dba39c9a6e7814","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Status Nulleinspeisung","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_boolean.status_nulleinspeisung","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":280,"y":1300,"wires":[["f04101965e727af7"]]},{"id":"18357dd483a9022e","type":"ha-get-entities","z":"0e707f1c81961f61","g":"fad7c9c2783c3c71","name":"Statische Leistung Wechselrichter","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"input_number.statische_leistung_wechselrichter","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":320,"y":1500,"wires":[["f04101965e727af7"]]},{"id":"fb0d40e8.e8f66","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true},{"id":"0fcfe0261c10f67b","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Verbrauch und Erzeugung","style":{"label":true},"nodes":["3ce80d6582b527a8","78fd2c7b96fe5927","85a6d7868c6e9362"],"x":154,"y":979,"w":392,"h":182},{"id":"3ce80d6582b527a8","type":"ha-get-entities","z":"0e707f1c81961f61","g":"0fcfe0261c10f67b","name":"Strombedarf (netto)","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"sensor.power_consumption","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":270,"y":1020,"wires":[["d6b25c71f48ed382"]]},{"id":"78fd2c7b96fe5927","type":"ha-get-entities","z":"0e707f1c81961f61","g":"0fcfe0261c10f67b","name":"Gesamtleistung weiterer Erzeugungsanlage","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"sensor.power_pv_2","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":350,"y":1120,"wires":[["d6b25c71f48ed382"]]},{"id":"85a6d7868c6e9362","type":"comment","z":"0e707f1c81961f61","g":"0fcfe0261c10f67b","name":"optional","info":"","x":230,"y":1080,"wires":[]},{"id":"f88f79c827a2930a","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Status Wechselrichter / Batterie / openDTU","style":{"label":true},"nodes":["0c751d1f7106fbac","7bc91d8fa3f7b22e","76ebd024cdeebcd2","a40310948a72c042"],"x":154,"y":759,"w":292,"h":202},{"id":"0c751d1f7106fbac","type":"ha-get-entities","z":"0e707f1c81961f61","g":"f88f79c827a2930a","name":"Status openDTU","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"binary_sensor.opendtu_168e58_status","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":270,"y":800,"wires":[["57723b0bd889f0a7"]]},{"id":"7bc91d8fa3f7b22e","type":"ha-get-entities","z":"0e707f1c81961f61","g":"f88f79c827a2930a","name":"Status Ladung Batterie","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"sensor.solarflow_solarflow_electriclevel","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":280,"y":840,"wires":[["57723b0bd889f0a7"]]},{"id":"76ebd024cdeebcd2","type":"ha-get-entities","z":"0e707f1c81961f61","g":"f88f79c827a2930a","name":"Status Inverter Erreichbarkeit","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"binary_sensor.hms_800_2t_reachable","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":300,"y":920,"wires":[["57723b0bd889f0a7"]]},{"id":"a40310948a72c042","type":"ha-get-entities","z":"0e707f1c81961f61","g":"f88f79c827a2930a","name":"Status Inverter Produktion","server":"fb0d40e8.e8f66","version":1,"rules":[{"property":"entity_id","logic":"includes","value":"binary_sensor.hms_800_2t_producing","valueType":"str"}],"outputType":"split","outputEmptyResults":false,"outputLocationType":"msg","outputLocation":"payload","outputResultsCount":1,"x":290,"y":880,"wires":[["57723b0bd889f0a7"]]},{"id":"26d3c5306d0fef5a","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Trigger","style":{"label":true},"nodes":["5ce3ae4f23192d41","eed002ece4224a0a"],"x":154,"y":659,"w":352,"h":82},{"id":"5ce3ae4f23192d41","type":"server-state-changed","z":"0e707f1c81961f61","g":"26d3c5306d0fef5a","name":"Event Trigger","server":"fb0d40e8.e8f66","version":5,"outputs":1,"exposeAsEntityConfig":"","entityId":"input_number.trigger_nulleinspeisung","entityIdType":"exact","outputInitially":true,"stateType":"num","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":250,"y":700,"wires":[["eed002ece4224a0a"]]},{"id":"eed002ece4224a0a","type":"function","z":"0e707f1c81961f61","g":"26d3c5306d0fef5a","name":"Trigger Timer","func":"let triggerTime = parseFloat(msg.payload); // Zeit in Sekunden aus dem input\nlet timerId = flow.get('timerId') || null; // Holen des Timer-IDs aus dem Flow-Kontext\nlet endTime = flow.get('endTime') || Date.now() + triggerTime * 1000; // Endzeit aus Flow-Kontext oder neu berechnen\n\n// Bestehenden Timer löschen, falls vorhanden\nif (timerId) {\n clearInterval(timerId);\n}\n\n// Funktion zur Aktualisierung des Node-Status\nfunction updateCountdown() {\n let remainingTime = Math.ceil((endTime - Date.now()) / 1000);\n if (remainingTime > 0) {\n node.status({fill:\"red\", shape:\"ring\", text:`Trigger in ${remainingTime}s`});\n } else {\n node.status({fill:\"green\", shape:\"dot\", text:\"Triggered\"});\n endTime = Date.now() + triggerTime * 1000; // Neu berechnen des Endzeitpunkts für kontinuierliche Wiederholungen\n node.send({payload: true}); // Sende 'true' bei Ablauf des Timers\n }\n}\n\n// Setzen des Intervall-Timers\ntimerId = setInterval(() => {\n updateCountdown();\n}, 1000); // Jede Sekunde aktualisieren\n\n// Speichern des Timer-IDs und des Endzeitpunkts im Flow-Kontext\nflow.set('timerId', timerId);\nflow.set('endTime', endTime);\n\n// Initialer Aufruf zur Statusaktualisierung\nupdateCountdown();\n\nreturn null; // Keine direkte Nachrichtenausgabe\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":700,"wires":[["43543a987662b3e9"]]},{"id":"a26c4f5925b4b643","type":"link in","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Trigger","links":["43543a987662b3e9"],"x":105,"y":1020,"wires":[["3ce80d6582b527a8","78fd2c7b96fe5927"]]},{"id":"ad417c320b10bec2","type":"link in","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Trigger","links":["43543a987662b3e9"],"x":105,"y":1220,"wires":[["aefb0da329db14a4","e1d732b9ed882ed0","63dba39c9a6e7814","c446955a546e1dfe","ba1bdf21e0e554c0","32b1de89d46895e9","19be0c6bf86240de","18357dd483a9022e"]]},{"id":"f04101965e727af7","type":"link out","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Data","mode":"link","links":["a66ee53700d3b369"],"x":605,"y":1220,"wires":[]},{"id":"a66ee53700d3b369","type":"link in","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Data","links":["f04101965e727af7","d6b25c71f48ed382","57723b0bd889f0a7"],"x":705,"y":860,"wires":[["da4a6644ae945f11"]]},{"id":"d6b25c71f48ed382","type":"link out","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Data","mode":"link","links":["a66ee53700d3b369"],"x":605,"y":1020,"wires":[]},{"id":"57723b0bd889f0a7","type":"link out","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Event Data","mode":"link","links":["a66ee53700d3b369"],"x":565,"y":800,"wires":[]},{"id":"c30d48f36fd7725f","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Ausgabe","style":{"label":true},"nodes":["73a77c3a1b8dcd3b","eaca7ff6ffe255c2","d6a84d3510a6591c","869eb6e1e644148a","d19f162282674090","794b544f9a7bccb9","15249236be519140","deaadefc156e85aa","3fabccf01b3b555c","d0526407edeba38b","d5e55fc7c6210855"],"x":1414,"y":679,"w":392,"h":422},{"id":"73a77c3a1b8dcd3b","type":"debug","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"WR Limit","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1700,"y":820,"wires":[]},{"id":"eaca7ff6ffe255c2","type":"api-call-service","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Inverter AN","server":"fb0d40e8.e8f66","version":5,"debugenabled":false,"domain":"button","service":"press","areaId":[],"deviceId":[],"entityId":["button.hms_800_2t_turn_inverter_on"],"data":"{}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1510,"y":880,"wires":[["869eb6e1e644148a"]]},{"id":"d6a84d3510a6591c","type":"api-call-service","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Inverter AUS","server":"fb0d40e8.e8f66","version":5,"debugenabled":false,"domain":"button","service":"press","areaId":[],"deviceId":[],"entityId":["button.hms_800_2t_turn_inverter_off"],"data":"{}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1510,"y":940,"wires":[["d19f162282674090"]]},{"id":"869eb6e1e644148a","type":"debug","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"WR AN","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1700,"y":880,"wires":[]},{"id":"d19f162282674090","type":"debug","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"WR AUS","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1700,"y":940,"wires":[]},{"id":"794b544f9a7bccb9","type":"api-call-service","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Inverter Limit","server":"fb0d40e8.e8f66","version":5,"debugenabled":false,"domain":"number","service":"set_value","areaId":[],"deviceId":[],"entityId":["number.hms_800_2t_limit_nonpersistent_relative"],"data":"{\"value\":\"{{payload}}\"}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1510,"y":820,"wires":[["73a77c3a1b8dcd3b"]]},{"id":"15249236be519140","type":"debug","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"WR RST","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1700,"y":720,"wires":[]},{"id":"deaadefc156e85aa","type":"api-call-service","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Inverter Neustart","server":"fb0d40e8.e8f66","version":5,"debugenabled":false,"domain":"button","service":"press","areaId":[],"deviceId":[],"entityId":["button.hms_800_2t_restart_inverter"],"data":"{}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"Neustart Wechselrichter","valueType":"str"}],"queue":"none","x":1530,"y":720,"wires":[["15249236be519140"]]},{"id":"3fabccf01b3b555c","type":"debug","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Debug","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1490,"y":1000,"wires":[]},{"id":"d0526407edeba38b","type":"link out","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"logFileMsg","mode":"link","links":["6f5efb4c79c63240"],"x":1455,"y":1060,"wires":[]},{"id":"d5e55fc7c6210855","type":"comment","z":"0e707f1c81961f61","g":"c30d48f36fd7725f","name":"Limit setzen mit \"nonpersistent_relative\"","info":"","x":1590,"y":780,"wires":[]},{"id":"8e132e8321cb3baa","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Berechnung","style":{"label":true},"nodes":["da4a6644ae945f11","619d1bef4f2cbbc8","4e69b641146d3315","e05954adb9bf01d7"],"x":734,"y":759,"w":612,"h":164.5},{"id":"da4a6644ae945f11","type":"join","z":"0e707f1c81961f61","g":"8e132e8321cb3baa","name":"join","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"2","count":"14","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":810,"y":860,"wires":[["e05954adb9bf01d7"]]},{"id":"619d1bef4f2cbbc8","type":"comment","z":"0e707f1c81961f61","g":"8e132e8321cb3baa","name":"Anpassung für join und Datenformatierung notwendig","info":"","x":960,"y":800,"wires":[]},{"id":"4e69b641146d3315","type":"function","z":"0e707f1c81961f61","g":"8e132e8321cb3baa","name":"Steuerlogik Nulleinspeisung","func":"// Definier Funktion zur Erstellung der Log-Nachricht\nfunction createLogFileMsg(dtuState, invStateProducing, invStateReachable, statusZeroInjection, pwrConsumption, pwrSecondSource, socLevelBattery, setPercentMsg, turnOnMsg, turnOffMsg, debugMsg) {\n const now = new Date();\n const formattedTime = now.toLocaleString('de-DE', { hour12: false }); // Formatiert Zeit als 'Tag.Monat.Jahr Stunden:Minuten:Sekunden'\n\n // Konvertiert Zahlenwerte zu Strings mit Komma als Dezimaltrennzeichen\n const formattedPwrConsumption = pwrConsumption.toLocaleString('de-DE');\n const formattedPwrSecondSource = pwrSecondSource.toLocaleString('de-DE');\n \n return {\n payload: {\n \"time\": formattedTime,\n \"dtuState\": dtuState,\n \"invStateProducing\": invStateProducing,\n \"invStateReachable\": invStateReachable,\n \"statusZeroInjection\": statusZeroInjection,\n \"pwrConsumption\": formattedPwrConsumption,\n \"pwrSecondSource\": formattedPwrSecondSource,\n \"socLevelBattery\": socLevelBattery,\n \"setPercentMsg\": setPercentMsg ? setPercentMsg.payload : null,\n \"turnOnMsg\": turnOnMsg ? turnOnMsg.payload : null,\n \"turnOffMsg\": turnOffMsg ? turnOffMsg.payload : null,\n \"debugMsg\": debugMsg.payload\n }\n };\n}\n\n// Definiert min und max Prozentwerte für die DTU-Ausgangsleistung\nconst maxOutputPowerInv = parseFloat(msg.payload.maxOutputPowerInv); // Maximale Ausgangsleistung des Wechselrichters in Watt\nconst pwrSteps = maxOutputPowerInv / 100; // Berechnet die Leistung pro Prozent\nconst minOutputZeroInjection = parseFloat(msg.payload.minOutputZeroInjection); // Minimale Leistung in Prozent bei aktivierter Nulleinspeisung\nconst maxOutputZeroInjection = parseFloat(msg.payload.maxOutputZeroInjection); // Maximale Leistung in Prozent bei aktivierter Nulleinspeisung\nconst maxOutputAtFullSoc = parseFloat(msg.payload.maxOutputAtFullSoc); // Maximale Ausgangsleistung in Prozent bei vollem Batterie-SoC\nconst staticInverterOutputPower = parseFloat(msg.payload.staticInverterOutputPower); // Voreingestellte Ausgangsleistung, wenn Nulleinspeisung deaktiviert ist\nconst minPowerInverter = minOutputZeroInjection * pwrSteps; // Berechnet die minimale Leistung in Watt, basierend auf dem Prozentwert und den Leistungsschritten\n\n// Definiert Schwellenwerte für den Batterie-SoC\nconst offThresholdInv = parseFloat(msg.payload.offThresholdInv); // Batterie-SoC-Schwelle zum Ausschalten des Wechselrichters\nconst onThresholdInv = parseFloat(msg.payload.onThresholdInv); // Batterie-SoC-Schwelle zum Einschalten des Wechselrichters\n\n// Extrahiert Daten aus msg.payload für Steuerungsentscheidungen\nconst dtuState = msg.payload.dtuState; // Der aktuelle Betriebszustand der DTU (Datenübertragungseinheit)\nconst pwrSecondSource = parseFloat(msg.payload.pwrSecondSource); // Leistung der zweiten Energiequelle in Watt\nconst pwrConsumption = parseFloat(msg.payload.pwrConsumption); // Aktueller Gesamtstromverbrauch in Watt\nconst invStateProducing = msg.payload.invStateProducing; // Gibt an, ob der Wechselrichter aktuell Strom produziert\nconst invStateReachable = msg.payload.invStateReachable; // Verfügbarkeitsstatus des Wechselrichters\nconst socLevelBattery = parseFloat(msg.payload.socLevelBattery); // Der aktuelle Ladezustand der Batterie in Prozent\nconst statusZeroInjection = msg.payload.statusZeroInjection; // Aktueller Status der Nulleinspeisung ('on' oder 'off')\n\n// Entscheidungslogik für die Ausgabe der Befehle basierend auf dem Zustand und den Messdaten\nlet setPercentMsg = null;\nlet turnOnMsg = null;\nlet turnOffMsg = null;\nlet debugMsg = null;\n\n// Steuerung basierend auf dem Status der Nulleinspeisung\nif (statusZeroInjection !== \"on\") {\n if (invStateProducing === \"on\") {\n setPercentMsg = { payload: staticInverterOutputPower };\n debugMsg = { payload: \"Nulleinspeisung deaktiviert, statische Leistung angewendet\" };\n } else {\n debugMsg = { payload: \"Nulleinspeisung deaktiviert, Wechselrichter aus\" };\n }\n const logFileMsg = createLogFileMsg(dtuState, invStateProducing, invStateReachable, statusZeroInjection, pwrConsumption, pwrSecondSource, socLevelBattery, setPercentMsg, turnOnMsg, turnOffMsg, debugMsg);\n return [setPercentMsg, turnOnMsg, turnOffMsg, debugMsg, logFileMsg];\n} else {\n debugMsg = { payload: \"Nulleinspeisung aktiviert\" };\n}\n\n// Überprüft die Erreichbarkeit und Betriebsbereitschaft der Systemkomponenten\nif (dtuState !== \"on\" || invStateReachable !== \"on\") {\n debugMsg = { payload: `DTU offline oder Wechselrichter nicht erreichbar` };\n const logFileMsg = createLogFileMsg(dtuState, invStateProducing, invStateReachable, statusZeroInjection, pwrConsumption, pwrSecondSource, socLevelBattery, setPercentMsg, turnOnMsg, turnOffMsg, debugMsg);\n return [null, null, null, debugMsg, logFileMsg];\n} else {\n debugMsg = { payload: `DTU und Wechselrichter sind online` };\n}\n\n// Berechnet die erforderliche Leistungskorrektur basierend auf dem aktuellen Verbrauch und der Zweitquelle\nlet powerDifference = pwrConsumption - pwrSecondSource;\n\n// Steuerung des Wechselrichters basierend auf dem Batterie-SoC und der Differenzleistung\nif (socLevelBattery <= offThresholdInv && invStateProducing === \"on\") {\n turnOffMsg = { payload: \"OFF\" };\n const logFileMsg = createLogFileMsg(dtuState, invStateProducing, invStateReachable, statusZeroInjection, pwrConsumption, pwrSecondSource, socLevelBattery, setPercentMsg, turnOnMsg, turnOffMsg, debugMsg);\n return [setPercentMsg, turnOnMsg, turnOffMsg, debugMsg, logFileMsg];\n} else {\n // Zuerst wird überprüft, ob der Wechselrichter Strom produziert\n if (invStateProducing === \"on\") {\n if (powerDifference < minPowerInverter) {\n // Sendet ein Signal, um den Wechselrichter auszuschalten, falls die Differenzleistung unter dem Mindestniveau liegt\n turnOffMsg = { payload: \"OFF\" };\n } else {\n // Berechnet den erforderlichen Leistungsprozentsatz, wenn keine Ausschaltanforderung vorliegt\n let requiredPercent = Math.floor(powerDifference / pwrSteps);\n let effectiveMaxOutput = socLevelBattery === 100 ? maxOutputAtFullSoc : maxOutputZeroInjection;\n requiredPercent = Math.max(minOutputZeroInjection, Math.min(requiredPercent, effectiveMaxOutput));\n setPercentMsg = { payload: requiredPercent };\n }\n } else if (socLevelBattery >= onThresholdInv && powerDifference >= minPowerInverter) {\n // Überprüft, ob der Batterie-SoC oberhalb des Schwellenwertes liegt und die Differenzleistung ausreichend ist\n let requiredPercent = Math.floor(powerDifference / pwrSteps);\n let effectiveMaxOutput = socLevelBattery === 100 ? maxOutputAtFullSoc : maxOutputZeroInjection;\n requiredPercent = Math.max(minOutputZeroInjection, Math.min(requiredPercent, effectiveMaxOutput));\n setPercentMsg = { payload: requiredPercent };\n turnOnMsg = { payload: \"ON\" };\n } else {\n // Keine Aktion erforderlich, da der Wechselrichter aus ist und die Bedingungen zum Einschalten nicht erfüllt sind\n debugMsg = { payload: \"Wechselrichter bleibt aus - Bedingungen zum Einschalten nicht erfüllt\" };\n }\n}\n\nconst logFileMsg = createLogFileMsg(dtuState, invStateProducing, invStateReachable, statusZeroInjection, pwrConsumption, pwrSecondSource, socLevelBattery, setPercentMsg, turnOnMsg, turnOffMsg, debugMsg);\n// Rückgabe der Steuerbefehle\nreturn [setPercentMsg, turnOnMsg, turnOffMsg, debugMsg, logFileMsg];","outputs":5,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":860,"wires":[["794b544f9a7bccb9"],["eaca7ff6ffe255c2"],["d6a84d3510a6591c"],["3fabccf01b3b555c"],["d0526407edeba38b"]]},{"id":"e05954adb9bf01d7","type":"function","z":"0e707f1c81961f61","g":"8e132e8321cb3baa","name":"Daten formatieren","func":"// ENTITY_IDS: An dieser Stelle sind alle Entitätsnamen aufgelistet, die aus dem Home Assistant abgefragt werden.\n// Ändere die Werte der Schlüssel, falls die Entitätsnamen in deiner Home Assistant-Konfiguration anders sind.\nconst ENTITY_IDS = {\n DTU_STATUS: \"binary_sensor.opendtu_168e58_status\",\n POWER_SECOND_SOURCE: \"sensor.power_pv_2\", // Entität durch leeren String ersetzt (POWER_SECOND_SOURCE: \"\"), wenn keine weitere Erzeugungsanlage vorhanden ist.\n POWER_CONSUMPTION: \"sensor.power_consumption\",\n SOLARFLOW_ELECTRIC_LEVEL: \"sensor.solarflow_solarflow_electriclevel\",\n INVERTER_PRODUCING: \"binary_sensor.hms_800_2t_producing\",\n INVERTER_REACHABLE: \"binary_sensor.hms_800_2t_reachable\",\n INVERTER_OFF_THRESHOLD: \"input_number.ausschaltschwelle_wechselrichter\",\n INVERTER_ON_THRESHOLD: \"input_number.einschaltschwelle_wechselrichter\",\n INVERTER_MAX_OUTPUT_POWER: \"input_number.maximale_ausgangsleistung_wechselrichter\",\n INVERTER_MAX_OUTPUT_AT_FULL_SOC: \"input_number.maximale_leistung_wenn_soc_100\",\n INVERTER_MAX_ZERO_INJECTION: \"input_number.maximale_leistung_nulleinspeisung_wechselrichter\",\n INVERTER_MIN_ZERO_INJECTION: \"input_number.minimale_leistung_nulleinspeisung_wechselrichter\",\n STATUS_ZERO_INJECTION: \"input_boolean.status_nulleinspeisung\",\n INVERTER_STATIC_OUTPUT_POWER: \"input_number.statische_leistung_wechselrichter\"\n};\n\n// nameMapping: Mapping von technischen Entitäts-IDs zu benutzerfreundlichen Schlüsselnamen.\nconst nameMapping = {\n [ENTITY_IDS.DTU_STATUS]: \"dtuState\",\n [ENTITY_IDS.POWER_SECOND_SOURCE]: \"pwrSecondSource\",\n [ENTITY_IDS.POWER_CONSUMPTION]: \"pwrConsumption\",\n [ENTITY_IDS.SOLARFLOW_ELECTRIC_LEVEL]: \"socLevelBattery\",\n [ENTITY_IDS.INVERTER_PRODUCING]: \"invStateProducing\",\n [ENTITY_IDS.INVERTER_REACHABLE]: \"invStateReachable\",\n [ENTITY_IDS.INVERTER_OFF_THRESHOLD]: \"offThresholdInv\",\n [ENTITY_IDS.INVERTER_ON_THRESHOLD]: \"onThresholdInv\",\n [ENTITY_IDS.INVERTER_MAX_OUTPUT_POWER]: \"maxOutputPowerInv\",\n [ENTITY_IDS.INVERTER_MAX_OUTPUT_AT_FULL_SOC]: \"maxOutputAtFullSoc\",\n [ENTITY_IDS.INVERTER_MAX_ZERO_INJECTION]: \"maxOutputZeroInjection\",\n [ENTITY_IDS.INVERTER_MIN_ZERO_INJECTION]: \"minOutputZeroInjection\",\n [ENTITY_IDS.STATUS_ZERO_INJECTION]: \"statusZeroInjection\",\n [ENTITY_IDS.INVERTER_STATIC_OUTPUT_POWER]: \"staticInverterOutputPower\"\n};\n\n// Eingabearray von msg.payload\nlet dataArray = msg.payload;\n\n// Initialisierung der sortierten Daten\nlet sortedData = {};\nlet missingDataWarnings = [];\n\n// Verarbeiten des Eingabearrays\ndataArray.forEach(item => {\n let entityId = item.entity_id;\n if (nameMapping[entityId]) {\n let key = nameMapping[entityId];\n sortedData[key] = item.state; // Hier extrahieren wir nur den 'state' aus dem Item\n }\n});\n\n// Überprüfung, ob alle erforderlichen Schlüssel vorhanden sind und ob Warnungen notwendig sind\nObject.keys(ENTITY_IDS).forEach(key => {\n let entityId = ENTITY_IDS[key];\n let mappedKey = nameMapping[entityId];\n if (!sortedData[mappedKey] && entityId) {\n if (key !== \"POWER_SECOND_SOURCE\" || entityId !== \"\") {\n missingDataWarnings.push(mappedKey || key);\n }\n }\n});\n\n// Setze den Standardwert für pwrSecondSource, wenn keine entsprechenden Daten vorhanden sind\nif (!sortedData[\"pwrSecondSource\"]) {\n sortedData[\"pwrSecondSource\"] = \"0\"; // Stellen Sie sicher, dass auch hier nur der Wert '0' gesetzt wird\n}\n\n// Warnmeldungen senden, falls erforderlich\nif (missingDataWarnings.length > 0) {\n node.warn(\"Fehlende Daten für: \" + missingDataWarnings.join(\", \"));\n node.status({ fill: \"red\", shape: \"dot\", text: \"Fehlende Daten!\" });\n} else {\n // Setze den Node-Status auf grün, um anzuzeigen, dass alle Daten gültig und vorhanden sind\n node.status({ fill: \"green\", shape: \"dot\", text: \"Daten gültig!\" });\n // Sende die sortierten und zusammengefassten Daten\n node.send({ payload: sortedData });\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":970,"y":860,"wires":[["4e69b641146d3315"]]},{"id":"025246c4ded22275","type":"comment","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Inverterneustart 1x/Tag","info":"","x":1180,"y":680,"wires":[]},{"id":"4477233b9b0acab6","type":"inject","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":720,"y":680,"wires":[["43543a987662b3e9"]]},{"id":"6dd893d2c26e82bd","type":"group","z":"0e707f1c81961f61","g":"5cf6489d8647b69b","name":"Log Datei","style":{"label":true},"nodes":["7c727b9349a66777","efb0f1e0854ccaea","9ff941bd037f63ee","aa395729d6395a93","2f2b36091f58c9f7","6f5efb4c79c63240"],"x":1224,"y":1119,"w":582,"h":182},{"id":"7c727b9349a66777","type":"inject","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"Reset Spaltennamen","props":[{"p":"payload"}],"repeat":"","crontab":"59 23 * * 0","once":false,"onceDelay":"6","topic":"","payload":"time;dtuState;invStateProducing;invStateReachable;statusZeroInjection;pwrConsumption;pwrSecondSource;socLevelBattery;setPercentMsg;turnOnMsg;turnOffMsg;debugMsg","payloadType":"str","x":1400,"y":1260,"wires":[["9ff941bd037f63ee"]]},{"id":"efb0f1e0854ccaea","type":"comment","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"Überschreibe Log Datei 1x/Woche","info":"","x":1440,"y":1220,"wires":[]},{"id":"9ff941bd037f63ee","type":"file","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"logFileMsg_Nulleinspeisung.csv","filename":"/share/logFileMsg_Nulleinspeisung.csv","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":1650,"y":1260,"wires":[[]]},{"id":"aa395729d6395a93","type":"csv","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"","sep":";","hdrin":true,"hdrout":"none","multi":"one","ret":"\\r\\n","temp":"time,dtuState,invStateProducing,invStateReachable,statusZeroInjection,pwrConsumption,pwrSecondSource,socLevelBattery,setPercentMsg,turnOnMsg,turnOffMsg,debugMsg","skip":"0","strings":false,"include_empty_strings":"","include_null_values":true,"x":1350,"y":1160,"wires":[["2f2b36091f58c9f7"]]},{"id":"2f2b36091f58c9f7","type":"file","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"logFileMsg_Nulleinspeisung.csv","filename":"/share/logFileMsg_Nulleinspeisung.csv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"false","encoding":"none","x":1650,"y":1160,"wires":[[]]},{"id":"6f5efb4c79c63240","type":"link in","z":"0e707f1c81961f61","g":"6dd893d2c26e82bd","name":"link in 23","links":["8bbbb468e7b475c8","d0526407edeba38b"],"x":1265,"y":1160,"wires":[["aa395729d6395a93"]]}] |
Entwicklungsstatus, Probleme und weitere Pläne
Mein Ansatz zur Dynamischen Nulleinspeisung befindet sich noch in einer frühen Entwicklungsphase und ist daher recht unerprobt. Derzeit arbeite ich intensiv daran, die Langzeitstabilität des Systems sicherzustellen. Die Herausforderungen sind vielfältig und stark abhängig von den spezifischen Systemkomponenten sowie der Fähigkeit des Herstellers, Daten kontinuierlich und zuverlässig bereitzustellen.
Stand heute gibt es Probleme mit der Hardware-Software-Konstellation des Zendure-Systems in Verbindung mit dem Bypass-Modus oder dem automatischen Tiefenentladen des Speichersystems zu Kalibrierungszwecken. Diese Abhängigkeiten sorgen, wenn auch nur sehr selten, für Probleme mit der Nulleinspeisungslogik. Ich hoffe, dass die Entwickler bei Zendure diese Probleme zeitnah beheben, denn dieses System ist aus meiner persönlichen Sicht ein sehr qualitatives, leistungsstarkes System.
Ein weiterer wichtiger Punkt meiner Entwicklungsarbeit ist die Optimierung der Nulleinspeisung. Ich bin dabei, die optimalen Grenzwerte zu ermitteln, um den Akku vollständig auszunutzen, ohne mit einem halbvollen Speicher in die nächsten Sonnenstunden am folgenden Tag zu starten. Zukünftig plane ich, dieses Problem durch die Integration weiterer Parameter, wie beispielsweise ein Solarforecast für die Produktion des nächsten Tages, zu adressieren.
Zusammenfassung
Zum Abschluss möchte ich euch für euer Interesse an meinem Projekt der Dynamischen Nulleinspeisung danken. Dieses System, obwohl es bereits in einer funktionierenden Form vorliegt, befindet sich noch in einer frühen Phase und wird stetig weiterentwickelt, um seine Zuverlässigkeit und Effektivität zu verbessern.
Nobody’s perfect! Ich ermutige euch, aktiv an der Diskussion teilzunehmen und eure Erfahrungen, Fragen oder Probleme im Kommentarbereich zu teilen. Euer direktes Feedback ist ungemein wertvoll und hilft mir, praxisnahe Anpassungen vorzunehmen und die Anwendung weiter zu optimieren.
Vielen Dank für eure Aufmerksamkeit und das Mitverfolgen der Entwicklungen.
FAQ
Geht mein Wechselrichter (HOYMILES) oder die PV Module durch eine gezielte Drosselung kaputt?
Antwort: Nein, eine gezielte Drosselung des Wechselrichters schadet weder dem Wechselrichter noch den PV-Modulen. Der Wechselrichter nutzt einen Maximum Power Point Tracker (MPPT), der die Leistung der PV-Module reguliert, um den optimalen Betriebspunkt zu finden. Bei einer Drosselung passt der MPPT die Parameter so an, dass die Module weniger Leistung produzieren, ohne dass überschüssige Energie in Wärme umgewandelt wird. Dies hat keine negativen Auswirkungen auf die Module, da sie innerhalb ihrer technischen Spezifikationen arbeiten und nicht überlastet werden. Die MPPT-Technologie optimiert die Effizienz der Module, indem sie stets den optimalen Arbeitspunkt wählt und dabei die Module vor möglichen schädlichen Bedingungen schützt. Somit wird die Lebensdauer und Zuverlässigkeit der Module nicht beeinträchtigt, auch wenn der Wechselrichter gedrosselt wird.
Wird durch das Setzen der Ausgangsleistung am Wechselrichter (HOYMILES) der interne Speicher oder sogar der Wechselrichter zerstört?
Antwort: Nein, jedoch gibt es wichtige Aspekte zu beachten. Die Ausgangsleistung des Wechselrichters kann über die openDTU mit zwei verschiedenen Parametern eingestellt werden: „permanent“ (persistent) und „nicht permanent“ (nonpersistent). Bei der Wahl des permanenten Parameters wird die Leistung dauerhaft im internen EEPROM-Speicher des Wechselrichters gesichert. Dieser Speichertyp hat technisch bedingt eine begrenzte Anzahl von Schreibzyklen, typischerweise zwischen 10.000 und 1.000.000. Ein häufiges Überschreiben dieser Einstellung könnte daher den Speicher über die Zeit abnutzen.
Um dies zu vermeiden, empfiehlt es sich, den nicht permanenten Parameter zu nutzen. Dieser speichert die Ausgangsleistung im flüchtigen Speicher, wo die Anzahl der Schreibvorgänge keinen Einfluss auf die Lebensdauer hat. Wird der Wechselrichter stromlos gemacht, greift er beim Neustart automatisch auf den zuletzt im EEPROM gespeicherten permanenten Wert zurück. So bleibt die gewünschte Leistungseinstellung erhalten, ohne den Speicher unnötig zu belasten.
Hallo,
mit großem Interesse habe ich deinen Beitrag gelesen und freue mich schon auf die Umsetzung, wenn wir in unseren Altbau umgezogen sind. Eine Frage habe ich dazu: Du benutzt ja Hoymiles-Komponenten. Ich plane die Beschaffung eines Anker Solix Pro. Im Prinzip muss das ja gleichermaßen funktionieren. Ich frage mich nur, auch bei der Hoymiles-Anlage, ob der Wechselrichter überschüssigen Strom automatisch einspeichert. Ich versuche mal ein Beispiel: Der WR produziert 800 W oder mehr. Du benötigt im Haushalt aber gerade nur 300 W. Speichert der WR nun die restliche Leistung automatische in den Speicher, oder steuerst du dies auch aktiv?
Hallo Birger,
erstmal vielen Dank für dein Interesse. 🙂
Also bei meinem System ist es wie folgt. Beispiel einfach dargestellt:
PV Module generieren 800W, Haus verbraucht 200W, bleiben 600W überschüssige Leistung. Nun wird die Leistung des Wechselrichters auf 200W begrenzt, so werden nun 600W Überschuss in den Akku gespeist.
Meine Funktion überprüft also ständig die benötigte Leistung und regelt aktiv den Wechselrichter mittels openDTU.
Ziel ist es, den Überschuss immer in den Akku zu speichern.
Ob der Anker eine dynamische Leistungsregelung ermöglicht kann ich dir jedoch nicht sagen, kann morgen aber gerne schauen welche Möglichkeiten zur Verfügung stehen.
Viele Grüße
Martin
Hallo
Super Anleitung.
Geht das ganze auch wenn ich Zwei oder Drei Wechselrichter einsetze?
Vielen Dank für den sehr interessanten Beitrag. Mit meinem Smart-CT-Modus vom Zendure-Hub bin ich schon sehr nah an der Nulleinspeisung, bin aber mit 1600 Nennleistung der Module und 3840 kWh minus 20% Sicherheit der Speicher bei max. 800W in einer Größenordnung eines reaktionsfähigen Systems. In der Sommerhälfte lief alles gut, in der Winterhälfte muss aber auf die konsequente Akkuschonung geachtet werden, also Vermeidung des ständigen Wechsels zwischen Laden und Verbrauch. Als Notallmaßnahme zur Vermeidung des Flipflops habe ich auf Akkuprioritätsmodus umgestellt. Mein Konzept geht aber dahin, dass der Akku auf Akkuprioritätsmodus läuft bis entweder 100% oder Sonnenuntergang erreicht wird, um dann nachts bis Sonnenaufgang bzw. erste Überschreitung einer Grundlastschwelle rein auf Verbrauch im Smart-CT-Modus läuft. Im Moment kämpfe ich als Einsteiger noch mit Basics, wie mit der Einbindung meines PI5 und MQTT-Steuerung meines Hubs. Aber bis Jahresende soll die angedachte Automatik flutschen.
Kleine Ergänzung: Natürlich braucht man eine Kontrolle und hierfür eine Visualisierung. Aber am Ende soll das System vollautomatisch und zuverlässig im Hintergrund laufen. Ich habe keine Lust an ständiger Überwachung. Mir reicht die Protokollierung und Archivierung der Verläufe von Akkustand, Gesamtverbrauch und Einspeisung um die Systemstabilität von Zeit zu Zeit zu überwachen.
Hi Peter
Super Beitrag. Aber eine Frage hätte ich . Ich würd mir den Hoymiles Wechselrichter HMS-1600-4T kaufen und eine Hoymiles DTU-WLite-S Datenübertragungseinheit .
Ich hab keinen Speicher oder ähnliches. Über Home assistant würd ich den Wechselrichter & meinen Smartmeter über einen IR-Leseeinheit (Tasmota) einbinden und versuchen ihr Vorgehen an meine gegebenheiten anzupassen.
Hier die Frage. Sie sagen es gibt einen Permanenten und none Permanentes Register für die Ausgangsleistung.
können wir mir sagen in welcher Dokumentation sie dies gefunden haben? oder mir sagen wie die Registereinträge heißten 🙂 .
Gruß Tobi
Hi Martin 😀 wollte ich schreiben 🙂
Hi Tobi,
danke für deinen positiven Kommentar. 😉
Dein Vorhaben klingt erstmal sehr spannend, jedoch ist mir noch nicht ganz klar, wie man mit dem DTU-WLite-S ein Register beschreiben kann.
Die Entwickler der openDTU haben sich bereits um die Kommunikation mit dem Wechselrichter gekümmert. Eine eventuelle Registeradresse für das permanente und nicht permanente Schreiben der Leistungsanpassung wäre in meinen Augen nur möglich herauszufinden, wenn du in den Sourcecode bei Github schaust.
Falls ich etwas falsch verstanden habe, dann kannst du deine Frage gerne etwas detaillierter stellen. 🙂
Grüße Martin
Hallo Martin,
ich bin auf deinen sehr interessanten Beitrag in deinem Block zur Nulleinspeisung gestoßen und das hat mich neugierig gemacht. Ich habe deine Nulleinspeisung in mein Home Assistent übernommen und muss sagen das Sie erstmal funktioniert. Mein Anlagenaufbau unterscheidet sich etwas von deiner und die Nulleinspeisung müsste für meinen Fall etwas angepasst werden.
Ich betriebe mein Balkonkraftwerk mit einen Hoymiles Wechselrichter HMS 1800-4T an den Eingängen sind einmal der Zendure Smart PV Hub 2000 mit zwei Speichern zu je 2000W angeschlossen. An den zwei freien Eingängen habe ich zur Abdeckung des Tagesbedarf zwei weitere Solarpanel angeschlossen.
Im Tagesbereich wenn alles normal läuft arbeitet die Regelung erstmal wie sie soll würde ich sagen.
Allerdings ist mir in meinem Aufbau aufgefallen, dass der Wechselrichter sich im Nachtbereich etwas anders verhält. Hier liegt an zwei Eingängen des Wechselrichters nun keine Spannung mehr an und es sind nur noch zwei Eingänge aktiv. Nun kann ich nicht mehr die benötigte Leistung dem Haus zur Verfügung stellen, da der Wechselrichter nicht den AC Ausgang zum Netz als gesamtes drosselt, sondern die benötigte Leistung durch die vier Eingänge teilt. Nehmen wir mal an ich benötige 600W im Haus erkennt das System das und gibt dem Wechselrichter 600W vor. Soweit so gut. Jetzt können aber aus den Batterien aufgrund der 600W Drosselung nur noch 300W abgeben werden.
Dazu habe ich mir ein paar Gedanken gemacht. Könnte man in die Parameter und Informationskarte noch weitere Felder implementieren mit den man einen festen Offset vorgeben für den Nachtbereich vorgeben kann, wenn zwei der vier Eingänge eine Leistung z.B. kleiner 10W ausgeben.
Des Weitern ging meine Überlegung dahin ein weiteres Feld für die Schaltschwelle des Offsets zu schaffen. Die Schaltschwelle der Leistung an den Eingängen müsste über einen weiteren Reiter in der Parameterkarte vorwählbar gemacht werden. So könnte man den Nachtbedarft optimal anpassen. Meinst du das wäre möglich?
Da ich noch nicht lange im Home Assistent unterwegs bin wäre ich über ein paar Gedankenanstöße dankbar.
Hallo Martin,
Komme leider nicht weiter,da keine Ahnung und Erfahrung da ist,sorry
ChatGPT sagt:Um das Problem zu finden, könntest du folgende Schritte ausführen:
Überprüfe deine gesamte YAML-Konfigurationsdatei und suche nach allen Referenzen zu input_number.trigger_nulleinspeisung. Stelle sicher, dass es korrekt geschrieben ist und keine Tippfehler enthält.
Suche nach der Definition von input_number.trigger_nulleinspeisung in deiner Konfiguration. Stelle sicher, dass das entsprechende input_number-Entity korrekt definiert ist.
1. Fehler:Missing:’input_number.trigger_nulleinspeisung‘,TemplateSyntaxError: Unexpected end of template. Jinja was looking for the following tags: ‚endif‘. The innermost block that needs to be closed is ‚if‘.
ChatGP sagt auch:Überprüfe auch andere Stellen in deiner YAML-Datei, die den Jinja2-Syntax verwenden, insbesondere if-Anweisungen und überprüfe, ob sie korrekt geschlossen sind.Führe eine schrittweise Überprüfung durch, indem du Teile deiner YAML-Datei entfernst oder auskommentierst und dann prüfst, ob der Fehler weiterhin auftritt. Auf diese Weise kannst du den Abschnitt isolieren, der das Problem verursacht.Überprüfe die Protokolldateien deiner Home Assistant-Instanz auf weitere Fehlermeldungen oder Hinweise, die dir bei der Fehlersuche helfen könnten.
2.Fehler:
Custom element doesn’t exist: input_boolean_card.
type: custom:input_boolean_card
entity: input_boolean.status_nulleinspeisung
name: Status Nulleinspeisung
ChatGP hat die Yaml geändert die du oben angeboten hast,der Grund war : entity: input_boolean.status_nulleinspeisung
Yaml Datei mit meinen Daten(2x HM 800 & openDTU,Sonnenseite beide „WEST“,ferner hast du eine Idee woran es liegen könnte
das der Mqtt die Zendure Daten anzeigt,sie aber überhaupt nicht im Home Assistant angezeigt werden?4x Modul & Solarflow 2xAB1000,
type: vertical-stack
cards:
– type: markdown
content: |
### Einstellung – Nulleinspeisung
title: Nulleinstellung
– type: custom:input_boolean_card
entity: input_boolean.status_nulleinspeisung
name: Status Nulleinspeisung
– type: conditional
conditions: []
card:
type: custom:numberbox-card
border: true
entity: input_number.maximale_ausgangsleistung_wechselrichter
step: 50
icon: false
unit: W
min: 200
max: 2000
name: Inverter Typ (max. Leistung)
delay: 5000
– type: button
tap_action:
action: toggle
show_state: true
entity: input_boolean.status_nulleinspeisung
name: Nulleinspeisung
– type: conditional
conditions:
– condition: state
entity: input_boolean.status_nulleinspeisung
state: ‚on‘
card:
type: horizontal-stack
cards:
– type: markdown
content: |
Leistungsbereich Inverter
– type: horizontal-stack
cards:
– type: custom:numberbox-card
border: true
entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter
name: false
icon: false
unit: ‚%‘
min: 1
max: 100
step: 1
max_entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter
card_mod:
style: >
.body { display: block !important } .body::before {
text-align: center; font-size: 12px; content: „von ({{
(states(‚input_number.minimale_leistung_nulleinspeisung_wechselrichter‘)
| int *
(states(‚input_number.maximale_ausgangsleistung_wechselrichter‘)
| int / 100)) | int }} W)“; display: block !important }
– type: custom:numberbox-card
border: true
entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter
name: false
icon: false
unit: ‚%‘
min: 1
max: 100
step: 1
min_entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter
card_mod:
style: >
.body { display: block !important } .body::before {
text-align: center; font-size: 12px; content: „bis ({{
(states(‚input_number.maximale_leistung_nulleinspeisung_wechselrichter‘)
| int *
(states(‚input_number.maximale_ausgangsleistung_wechselrichter‘)
| int / 100)) | int }} W)“; display: block !important }
– type: conditional
conditions:
– condition: state
entity: input_boolean.status_nulleinspeisung
state: ‚on‘
card:
type: horizontal-stack
cards:
– type: markdown
content: |
Schaltschwelle Inverter
– type: horizontal-stack
cards:
– type: custom:numberbox-card
border: true
entity: input_number.ausschaltschwelle_wechselrichter
name: false
icon: false
unit: ‚%‘
min: 1
max: 100
step: 1
min_entity: input_number.minimale_leistung_nulleinspeisung_wechselrichter
max_entity: input_number.einschaltschwelle_wechselrichter
card_mod:
style: >
.body { display: block !important } .body::before {
text-align: center; font-size: 12px; content: „AUS bei SoC“;
display: block !important }
– type: custom:numberbox-card
border: true
entity: input_number.einschaltschwelle_wechselrichter
name: false
icon: false
unit: ‚%‘
min: 1
max: 100
step: 1
max_entity: input_number.maximale_leistung_nulleinspeisung_wechselrichter
min_entity: input_number.ausschaltschwelle_wechselrichter
card_mod:
style: >
.body { display: block !important } .body::before {
text-align: center; font-size: 12px; content: „EIN bei SoC“;
display: block !important }
– type: conditional
conditions:
– condition: state
entity: input_boolean.status_nulleinspeisung
state: ‚on‘
card:
type: horizontal-stack
cards:
– type: markdown
content: |
Leistung bei SoC 100%
– type: horizontal-stack
cards:
– type: custom:numberbox-card
border: true
entity: input_number.maximale_leistung_wenn_soc_100
name: false
step: 1
icon: false
unit: ‚%‘
min: 1
max: 100
card_mod:
style: >
.body { display: block !important } .body::before {
text-align: center; font-size: 12px; content: „bis ({{
(states(‚input_number.maximale_leistung_wenn_soc_100‘) | int *
(states(‚input_number.maximale_ausgangsleistung_wechselrichter‘)
| int / 100)) | int }} W)“; display: block !important }
– type: conditional
conditions: []
card:
type: custom:numberbox-card
border: true
entity: input_number.trigger_nulleinspeisung
name: Aktualisiere Ausgangsleistung aller
step: 10
icon: false
unit: s
min: 10
max: 600
– type: markdown
content: >
|||
| :— | :— |
| ***Leistungswerte*** ||
| Stromverbrauch: | **{{ states(’sensor.power_consumption‘) |
default(‚N/A‘) }} W** |
| Netzbezug: | **{{ states(’sensor.power_current‘) | default(‚N/A‘) }} W**
|
| Inverterleistung WEST: | **{{ states(’sensor.power_pv_1′) |
default(‚N/A‘) }} W** |
| Inverterleistung WEST: | **{{ states(’sensor.power_pv_2′) |
default(‚N/A‘) }} W** |
|||
| ***Status*** | |
| {% if is_state(‚input_boolean.status_nulleinspeisung‘, ‚on‘) %} |
| Nulleinspeisung: | Aktiviert |
| openDTU erreichbar: | {% if
is_state(‚binary_sensor.opendtu_958650_status‘, ‚on‘) %}Online{% else %}Offline{%
endif %} |
| Inverter Grenzwert: | **{% if
states(’number.hm_800_limit_persistent_relative‘) | default(‚N/A‘) !=
‚N/A‘ %}{{ states(’number.hm_800_limit_persistent_relative‘) | int }} %**
(**{% if states(’number.hm_800_limit_persistent_absolute‘) |
default(‚N/A‘) != ‚N/A‘ %}{{
states(’number.hm_800_limit_persistent_absolute‘) | int }} W{% else
%}N/A{% endif %}**) |
| Inverter produzierend: | {% if
is_state(‚binary_sensor.hm_800_producing‘, ‚on‘) %}An{% else %}Aus{% endif %} |
| Inverter erreichbar: | {% if is_state(‚binary_sensor.hm_800_reachable‘,
‚on‘) %}An{% else %}Aus{% endif %} |
| SoC Speicher: | **{% if
states(’sensor.solarflow_solarflow_electriclevel‘) | default(‚N/A‘) !=
‚N/A‘ %}{{ states(’sensor.solarflow_solarflow_electriclevel‘) | int }}{%
else %}N/A{% endif %} %** ({% if
states(’sensor.solarflow_solarflow_electriclevel‘) | default(‚N/A‘) !=
‚N/A‘ %}{% if states(’sensor.solarflow_pv_system_packstate‘) == ‚0‘
%}Standby{% elif states(’sensor.solarflow_pv_system_packstate‘) == ‚1‘
%}Lädt{% elif states(’sensor.solarflow_pv_system_packstate‘) == ‚2‘
%}Entlädt{% else %}Unbekannter Status{% endif %}{% endif %}) |
| {% else %} |
| Nulleinspeisung: | Deaktiviert |
| openDTU erreichbar: | {% if
is_state(‚binary_sensor.opendtu_958650_status‘, ‚on‘) %}Online{% else %}Offline{%
endif %} |
| Inverter Grenzwert: | **{% if
states(’number.hm_800_limit_persistent_relative‘) | default(‚N/A‘) !=
‚N/A‘ %}{{ states(’number.hm_800_limit_persistent_relative‘) | int }} %**
(**{% if states(’number.hm_800_limit_persistent_absolute‘) |
default(‚N/A‘) != ‚N/A‘ %}{{
states(’number.hm_800_limit_persistent_absolute‘) | int }} W{% else
%}N/A{% endif %}**) |
| Inverter produzierend: | {% if
is_state(‚binary_sensor.hm_800_producing‘, ‚on‘) %}An{% else %}Aus{% endif %} |
| Inverter erreichbar: | {% if is_state(‚binary_sensor.hm_800_reachable‘,
‚on‘) %}An{% else %}Aus{% endif %} |
| SoC Speicher: | **{% if
states(’sensor.solarflow_solarflow_electriclevel‘) | default(‚N/A‘) !=
‚N/A‘ %}{{ states(’sensor.solarflow_solarflow_electriclevel‘) | int }}{%
else %}N/A{% endif %} %** ({% if
states(’sensor.solarflow_solarflow_electriclevel‘) | default(‚N/A‘) !=
‚N/A‘ %}{% if states(’sensor.solarflow_pv_system_packstate‘) == ‚0‘
%}Standby{% elif states(’sensor.solarflow_pv_system_packstate‘) == ‚1‘
%}Lädt{% elif states(’sensor.solarflow_pv_system_packstate‘) == ‚2‘
%}Entlädt{% else %}Unbekannter Status{% endif %}{% endif %}) |
| {% endif %} |
:
Wenn die Zeit und die Lust da ist könntes du mir bitte mitteilen wo diese ID im einzelnen her kommen.Da ich es versuche 1 zu 1 um zusetzen.
Die ID mit Frage woher kommen die ???
– id: „5cf6489d8647b69b“ von ?
– id: „5739c3f29a1ea937“ von ?
– – id: „deaadefc156e85aa“ von ?
– „a66ee53700d3b369“ von ?
– id: „2a0d4e251064647e“ von ?
– „43543a987662b3e9“ von ?
– – id: „0c751d1f7106fbac“ von ?
: „fb0d40e8.e8f66“ von ?
– id: „43543a987662b3e9“ von ?
– „2a0d4e251064647e“ von ?
– „a26c4f5925b4b643“ von ?
– „ad417c320b10bec2“ von ?
– id: „fad7c9c2783c3c71“ von ?
– id: „32b1de89d46895e9“ von ?
: „fb0d40e8.e8f66“ von ?
– id: „aefb0da329db14a4“ von ?
: „fb0d40e8.e8f66“ von ?
– id: „474344884a02867c“ von ?
: „fb0d40e8.e8f66“ von ?
– id: „deaadefc156e85aa“ von ?
– id: „f04101965e727af7“ von ?
– „fad7c9c2783c3c71“ von ?
– id: „57723b0bd889f0a7“ von ?
Die IDs werden von NodeRed beim Erstellen von Nodes automatisch erstellt.
Ich habe den Beitrag aktualisiert. Du kannst jetzt den JSON-Flow über die Symbolleiste kopieren und in NodeRed importieren.
VG Martin
Hallo,
hier die Node Red in Json Format laut ChatGP:
[
{
„id“: „5cf6489d8647b69b“,
„type“: „group“,
„name“: „Nulleinspeisung V1.0 04/2024“,
„style“: {
„label“: true
},
„nodes“: [
{
„id“: „5739c3f29a1ea937“,
„type“: „inject“,
„name“: „Trigger Inverter Neustart“,
„props“: [
{
„p“: „payload“
}
],
„repeat“: „“,
„crontab“: „00 00 * * *“,
„once“: false,
„onceDelay“: „6“,
„topic“: „“,
„payload“: „“,
„payloadType“: „date“,
„x“: 1210,
„y“: 720,
„wires“: [
[
{
„id“: „deaadefc156e85aa“,
„type“: „link out“,
„name“: „Event Data“,
„mode“: „link“,
„links“: [
„a66ee53700d3b369“
]
}
]
]
},
{
„id“: „2a0d4e251064647e“,
„type“: „link in“,
„name“: „Event Trigger“,
„links“: [
„43543a987662b3e9“
],
„x“: 105,
„y“: 800,
„wires“: [
[
{
„id“: „0c751d1f7106fbac“,
„type“: „ha-get-entities“,
„name“: „Status openDTU“,
„server“: „fb0d40e8.e8f66“,
„version“: 1,
„rules“: [
{
„property“: „entity_id“,
„logic“: „includes“,
„value“: „binary_sensor.opendtu_168e58_status“,
„valueType“: „str“
}
],
„outputType“: „split“,
„outputEmptyResults“: false,
„outputLocationType“: „msg“,
„outputLocation“: „payload“,
„outputResultsCount“: 1
}
]
]
},
{
„id“: „43543a987662b3e9“,
„type“: „link out“,
„name“: „Event Trigger“,
„mode“: „link“,
„links“: [
„2a0d4e251064647e“,
„a26c4f5925b4b643“,
„ad417c320b10bec2“
],
„x“: 565,
„y“: 700
},
{
„id“: „fad7c9c2783c3c71“,
„type“: „group“,
„name“: „Parameter“,
„style“: {
„label“: true
},
„nodes“: [
{
„id“: „32b1de89d46895e9“,
„type“: „ha-get-entities“,
„name“: „Minimale Leistung Nulleinspeisung Wechselrichter“,
„server“: „fb0d40e8.e8f66“,
„version“: 1,
„rules“: [
{
„property“: „entity_id“,
„logic“: „includes“,
„value“: „input_number.minimale_leistung_nulleinspeisung_wechselrichter“,
„valueType“: „str“
}
],
„outputType“: „split“,
„outputEmptyResults“: false,
„outputLocationType“: „msg“,
„outputLocation“: „payload“,
„outputResultsCount“: 1,
„x“: 370,
„y“: 1420
},
{
„id“: „aefb0da329db14a4“,
„type“: „ha-get-entities“,
„name“: „Ausschaltschwelle Inverter „,
„server“: „fb0d40e8.e8f66“,
„version“: 1,
„rules“: [
{
„property“: „entity_id“,
„logic“: „includes“,
„value“: „input_number.ausschaltschwelle_wechselrichter“,
„valueType“: „str“
}
],
„outputType“: „split“,
„outputEmptyResults“: false,
„outputLocationType“: „msg“,
„outputLocation“: „payload“,
„outputResultsCount“: 1,
„x“: 350,
„y“: 1480
},
{
„id“: „474344884a02867c“,
„type“: „ha-get-entities“,
„name“: „Maximale Leistung Nulleinspeisung Wechselrichter“,
„server“: „fb0d40e8.e8f66“,
„version“: 1,
„rules“: [
{
„property“: „entity_id“,
„logic“: „includes“,
„value“: „input_number.maximale_leistung_nulleinspeisung_wechselrichter“,
„valueType“: „str“
}
],
„outputType“: „split“,
„outputEmptyResults“: false,
„outputLocationType“: „msg“,
„outputLocation“: „payload“,
„outputResultsCount“: 1,
„x“: 370,
„y“: 1360
}
]
},
{
„id“: „deaadefc156e85aa“,
„type“: „link out“,
„name“: „Event Data“,
„mode“: „link“,
„links“: [
„2a0d4e251064647e“,
„43543a987662b3e9“
],
„x“: 1375,
„y“: 720
},
{
„id“: „f04101965e727af7“,
„type“: „link out“,
„name“: „Event Data“,
„mode“: „link“,
„links“: [
„2a0d4e251064647e“,
„43543a987662b3e9“,
„fad7c9c2783c3c71“
],
„x“: 615,
„y“: 1400
},
{
„id“: „57723b0bd889f0a7“,
„type“: „link out“,
„name“: „Event Data“,
„mode“: „link“,
„links“: [
„2a0d4e251064647e“,
„43543a987662b3e9“
],
„x“: 430,
„y“: 760
},
{
„id“: „fb0d40e8e8f66“,
„type“: „server“,
„name“: „Home Assistant“,
„version“: 1,
„legacy“: false,
„addon“: false,
„rejectUnauthorizedCerts“: true,
„ha_boolean“: „y|yes|true|on|home|open“,
„connectionDelay“: true,
„cacheJson“: true,
„x“: 110,
„y“: 580,
„wires“: []
}
],
„wires“: []
}
]
Mfg
Peter
Hi Peter,
ich habe den JSON-Flow und die Kartenkonfiguration aktualisiert.
VG Martin
Hallo Martin,
das über tragen hat top geklappt,danke