NEWS
Zendure zenSDK Lokal API, SmartMode, SolarFlow AC 800 Pro 2
-
@T-147
genau für solche Rückmeldungen ist die Vorlage da!
Danke für das genaue Log.
Du hast hier einen extremen Ausnahmefall aufgedeckt, den das Skript in dieser Basis-Version so noch nicht abfangen konnte.Was ist passiert?
Deine Batterie ist in den hardwareseitigen Notlademodus gegangen und hat sich mit 1000W aus dem Netz gerettet.
Das Skript hat diesen plötzlichen Netzbezug über das Gridmeter registriert und dachte wegen des criticalMode, im Haus sei ein riesiger Verbraucher angesprungen.
Daraufhin hat es die Entladung wieder freigegeben und gegen die eigene Notladung des Hubs angekämpft.
Ein klassischer Logik-Teufelskreis.Der criticalMode und der normale Regelkreis müssen sofort blockiert werden, wenn der Batterieschutz aktiv ist.
Ich schaue mir das noch genauer an, damit der batteryLock immer die oberste Priorität hat und nicht mehr vom eigenen Laden ausgetrickst werden kann.Möchtest Du bitte dieses Blockly testen:
@maxclaudi sagte:
Möchtest Du bitte dieses Blockly testen:Wird gemacht, kein Problem.
Ich hatte zusätzlich noch die Vermutung, dass der Batterieschutz zwar aktiviert wird, aber die Regelung dann auf dem aktuellen Wert stehen bleibt (in meinem aktuellen Fall 240W).
Ich habe deswegen dem Blockly unter Entladeschutz noch zwei kleine Teile hinzugefügt, die einmal den minSoc als zusätzlichen Parameter für den Entladeschutz hinzufügen und einmal nach Aktivieren des Ladeschutzes das In/Out-Limit auf 0 setzt, damit das Einspeisen beendet wird:

Maybe ist das mit dem minSoc auch doppelt gemoppelt, aber er sollte den Entladeschutz aktivieren, je nachdem was eher eintritt.Ist noch nicht getestet, morgen kann ich da vielleicht schon mehr zu sagen.
-
// GET intervall
// Empfehlung: >= 5000 ms.
// Kleinere Werte möglich, aber m. M. nach sinnfrei und nicht empfohlen (Last / Stabilität).
const getIntervalMs = 4000; // Intervall für GET 5000ms. Bei Problemen erhöhen. NICHT < 5000!Hallo maxclaudi,
in deinem überarbeiteten Skript steht bei const getIntervalMs = 4000 und im Komentar dahinter, dass man nichrt unter 5000 gehen soll.Ich bewundere deinen Enthusiasmus bei der Analyse der Firmware.
peter
Hallo Peter, bald kommt schon wieder das große Fest :-)
in deinem überarbeiteten Skript steht bei const getIntervalMs = 4000 und im Komentar dahinter, dass man nichrt unter 5000 gehen soll.
Du kennst das doch: Sicher ist sicher ;-)
Bei mir läuft es mit 4000 (und selbst mit 3500) absolut stabil.
Aber nicht jeder hat ein optimales WLAN oder einen eigenen Access Point direkt neben den Geräten. Zudem funken meine in einem komplett eigenen, isolierten Netz.
Das muss man im Zweifel einfach selbst ausprobieren.
Bei mir funktionieren die 3500 ms einwandfrei – wahrscheinlich auch, weil in dem isolierten Netz absolut kein anderer HTTP(S)-Traffic dazwischenfunken kann.Ich bewundere deinen Enthusiasmus bei der Analyse der Firmware.
Ich sage dazu nur: Kühlschrank und Festplatte ;-)
Ich liebe es einfach, wenn Kollegen einen Enthusiasmus und eine gesunde Portion Pragmatismus teilen und verstehen! :-)
Viele Grüße
edit /PS 09.10.2026 12:20h
HINWEIS:
Der originale Firmware-Code verifiziert, dass (z. B. bei MQTT im Standard) alle 5000 ms automatisch ein Report published wird.Wenn mittels GET via zenSDK noch schneller abgefragt wird, kann es hardwarebedingt vorkommen, dass man alte bzw. identische Werte empfängt. Es ist m. M. n. daher sinnfrei, schneller als alle 4000–5000 ms abzufragen.
-
Hallo @maxclaudi,
erstmal danke für deine Arbeit und für das Bereitstellen des Skriptes. Ich habe seit ein paar Tagen einen Solarflow 4000 Mix AC+ und versuche eine Regelung zu realisieren.
Bei dem "offiziellen" Adapter stoße ich aber auf ein Problem, das auch bei deinem Skript existiert. Bei letzterem kann ich es aber selber anpassen. Warum wird acMode auf 0 gesetzt, wenn auto_in_out_Limit null ist? Der Wert 0 ist laut zenSDK Doku gar nicht vorgesehen oder übersehe ich etwas? Mein Speicher wechselt bei acMode == 0 nicht in den Standby sondern speist mit 200W ein. Belasse ich acMode bei 1 oder 2 passt es.
Ach und vielleicht möchtest du noch einen Hinweis bei folderZendureApi ergänzen, das man auf Sonderzeichen versichten sollte. '0_userdata.0.zendure.' + "solarFlow4000MixAC+" schmeckte dem Skript natürlich nicht

-
@T-147
genau für solche Rückmeldungen ist die Vorlage da!
Danke für das genaue Log.
Du hast hier einen extremen Ausnahmefall aufgedeckt, den das Skript in dieser Basis-Version so noch nicht abfangen konnte.Was ist passiert?
Deine Batterie ist in den hardwareseitigen Notlademodus gegangen und hat sich mit 1000W aus dem Netz gerettet.
Das Skript hat diesen plötzlichen Netzbezug über das Gridmeter registriert und dachte wegen des criticalMode, im Haus sei ein riesiger Verbraucher angesprungen.
Daraufhin hat es die Entladung wieder freigegeben und gegen die eigene Notladung des Hubs angekämpft.
Ein klassischer Logik-Teufelskreis.Der criticalMode und der normale Regelkreis müssen sofort blockiert werden, wenn der Batterieschutz aktiv ist.
Ich schaue mir das noch genauer an, damit der batteryLock immer die oberste Priorität hat und nicht mehr vom eigenen Laden ausgetrickst werden kann.Möchtest Du bitte dieses Blockly testen:
Das Blockly zum Testen ist auf meine Datenpunkte angepasst (gefühlt 3000 Stück...) und läuft ab jetzt. Hab sonst erstmal keinerlei Änderungen daran vorgenommen.
Gestern Abend konnte ich nochmal beobachten, wie das Blockly den Entladeschutz aktiviert hat, aber trotzdem bis 10% SoC weiter entladen wurde. Mein kleiner Zusatz hat offensichtlich keinerlei Wirkung gezeigt.
Im Anschluss sackte der SoC über einen längeren Zeitraum bis auf 6% runter, minVol stand in der Zeit ziemlich konstan bei 3,15V.
Habe dann dann nach einiger Zeit manuell das Aufladen gestartet und ca 30min Laden lassen. minVol ging kurzfristig auf 3,25V hoch und hielt sich dann anschließen auf 3,21V.Aber wie gesagt, ab jetzt läuft das Script zum Testen und ich melde mich, sobald ich Erkenntnisse dazu habe.
Beste Grüße
-
Hallo @maxclaudi,
erstmal danke für deine Arbeit und für das Bereitstellen des Skriptes. Ich habe seit ein paar Tagen einen Solarflow 4000 Mix AC+ und versuche eine Regelung zu realisieren.
Bei dem "offiziellen" Adapter stoße ich aber auf ein Problem, das auch bei deinem Skript existiert. Bei letzterem kann ich es aber selber anpassen. Warum wird acMode auf 0 gesetzt, wenn auto_in_out_Limit null ist? Der Wert 0 ist laut zenSDK Doku gar nicht vorgesehen oder übersehe ich etwas? Mein Speicher wechselt bei acMode == 0 nicht in den Standby sondern speist mit 200W ein. Belasse ich acMode bei 1 oder 2 passt es.
Ach und vielleicht möchtest du noch einen Hinweis bei folderZendureApi ergänzen, das man auf Sonderzeichen versichten sollte. '0_userdata.0.zendure.' + "solarFlow4000MixAC+" schmeckte dem Skript natürlich nicht

Hallo @maxclaudi,
erstmal danke für deine Arbeit und für das Bereitstellen des Skriptes.
Danke auch für das Vertrauen und die Nutzung :-)
Zum Bedanken:
tut gut, aber ist in einem post nicht nötig.
Dazu lieber den voting-Button benutzen:

Für das Steuerungs-Script vorzugsweise ganz oben das erste Post (vom Thread) oder auch im Beitrag des Scripts selbst.
Ich habe seit ein paar Tagen einen Solarflow 4000 Mix AC+ und versuche eine Regelung zu realisieren.
Warum wird acMode auf 0 gesetzt, wenn auto_in_out_Limit null ist? Der Wert 0 ist laut zenSDK Doku gar nicht vorgesehen
Du hast absolut Recht. Wurde gefixt. Danke.
-
Das Blockly zum Testen ist auf meine Datenpunkte angepasst (gefühlt 3000 Stück...) und läuft ab jetzt. Hab sonst erstmal keinerlei Änderungen daran vorgenommen.
Gestern Abend konnte ich nochmal beobachten, wie das Blockly den Entladeschutz aktiviert hat, aber trotzdem bis 10% SoC weiter entladen wurde. Mein kleiner Zusatz hat offensichtlich keinerlei Wirkung gezeigt.
Im Anschluss sackte der SoC über einen längeren Zeitraum bis auf 6% runter, minVol stand in der Zeit ziemlich konstan bei 3,15V.
Habe dann dann nach einiger Zeit manuell das Aufladen gestartet und ca 30min Laden lassen. minVol ging kurzfristig auf 3,25V hoch und hielt sich dann anschließen auf 3,21V.Aber wie gesagt, ab jetzt läuft das Script zum Testen und ich melde mich, sobald ich Erkenntnisse dazu habe.
Beste Grüße
Das Blockly zum Testen ist auf meine Datenpunkte angepasst (gefühlt 3000 Stück...) und läuft ab jetzt. Hab sonst erstmal keinerlei Änderungen daran vorgenommen.
Reines JS ist einfach besser als Blockly.
Wenn alle Datenpunkte umgestellt sind, kannst Du die Ansicht auf JS umstellen und dann (auch ohne letzte Zeile) in einen Editor kopieren (z.B. Notepad++).
Nach 1600 suchen.
Wenn was gefunden wird siehst Du dank der vielen Kommentare auch gleich wo was vergessen wurde.Gestern Abend konnte ich nochmal beobachten, wie das Blockly den Entladeschutz aktiviert hat, aber trotzdem bis 10% SoC weiter entladen wurde. Mein kleiner Zusatz hat offensichtlich keinerlei Wirkung gezeigt.
Im Anschluss sackte der SoC über einen längeren Zeitraum bis auf 6% runter, minVol stand in der Zeit ziemlich konstan bei 3,15V.
Habe dann dann nach einiger Zeit manuell das Aufladen gestartet und ca 30min Laden lassen. minVol ging kurzfristig auf 3,25V hoch und hielt sich dann anschließen auf 3,21V.das war noch das alte Blockly, nicht war?
-
Hallo Peter, bald kommt schon wieder das große Fest :-)
in deinem überarbeiteten Skript steht bei const getIntervalMs = 4000 und im Komentar dahinter, dass man nichrt unter 5000 gehen soll.
Du kennst das doch: Sicher ist sicher ;-)
Bei mir läuft es mit 4000 (und selbst mit 3500) absolut stabil.
Aber nicht jeder hat ein optimales WLAN oder einen eigenen Access Point direkt neben den Geräten. Zudem funken meine in einem komplett eigenen, isolierten Netz.
Das muss man im Zweifel einfach selbst ausprobieren.
Bei mir funktionieren die 3500 ms einwandfrei – wahrscheinlich auch, weil in dem isolierten Netz absolut kein anderer HTTP(S)-Traffic dazwischenfunken kann.Ich bewundere deinen Enthusiasmus bei der Analyse der Firmware.
Ich sage dazu nur: Kühlschrank und Festplatte ;-)
Ich liebe es einfach, wenn Kollegen einen Enthusiasmus und eine gesunde Portion Pragmatismus teilen und verstehen! :-)
Viele Grüße
edit /PS 09.10.2026 12:20h
HINWEIS:
Der originale Firmware-Code verifiziert, dass (z. B. bei MQTT im Standard) alle 5000 ms automatisch ein Report published wird.Wenn mittels GET via zenSDK noch schneller abgefragt wird, kann es hardwarebedingt vorkommen, dass man alte bzw. identische Werte empfängt. Es ist m. M. n. daher sinnfrei, schneller als alle 4000–5000 ms abzufragen.
HINWEIS:
Der originale Firmware-Code verifiziert, dass (z. B. bei MQTT im Standard) alle 5000 ms automatisch ein Report published wird.Wenn mittels GET via zenSDK noch schneller abgefragt wird, kann es hardwarebedingt vorkommen, dass man alte bzw. identische Werte empfängt. Es ist m. M. n. daher sinnfrei, schneller als alle 4000–5000 ms abzufragen.
-
Das Blockly zum Testen ist auf meine Datenpunkte angepasst (gefühlt 3000 Stück...) und läuft ab jetzt. Hab sonst erstmal keinerlei Änderungen daran vorgenommen.
Reines JS ist einfach besser als Blockly.
Wenn alle Datenpunkte umgestellt sind, kannst Du die Ansicht auf JS umstellen und dann (auch ohne letzte Zeile) in einen Editor kopieren (z.B. Notepad++).
Nach 1600 suchen.
Wenn was gefunden wird siehst Du dank der vielen Kommentare auch gleich wo was vergessen wurde.Gestern Abend konnte ich nochmal beobachten, wie das Blockly den Entladeschutz aktiviert hat, aber trotzdem bis 10% SoC weiter entladen wurde. Mein kleiner Zusatz hat offensichtlich keinerlei Wirkung gezeigt.
Im Anschluss sackte der SoC über einen längeren Zeitraum bis auf 6% runter, minVol stand in der Zeit ziemlich konstan bei 3,15V.
Habe dann dann nach einiger Zeit manuell das Aufladen gestartet und ca 30min Laden lassen. minVol ging kurzfristig auf 3,25V hoch und hielt sich dann anschließen auf 3,21V.das war noch das alte Blockly, nicht war?
@maxclaudi sagte:>
Reines JS ist einfach besser als Blockly.
Wenn alle Datenpunkte umgestellt sind, kannst Du die Ansicht auf JS umstellen und dann (auch ohne letzte Zeile) in einen Editor kopieren (z.B. Notepad++).
Nach 1600 suchen.
Wenn was gefunden wird siehst Du dank der vielen Kommentare auch gleich wo was vergessen wurde.Probier ich beim nächsten Mal aus. Mit der XML direkt hab ich das nicht hinbekommen.
das war noch das alte Blockly, nicht war?
Ja, in der Tat.
Ich kann aber zumindest schon sagen, dass das Problem bei deinem Test-Blockly weiterhin besteht.
Um etwa 12:00 Uhr wurde die Entladesperre automatisch entfernt und ordnungsgemäß das Entladen geregelt. Um etwa 12:23 Uhr sprint ein großer Verbaucher an (ca 2kW) und der SF800 geht kurz darauf auf Entladen, allerdings nur etwa 400W. Der Verbraucher ist dann wieder aus und das Entladen geht weiter, sodass der Stromzähler -180W zeigt. Nach etwa 20 min hab ich mal das Blockly neu gestartet, hat aber auch nicht geholfen. Blockly aus und altes wieder an hat auch nicht geholfen, ich musste dann manuell (habs leider in der App gemacht und nicht im ZenSDK) Laden/Entladen auf 0 gestellt, dann fing der SF800 wieder an aus dem PV zu laden und nichts weiter zu machen.
Im Log ist davon nichts zu sehen, letzter Eintrag ist 12:20 Uhr und dann bis zum Neustart des Blockly nichts, obwohl um 12:23 Uhr auch die Entladesperre mit minVol 3,19V gegriffen haben müsste (oder zeigt das Test-Blockly diese Meldung nicht?)javascript.0 2026-10-09 12:42:15.557 info script.js.Energieversorgung.Zendure.SF800_Pro_2_-_Nulleinspeisung_2026_09: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:42:15.543 info script.js.Energieversorgung.Zendure.SF800_Pro_2_-_Nulleinspeisung_2026_09: start JavaScript (Blockly) javascript.0 2026-10-09 12:42:09.903 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:41:28.025 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:41:27.985 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: start JavaScript (Blockly) javascript.0 2026-10-09 12:41:22.772 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:32:57.360 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:32:57.290 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: start JavaScript (Blockly) javascript.0 2026-10-09 12:32:57.086 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:20:28.408 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: auto_in_out_Limit ist positiv oder 0: 400 javascript.0 2026-10-09 12:20:28.407 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: newLimit positiv: 400 ist > oldLimit: 190 Es wird mehr entladen als zuvor. javascript.0 2026-10-09 12:20:18.359 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: auto_in_out_Limit ist positiv oder 0: 190 javascript.0 2026-10-09 12:20:18.358 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: newLimit positiv: 190 ist > oldLimit: 170 Es wird mehr entladen als zuvor. javascript.0 2026-10-09 12:19:58.594 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170 javascript.0 2026-10-09 12:19:51.338 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170 javascript.0 2026-10-09 12:19:50.682 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170Nachtrag:
Auch beim Aktivieren des Batterieschutzes wird das Laden/Entladen nicht auf 0 gesetzt und der SF800 entlädt stur auf bisherigem Wert weiter, bis der min SoC aus der App greift.
Auch hier muss ich manuell eingreifen. Diesmal hab ich es über das ZenSDK-Script gemacht und auto_in_out_limit auf 0 gesetzt, hat aber erstmal keine Wirkung gezeigt. Ein -1 brachte dann Erfolg. Das würde auch erklären, warum mein Blockly-Zusatz und auf 0 setzen von gestern nicht funktioniert hat. -
@maxclaudi sagte:>
Reines JS ist einfach besser als Blockly.
Wenn alle Datenpunkte umgestellt sind, kannst Du die Ansicht auf JS umstellen und dann (auch ohne letzte Zeile) in einen Editor kopieren (z.B. Notepad++).
Nach 1600 suchen.
Wenn was gefunden wird siehst Du dank der vielen Kommentare auch gleich wo was vergessen wurde.Probier ich beim nächsten Mal aus. Mit der XML direkt hab ich das nicht hinbekommen.
das war noch das alte Blockly, nicht war?
Ja, in der Tat.
Ich kann aber zumindest schon sagen, dass das Problem bei deinem Test-Blockly weiterhin besteht.
Um etwa 12:00 Uhr wurde die Entladesperre automatisch entfernt und ordnungsgemäß das Entladen geregelt. Um etwa 12:23 Uhr sprint ein großer Verbaucher an (ca 2kW) und der SF800 geht kurz darauf auf Entladen, allerdings nur etwa 400W. Der Verbraucher ist dann wieder aus und das Entladen geht weiter, sodass der Stromzähler -180W zeigt. Nach etwa 20 min hab ich mal das Blockly neu gestartet, hat aber auch nicht geholfen. Blockly aus und altes wieder an hat auch nicht geholfen, ich musste dann manuell (habs leider in der App gemacht und nicht im ZenSDK) Laden/Entladen auf 0 gestellt, dann fing der SF800 wieder an aus dem PV zu laden und nichts weiter zu machen.
Im Log ist davon nichts zu sehen, letzter Eintrag ist 12:20 Uhr und dann bis zum Neustart des Blockly nichts, obwohl um 12:23 Uhr auch die Entladesperre mit minVol 3,19V gegriffen haben müsste (oder zeigt das Test-Blockly diese Meldung nicht?)javascript.0 2026-10-09 12:42:15.557 info script.js.Energieversorgung.Zendure.SF800_Pro_2_-_Nulleinspeisung_2026_09: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:42:15.543 info script.js.Energieversorgung.Zendure.SF800_Pro_2_-_Nulleinspeisung_2026_09: start JavaScript (Blockly) javascript.0 2026-10-09 12:42:09.903 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:41:28.025 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:41:27.985 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: start JavaScript (Blockly) javascript.0 2026-10-09 12:41:22.772 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:32:57.360 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: registered 2 subscriptions, 0 schedules, 0 messages, 0 logs and 0 file subscriptions javascript.0 2026-10-09 12:32:57.290 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: start JavaScript (Blockly) javascript.0 2026-10-09 12:32:57.086 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Stopping script javascript.0 2026-10-09 12:20:28.408 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: auto_in_out_Limit ist positiv oder 0: 400 javascript.0 2026-10-09 12:20:28.407 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: newLimit positiv: 400 ist > oldLimit: 190 Es wird mehr entladen als zuvor. javascript.0 2026-10-09 12:20:18.359 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: auto_in_out_Limit ist positiv oder 0: 190 javascript.0 2026-10-09 12:20:18.358 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: newLimit positiv: 190 ist > oldLimit: 170 Es wird mehr entladen als zuvor. javascript.0 2026-10-09 12:19:58.594 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170 javascript.0 2026-10-09 12:19:51.338 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170 javascript.0 2026-10-09 12:19:50.682 info script.js.Energieversorgung.Zendure.Test_v__Maxclaudi: Es gibt nichts zu tun, theoretisches positives newLimit: 170; oldLimit: 170Nachtrag:
Auch beim Aktivieren des Batterieschutzes wird das Laden/Entladen nicht auf 0 gesetzt und der SF800 entlädt stur auf bisherigem Wert weiter, bis der min SoC aus der App greift.
Auch hier muss ich manuell eingreifen. Diesmal hab ich es über das ZenSDK-Script gemacht und auto_in_out_limit auf 0 gesetzt, hat aber erstmal keine Wirkung gezeigt. Ein -1 brachte dann Erfolg. Das würde auch erklären, warum mein Blockly-Zusatz und auf 0 setzen von gestern nicht funktioniert hat.@T-147 sagte:
Auch hier muss ich manuell eingreifen. Diesmal hab ich es über das ZenSDK-Script gemacht und auto_in_out_limit auf 0 gesetzt, hat aber erstmal keine Wirkung gezeigt. Ein -1 brachte dann Erfolg. Das würde auch erklären, warum mein Blockly-Zusatz und auf 0 setzen von gestern nicht funktioniert hat.Bitte das aktuelle Steuerungsscript benutzen und "vor Aktivieren" den Datenpunkt ....control.acMode löschen.
Das andere schaue ich mir demnächst an, sobald ich Zeit habe
edit/ps - vor 16/17 Uhr leider nicht, sorry -
@T-147 sagte:
Auch hier muss ich manuell eingreifen. Diesmal hab ich es über das ZenSDK-Script gemacht und auto_in_out_limit auf 0 gesetzt, hat aber erstmal keine Wirkung gezeigt. Ein -1 brachte dann Erfolg. Das würde auch erklären, warum mein Blockly-Zusatz und auf 0 setzen von gestern nicht funktioniert hat.Bitte das aktuelle Steuerungsscript benutzen und "vor Aktivieren" den Datenpunkt ....control.acMode löschen.
Das andere schaue ich mir demnächst an, sobald ich Zeit habe
edit/ps - vor 16/17 Uhr leider nicht, sorryAlles gut, mach dir keinen Stress. Werd am WE eh nicht viel Zeit dafür haben. Hab im Blockly den Bereich mit den Großverbrauchern jetzt erstmal deaktiviert.
ZenSDK-Script grad neu geladen und vor dem Starten den Datenpunkt ...control.acMode gelöscht.

Ich teste weiter. -
Alles gut, mach dir keinen Stress. Werd am WE eh nicht viel Zeit dafür haben. Hab im Blockly den Bereich mit den Großverbrauchern jetzt erstmal deaktiviert.
ZenSDK-Script grad neu geladen und vor dem Starten den Datenpunkt ...control.acMode gelöscht.

Ich teste weiter.Alles gut, mach dir keinen Stress. Werd am WE eh nicht viel Zeit dafür haben. Hab im Blockly den Bereich mit den Großverbrauchern jetzt erstmal deaktiviert.
ZenSDK-Script grad neu geladen und vor dem Starten den Datenpunkt ...control.acMode gelöscht.

Ich teste weiter.ok, Bitte habe Nachsicht mit mir, dass ich nicht die Zeit finde, das alles in Blockly zusammenzuklicken.
Ich habe das Ganze nun – auf die Schnelle – in reinem JavaScript umgesetzt. Das ist für mich wesentlich einfacher zu lesen, und eventuelle Fehler sind schneller zu finden und zu beheben.
Ich habe das JS extra für Einsteiger geschrieben und sehr einfach gehalten, damit es leicht nachvollziehbar ist.
Oben im Skript muss nur noch die Konfiguration eingetragen werden, ohne dass man (wie im Blockly) mühsam unzählige Datenpunkte manuell anpassen muss.
Bitte einfach mal testen.
Ich denke, es ist ausreichend kommentiert...Das Skript ist bei mir nur kurzfristig auf Lauffähigkeit getestet, sollte aber einwandfrei funktionieren.
// ZENDURE einfache NULLEINSPEISUNG - ioBroker JavaScript-Adapter // Wahlweise 1 bis 6 Batterien. Keine Schleifen, einfach zu lesen für Einsteiger // Für alle Geräte ab 2025/2026, die zenSDK unterstützen, wie z. B.: // SF800, SF800 PLUS, 800Pro (2), 1600AC, SF2400AC(+) usw. // (c) maxclaudi 09.10.2026_18:00h für das ioBroker-Forum // // EIN WORT IN EIGENER SACHE:. // In der Vergangenheit wurden meine Erkenntnisse oft ohne Erwähnung in andere Projekte übernommen. // Ich teile diesen Code gerne. // Wer diese(n) Code/Logik in öffentliche Adapter integriert oder anderweitig - auch Auszugsweise verwenden möchte, ist herzlich // eingeladen – ich bitte jedoch um die Fairness, die Quelle zu nennen. // Das ist der "Lohn" für meine Zeit und Forschung. // ====================================================================================== // 1. KONFIGURATION: HIER PFADE UND DATENPUNKTE und Anzahl der Batterien ANPASSEN // Trigger-Datenpunkt (Stromzähler / Smart Meter, Netzbezug in Watt) const DP_GRID_METER_TRIGGER = '0_userdata.0.Datenpunkte.zendureSolarFlow.user.ZaehlerTrigger_easy_shelly'; // Haupt-Verzeichnis des Zendure-Datenpunkte-Scripts (muss identisch sein) const folderZendureApi = '0_userdata.0.zendure.' + "2400ACproZENsdk"; // Wie viele Batterien hast du? Mögliche Werte: 1, 2, 3, 4, 5 oder 6 const vorhandeneBatAnz = 2; // Seriennummern der Batterien. // Nur die Seriennummer eintragen (ohne ".minVol"), nicht benötigte Zeilen einfach so lassen. const akku1sn = "Cxxxxxxxxxxxxx1"; // z.B.: const akku1sn = "JO2AEP1P0605193"; const akku2sn = "Cxxxxxxxxxxxxx2"; const akku3sn = "Cxxxxxxxxxxxxx3"; const akku4sn = "Cxxxxxxxxxxxxx4"; const akku5sn = "Cxxxxxxxxxxxxx5"; const akku6sn = "Cxxxxxxxxxxxxx6"; // 2. REGEL-PARAMETER (die Standardwerte müssten für die meisten Zendure-Geräte passen) //--------------------------------------------------------------------------------------- let intervalSec_outputLimit = 15; // Entladen frühestens nach X Sekunden. Standard: 15 s let intervalSec_inputLimit = 20; // Laden frühestens nach X Sekunden. Standard: 20 s let chargingStep = 50; // Schritte AC-Laden (z.B. 50 W, 100 W). Standard: 50 W let dischargeStep = 10; // Schritte Entladen, wird aufgerundet. Standard: 10 W let wattChangeThreshold = 30; // Hysterese: Änderungen erst ab X Watt Abweichung. Standard: 30 W let safetyReserve = 20; // Sicherheitsreserve gegen Netzbezug beim Laden. Standard: 20 W let criticalGridPower = 600; // Ab wie viel Watt Netzbezug gilt es als hoher Leistungsabruf. Standard: 600 W let criticalOutputLimit = 1600; // Maximale Entladeleistung im Critical-Mode (nicht größer als dein Gerät: 800, 1000, 2400 W) let intervalSec_criticalMode = 45; // So lange wird die Spitze gehalten (taktende Großverbraucher: Herd, Klima, Durchlauferhitzer) let intervalSec_change_acModeAllowed = 45; // Relais-Schutz: Sperrzeit nach einem Moduswechsel in Sekunden, bitte nicht zu kurz let batteryLockMinCellVoltage = 3.17; // Entladesperre bei dieser Zellspannung: 3.16 bis 3.20 V let batteryUnlockMinCellVoltage = 3.25; // Freigabe nach der Sperre ab dieser Zellspannung. Standard: 3.25 V let batteryRecoveryTimeSec = 300; // Beruhigungszeit der Zellen in Sekunden. Standard: 300 s (5 min) //--------------------------------------------------------------------------------------- // AB HIER NICHTS VERÄNDERN! //--------------------------------------------------------------------------------------- // Anzahl Batterien absichern (nur 1 bis 6 erlaubt) let batAnz = Math.round(vorhandeneBatAnz); if (!(batAnz >= 1)) batAnz = 1; if (batAnz > 6) batAnz = 6; // Basis-Pfade zu den Zendure-Eigenschaften const BASE_PATH_PROPERTIES = folderZendureApi + '.properties.'; const BASE_PATH_CONTROL = folderZendureApi + '.control.'; const BASE_PATH_PACKDATA = folderZendureApi + '.packData.'; // Zellspannungs-Datenpunkt einer Batterie zusammensetzen // (ein versehentlich mit eingetragenes ".minVol" wird automatisch entfernt) function packDp(sn) { return BASE_PATH_PACKDATA + String(sn).replace('.minVol', '') + '.minVol'; } const DP_MIN_VOL_PACK1 = packDp(akku1sn); const DP_MIN_VOL_PACK2 = packDp(akku2sn); const DP_MIN_VOL_PACK3 = packDp(akku3sn); const DP_MIN_VOL_PACK4 = packDp(akku4sn); const DP_MIN_VOL_PACK5 = packDp(akku5sn); const DP_MIN_VOL_PACK6 = packDp(akku6sn); // Spezifische Datenpunkte (automatisch zusammengesetzt) const DP_AUTO_IN_OUT_LIMIT = BASE_PATH_CONTROL + 'auto_in_out_Limit'; const DP_SMART_MODE = BASE_PATH_CONTROL + 'smartMode'; const DP_INVERSE_MAX_POWER = BASE_PATH_PROPERTIES + 'inverseMaxPower'; const DP_CHARGE_MAX_LIMIT = BASE_PATH_PROPERTIES + 'chargeMaxLimit'; const DP_GRID_INPUT_POWER = BASE_PATH_PROPERTIES + 'gridInputPower'; const DP_OUTPUT_HOME_POWER = BASE_PATH_PROPERTIES + 'outputHomePower'; const DP_INPUT_LIMIT = BASE_PATH_PROPERTIES + 'inputLimit'; const DP_OUTPUT_LIMIT = BASE_PATH_PROPERTIES + 'outputLimit'; const DP_AC_MODE = BASE_PATH_PROPERTIES + 'acMode'; const DP_PASS = BASE_PATH_PROPERTIES + 'pass'; const DP_SOC_LIMIT = BASE_PATH_PROPERTIES + 'socLimit'; const DP_PACK_STATE = BASE_PATH_PROPERTIES + 'packState'; const DP_ELECTRIC_LEVEL = BASE_PATH_PROPERTIES + 'electricLevel'; const DP_MIN_SOC = BASE_PATH_PROPERTIES + 'minSoc'; const DP_SOC_SET = BASE_PATH_PROPERTIES + 'socSet'; // Merker-Variablen let dplAktiv = true; let lastSec_outputLimit_auto_in_out_Limit = 0; let lastSec_inputLimit_auto_in_out_Limit = 0; let lastSec_criticalMode = 0; let lastSec_change_acModeAllowed = 0; let batteryRecoveryStartSec = 0; let batteryLock = false; let batteryRecoveryPending = 0; // aktuelle Sekunden function getNowSec() { return Math.floor(Date.now() / 1000); } // sicherer getState mit Fallback, verhindert Abstürze bei fehlenden Datenpunkten function getSafeVal(dpId, fallback) { if (fallback === undefined) fallback = 0; let state = getState(dpId); if (state && state.val !== undefined && state.val !== null) { return state.val; } return fallback; } // konfiguration prüfen und ggf. auf Standardwerte zurücksetzen if (chargingStep < 10 || chargingStep > 100) chargingStep = 50; if (dischargeStep < 10 || dischargeStep > 60) dischargeStep = 10; if (wattChangeThreshold < 6 || wattChangeThreshold > 60) wattChangeThreshold = 30; if (safetyReserve < 0 || safetyReserve > 60) safetyReserve = 20; // Hardware-Maxima aus den Geräte-Eigenschaften lesen (mit Absturzsicherung) let maxHardwareOutput = getSafeVal(DP_INVERSE_MAX_POWER, 800); let maxHardwareCharge = getSafeVal(DP_CHARGE_MAX_LIMIT, 800); let max_outputLimit = maxHardwareOutput; let max_inputLimit = maxHardwareCharge; if (criticalOutputLimit > maxHardwareOutput) criticalOutputLimit = maxHardwareOutput; if (batteryLockMinCellVoltage < 3.0 || batteryLockMinCellVoltage > 3.4 || batteryLockMinCellVoltage >= batteryUnlockMinCellVoltage) { batteryLockMinCellVoltage = 3.16; } if (batteryUnlockMinCellVoltage < 3.2 || batteryUnlockMinCellVoltage > 3.4 || batteryUnlockMinCellVoltage <= batteryLockMinCellVoltage) { batteryUnlockMinCellVoltage = 3.25; } if (batteryRecoveryTimeSec < 60 || batteryRecoveryTimeSec > 1800) batteryRecoveryTimeSec = 300; console.info('Nulleinspeisung gestartet. Batterien: ' + batAnz); // RELAIS-SCHUTZ: Zeitpunkt des letzten Moduswechsels (Laden <-> Entladen) merken on({ id: DP_AC_MODE, change: 'ne' }, function () { lastSec_change_acModeAllowed = getNowSec(); }); // MAIN TRIGGER: reagiert auf den Stromzähler on({ id: DP_GRID_METER_TRIGGER, change: 'ne' }, function (obj) { let gridMeterValue = Math.ceil(obj.state.val || 0); let nowSec = getNowSec(); // 1. ZELLSPANNUNGEN UND GERÄTE-WERTE AUSLESEN // Es wird die niedrigste Zellspannung aller vorhandenen Batterien verwendet. let minCell = getSafeVal(DP_MIN_VOL_PACK1, 3.3); if (batAnz >= 2) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK2, 3.3)); if (batAnz >= 3) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK3, 3.3)); if (batAnz >= 4) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK4, 3.3)); if (batAnz >= 5) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK5, 3.3)); if (batAnz >= 6) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK6, 3.3)); let socLimitState = getSafeVal(DP_SOC_LIMIT, 0); let packState = getSafeVal(DP_PACK_STATE, 0); let currentSoc = getSafeVal(DP_ELECTRIC_LEVEL, 0); let minSocLimit = getSafeVal(DP_MIN_SOC, 10); let maxSocLimit = getSafeVal(DP_SOC_SET, 100); // 2. BATTERIE-ENTLADESCHUTZ if (socLimitState === 2 || (minCell <= batteryLockMinCellVoltage && packState !== 1)) { if (!batteryLock) { batteryLock = true; console.info('Zellschutz AKTIVIERT. Mindestspannung unterschritten oder SoC-Limit erreicht.'); } } // Freigabe nach der Sperre (erst nach Beruhigungszeit) if (minCell >= batteryUnlockMinCellVoltage && batteryLock && batteryRecoveryPending === 0 && socLimitState !== 2) { batteryRecoveryPending = 1; batteryRecoveryStartSec = nowSec; } if (batteryRecoveryPending === 1 && socLimitState !== 2 && (nowSec - batteryRecoveryStartSec >= batteryRecoveryTimeSec)) { if (minCell < batteryUnlockMinCellVoltage) { batteryRecoveryPending = 0; // Zellen wieder eingebrochen, Abbruch } else { batteryLock = false; batteryRecoveryPending = 0; console.info('Zellschutz ERFOLGREICH DEAKTIVIERT. Batterien wieder stabil.'); } } // true = Entladen ist gesperrt let protectionActive = (batteryLock || socLimitState === 2); // 3. aktuellen Hausverbrauch (ohne Bat) berechnen // positiv = Verbrauch / Netzbezug, negativ = Überschuss let netPowerWithoutBattery = (gridMeterValue - getSafeVal(DP_GRID_INPUT_POWER)) + getSafeVal(DP_OUTPUT_HOME_POWER); // 4. hoher Leistungsbedarf (criticalMode) // Darf NUR laufen, wenn KEIN Batterieschutz greift if (!protectionActive && gridMeterValue >= criticalGridPower && dplAktiv && (nowSec - lastSec_criticalMode > intervalSec_criticalMode)) { // criticalMode starten dplAktiv = false; let critLimit = Math.min(Math.ceil(Math.max(netPowerWithoutBattery, 0)), criticalOutputLimit); setState(DP_AUTO_IN_OUT_LIMIT, critLimit); console.info('Critical Mode AN: auto_in_out_Limit gesetzt auf: ' + critLimit + ' W'); lastSec_criticalMode = nowSec; lastSec_outputLimit_auto_in_out_Limit = nowSec; } else if (!dplAktiv && (protectionActive || (nowSec - lastSec_criticalMode > intervalSec_criticalMode))) { // criticalMode läuft: verlängern oder beenden if (gridMeterValue >= criticalGridPower && !protectionActive) { let critLimit = Math.min(Math.ceil(Math.max(netPowerWithoutBattery, 0)), criticalOutputLimit); if (critLimit !== getSafeVal(DP_OUTPUT_LIMIT)) { setState(DP_AUTO_IN_OUT_LIMIT, critLimit); console.info('Critical Mode VERLÄNGERT: auto_in_out_Limit angepasst auf: ' + critLimit + ' W'); } lastSec_criticalMode = nowSec; lastSec_outputLimit_auto_in_out_Limit = nowSec; } else { // Lastspitze vorbei ODER Batterieschutz, dann criticalMode beenden, normale Regelung wieder freigeben lastSec_outputLimit_auto_in_out_Limit = 0; lastSec_inputLimit_auto_in_out_Limit = 0; dplAktiv = true; lastSec_criticalMode = nowSec; console.info('Critical Mode AUS: Zurück zur normalen Regelung.'); } } // 5. normale Regelung Nulleinspeisung & Laderegelung if (dplAktiv) { // Sicherstellen, dass Zendure im SmartMode (1) läuft if (getSafeVal(DP_SMART_MODE) === 0) { setState(DP_SMART_MODE, 1); } let newLimit = 0; let currentAcMode = getSafeVal(DP_AC_MODE); let acModeTimeOk = (nowSec - lastSec_change_acModeAllowed >= intervalSec_change_acModeAllowed); // Aktuell gesetzten Wert ermitteln (Laden negativ, Entladen positiv) let currentActiveLimit = 0; if (getSafeVal(DP_INPUT_LIMIT) > 0) { currentActiveLimit = getSafeVal(DP_INPUT_LIMIT) * -1; } else if (getSafeVal(DP_OUTPUT_LIMIT) > 0) { currentActiveLimit = getSafeVal(DP_OUTPUT_LIMIT); } // Hysterese: bei kleiner Abweichung wird nichts geändert let difference = Math.abs(netPowerWithoutBattery - currentActiveLimit); let hysteresisHold = (difference < wattChangeThreshold); if (hysteresisHold) { newLimit = currentActiveLimit; } // FALL A: Überschuss vorhanden, dann Ladeleistung berechnen (Wert wird negativ) if (!hysteresisHold && netPowerWithoutBattery <= -100 - safetyReserve) { let safeSurplus = netPowerWithoutBattery + safetyReserve; let steppedLimit = Math.ceil(safeSurplus / chargingStep) * chargingStep; newLimit = steppedLimit > -100 ? 0 : steppedLimit; if (newLimit <= (max_inputLimit * -1)) { newLimit = max_inputLimit * -1; } } // FALL D: NOTABSCHALTUNG bei Batterieschutz oder leerem Akku if ((protectionActive || currentSoc <= minSocLimit) && getSafeVal(DP_OUTPUT_LIMIT) > 0) { setState(DP_AUTO_IN_OUT_LIMIT, 0); console.info('auto_in_out_Limit 0: Entladen gesperrt (Batterieschutz aktiv / MinSoC erreicht)'); lastSec_outputLimit_auto_in_out_Limit = nowSec; // FALL B: Netzbezug vorhanden, dann aus Akku entladen (Wert ist positiv) } else if (!protectionActive && currentSoc > minSocLimit && netPowerWithoutBattery > 0 && !hysteresisHold && (nowSec - lastSec_outputLimit_auto_in_out_Limit >= intervalSec_outputLimit)) { let targetDemand = Math.ceil(netPowerWithoutBattery); if (targetDemand <= 30) { newLimit = 30; } else if (targetDemand <= 60) { newLimit = 60; } else if (targetDemand <= 90) { newLimit = 90; } else if (targetDemand <= 100) { newLimit = 100; } else { newLimit = Math.ceil(targetDemand / dischargeStep) * dischargeStep; } if (newLimit >= max_outputLimit) { newLimit = max_outputLimit; } // Senden... Relais-Schutz: Wechsel vom Lade- in Entlade-Modus nur nach der Sperrzeit if (newLimit !== getSafeVal(DP_OUTPUT_LIMIT)) { if (currentAcMode !== 1 || acModeTimeOk) { setState(DP_AUTO_IN_OUT_LIMIT, newLimit); console.info('Entladen: auto_in_out_Limit gesetzt auf ' + newLimit + ' W'); lastSec_outputLimit_auto_in_out_Limit = nowSec; } } // FALL C: Überschuss oder kein Verbrauch, dann Laden bzw. Entladen beenden } else if (netPowerWithoutBattery <= 0 && (nowSec - lastSec_inputLimit_auto_in_out_Limit >= intervalSec_inputLimit)) { let currentPassMode = getSafeVal(DP_PASS); // Ladegrenze erreicht oder Gerät im Pass-Modus -> nicht laden let chargeBlocked = (socLimitState === 1 || currentSoc >= maxSocLimit || currentPassMode === 2); if (chargeBlocked && newLimit < 0) { newLimit = 0; } if (newLimit !== currentActiveLimit) { // Relais-Schutz: Wechsel vom Entlade- ins Lade-Modus nur nach der Sperrzeit (Stoppen ist immer erlaubt) if (newLimit === 0 || currentAcMode !== 2 || acModeTimeOk) { setState(DP_AUTO_IN_OUT_LIMIT, newLimit); console.info('auto_in_out_Limit gesetzt auf ' + newLimit + ' W (negativ = Laden, 0 = Aus)'); lastSec_inputLimit_auto_in_out_Limit = nowSec; if (newLimit === 0) { lastSec_outputLimit_auto_in_out_Limit = nowSec; } } } } } }); -
HINWEIS:
Der originale Firmware-Code verifiziert, dass (z. B. bei MQTT im Standard) alle 5000 ms automatisch ein Report published wird.Wenn mittels GET via zenSDK noch schneller abgefragt wird, kann es hardwarebedingt vorkommen, dass man alte bzw. identische Werte empfängt. Es ist m. M. n. daher sinnfrei, schneller als alle 4000–5000 ms abzufragen.
10.10.2026; 16:28h Memo:
Ab Firmware > V2.0.2 (bzw. V2.0.4) wird eine weitere, spezifische proprietäre Endstelle/Adresse hinzugefügt.
edit 11.10.2026; 08:20h
2400AC Pro; Firmware: 2.0.4
seit 11.10.2026; 05:51:15h mit mosquitto als Broker über Port: 1883 ohne TLS verbunden (Bridge-Modus Cloud).edit: Memo
edit 11.10.2026; 12:04h
2400AC Pro; seit 11.10.2026; 05:51:15h mit mosquitto als Broker über Port: 1883 ohne TLS verbunden (Bridge-Modus Cloud).
App: Parallele Steuerung in der Bridge per App funktioniert einwandfrei.
edit 11.10.2026; 13:15h report/getALL stabil.
Edit 11.10.2026, 21:40 Uhr Analyse abgeschlossen
edit: 12.10.2026; 12:40h Mythos widerlegt: BT und WiFi simultan möglich
-
Alles gut, mach dir keinen Stress. Werd am WE eh nicht viel Zeit dafür haben. Hab im Blockly den Bereich mit den Großverbrauchern jetzt erstmal deaktiviert.
ZenSDK-Script grad neu geladen und vor dem Starten den Datenpunkt ...control.acMode gelöscht.

Ich teste weiter.ok, Bitte habe Nachsicht mit mir, dass ich nicht die Zeit finde, das alles in Blockly zusammenzuklicken.
Ich habe das Ganze nun – auf die Schnelle – in reinem JavaScript umgesetzt. Das ist für mich wesentlich einfacher zu lesen, und eventuelle Fehler sind schneller zu finden und zu beheben.
Ich habe das JS extra für Einsteiger geschrieben und sehr einfach gehalten, damit es leicht nachvollziehbar ist.
Oben im Skript muss nur noch die Konfiguration eingetragen werden, ohne dass man (wie im Blockly) mühsam unzählige Datenpunkte manuell anpassen muss.
Bitte einfach mal testen.
Ich denke, es ist ausreichend kommentiert...Das Skript ist bei mir nur kurzfristig auf Lauffähigkeit getestet, sollte aber einwandfrei funktionieren.
// ZENDURE einfache NULLEINSPEISUNG - ioBroker JavaScript-Adapter // Wahlweise 1 bis 6 Batterien. Keine Schleifen, einfach zu lesen für Einsteiger // Für alle Geräte ab 2025/2026, die zenSDK unterstützen, wie z. B.: // SF800, SF800 PLUS, 800Pro (2), 1600AC, SF2400AC(+) usw. // (c) maxclaudi 09.10.2026_18:00h für das ioBroker-Forum // // EIN WORT IN EIGENER SACHE:. // In der Vergangenheit wurden meine Erkenntnisse oft ohne Erwähnung in andere Projekte übernommen. // Ich teile diesen Code gerne. // Wer diese(n) Code/Logik in öffentliche Adapter integriert oder anderweitig - auch Auszugsweise verwenden möchte, ist herzlich // eingeladen – ich bitte jedoch um die Fairness, die Quelle zu nennen. // Das ist der "Lohn" für meine Zeit und Forschung. // ====================================================================================== // 1. KONFIGURATION: HIER PFADE UND DATENPUNKTE und Anzahl der Batterien ANPASSEN // Trigger-Datenpunkt (Stromzähler / Smart Meter, Netzbezug in Watt) const DP_GRID_METER_TRIGGER = '0_userdata.0.Datenpunkte.zendureSolarFlow.user.ZaehlerTrigger_easy_shelly'; // Haupt-Verzeichnis des Zendure-Datenpunkte-Scripts (muss identisch sein) const folderZendureApi = '0_userdata.0.zendure.' + "2400ACproZENsdk"; // Wie viele Batterien hast du? Mögliche Werte: 1, 2, 3, 4, 5 oder 6 const vorhandeneBatAnz = 2; // Seriennummern der Batterien. // Nur die Seriennummer eintragen (ohne ".minVol"), nicht benötigte Zeilen einfach so lassen. const akku1sn = "Cxxxxxxxxxxxxx1"; // z.B.: const akku1sn = "JO2AEP1P0605193"; const akku2sn = "Cxxxxxxxxxxxxx2"; const akku3sn = "Cxxxxxxxxxxxxx3"; const akku4sn = "Cxxxxxxxxxxxxx4"; const akku5sn = "Cxxxxxxxxxxxxx5"; const akku6sn = "Cxxxxxxxxxxxxx6"; // 2. REGEL-PARAMETER (die Standardwerte müssten für die meisten Zendure-Geräte passen) //--------------------------------------------------------------------------------------- let intervalSec_outputLimit = 15; // Entladen frühestens nach X Sekunden. Standard: 15 s let intervalSec_inputLimit = 20; // Laden frühestens nach X Sekunden. Standard: 20 s let chargingStep = 50; // Schritte AC-Laden (z.B. 50 W, 100 W). Standard: 50 W let dischargeStep = 10; // Schritte Entladen, wird aufgerundet. Standard: 10 W let wattChangeThreshold = 30; // Hysterese: Änderungen erst ab X Watt Abweichung. Standard: 30 W let safetyReserve = 20; // Sicherheitsreserve gegen Netzbezug beim Laden. Standard: 20 W let criticalGridPower = 600; // Ab wie viel Watt Netzbezug gilt es als hoher Leistungsabruf. Standard: 600 W let criticalOutputLimit = 1600; // Maximale Entladeleistung im Critical-Mode (nicht größer als dein Gerät: 800, 1000, 2400 W) let intervalSec_criticalMode = 45; // So lange wird die Spitze gehalten (taktende Großverbraucher: Herd, Klima, Durchlauferhitzer) let intervalSec_change_acModeAllowed = 45; // Relais-Schutz: Sperrzeit nach einem Moduswechsel in Sekunden, bitte nicht zu kurz let batteryLockMinCellVoltage = 3.17; // Entladesperre bei dieser Zellspannung: 3.16 bis 3.20 V let batteryUnlockMinCellVoltage = 3.25; // Freigabe nach der Sperre ab dieser Zellspannung. Standard: 3.25 V let batteryRecoveryTimeSec = 300; // Beruhigungszeit der Zellen in Sekunden. Standard: 300 s (5 min) //--------------------------------------------------------------------------------------- // AB HIER NICHTS VERÄNDERN! //--------------------------------------------------------------------------------------- // Anzahl Batterien absichern (nur 1 bis 6 erlaubt) let batAnz = Math.round(vorhandeneBatAnz); if (!(batAnz >= 1)) batAnz = 1; if (batAnz > 6) batAnz = 6; // Basis-Pfade zu den Zendure-Eigenschaften const BASE_PATH_PROPERTIES = folderZendureApi + '.properties.'; const BASE_PATH_CONTROL = folderZendureApi + '.control.'; const BASE_PATH_PACKDATA = folderZendureApi + '.packData.'; // Zellspannungs-Datenpunkt einer Batterie zusammensetzen // (ein versehentlich mit eingetragenes ".minVol" wird automatisch entfernt) function packDp(sn) { return BASE_PATH_PACKDATA + String(sn).replace('.minVol', '') + '.minVol'; } const DP_MIN_VOL_PACK1 = packDp(akku1sn); const DP_MIN_VOL_PACK2 = packDp(akku2sn); const DP_MIN_VOL_PACK3 = packDp(akku3sn); const DP_MIN_VOL_PACK4 = packDp(akku4sn); const DP_MIN_VOL_PACK5 = packDp(akku5sn); const DP_MIN_VOL_PACK6 = packDp(akku6sn); // Spezifische Datenpunkte (automatisch zusammengesetzt) const DP_AUTO_IN_OUT_LIMIT = BASE_PATH_CONTROL + 'auto_in_out_Limit'; const DP_SMART_MODE = BASE_PATH_CONTROL + 'smartMode'; const DP_INVERSE_MAX_POWER = BASE_PATH_PROPERTIES + 'inverseMaxPower'; const DP_CHARGE_MAX_LIMIT = BASE_PATH_PROPERTIES + 'chargeMaxLimit'; const DP_GRID_INPUT_POWER = BASE_PATH_PROPERTIES + 'gridInputPower'; const DP_OUTPUT_HOME_POWER = BASE_PATH_PROPERTIES + 'outputHomePower'; const DP_INPUT_LIMIT = BASE_PATH_PROPERTIES + 'inputLimit'; const DP_OUTPUT_LIMIT = BASE_PATH_PROPERTIES + 'outputLimit'; const DP_AC_MODE = BASE_PATH_PROPERTIES + 'acMode'; const DP_PASS = BASE_PATH_PROPERTIES + 'pass'; const DP_SOC_LIMIT = BASE_PATH_PROPERTIES + 'socLimit'; const DP_PACK_STATE = BASE_PATH_PROPERTIES + 'packState'; const DP_ELECTRIC_LEVEL = BASE_PATH_PROPERTIES + 'electricLevel'; const DP_MIN_SOC = BASE_PATH_PROPERTIES + 'minSoc'; const DP_SOC_SET = BASE_PATH_PROPERTIES + 'socSet'; // Merker-Variablen let dplAktiv = true; let lastSec_outputLimit_auto_in_out_Limit = 0; let lastSec_inputLimit_auto_in_out_Limit = 0; let lastSec_criticalMode = 0; let lastSec_change_acModeAllowed = 0; let batteryRecoveryStartSec = 0; let batteryLock = false; let batteryRecoveryPending = 0; // aktuelle Sekunden function getNowSec() { return Math.floor(Date.now() / 1000); } // sicherer getState mit Fallback, verhindert Abstürze bei fehlenden Datenpunkten function getSafeVal(dpId, fallback) { if (fallback === undefined) fallback = 0; let state = getState(dpId); if (state && state.val !== undefined && state.val !== null) { return state.val; } return fallback; } // konfiguration prüfen und ggf. auf Standardwerte zurücksetzen if (chargingStep < 10 || chargingStep > 100) chargingStep = 50; if (dischargeStep < 10 || dischargeStep > 60) dischargeStep = 10; if (wattChangeThreshold < 6 || wattChangeThreshold > 60) wattChangeThreshold = 30; if (safetyReserve < 0 || safetyReserve > 60) safetyReserve = 20; // Hardware-Maxima aus den Geräte-Eigenschaften lesen (mit Absturzsicherung) let maxHardwareOutput = getSafeVal(DP_INVERSE_MAX_POWER, 800); let maxHardwareCharge = getSafeVal(DP_CHARGE_MAX_LIMIT, 800); let max_outputLimit = maxHardwareOutput; let max_inputLimit = maxHardwareCharge; if (criticalOutputLimit > maxHardwareOutput) criticalOutputLimit = maxHardwareOutput; if (batteryLockMinCellVoltage < 3.0 || batteryLockMinCellVoltage > 3.4 || batteryLockMinCellVoltage >= batteryUnlockMinCellVoltage) { batteryLockMinCellVoltage = 3.16; } if (batteryUnlockMinCellVoltage < 3.2 || batteryUnlockMinCellVoltage > 3.4 || batteryUnlockMinCellVoltage <= batteryLockMinCellVoltage) { batteryUnlockMinCellVoltage = 3.25; } if (batteryRecoveryTimeSec < 60 || batteryRecoveryTimeSec > 1800) batteryRecoveryTimeSec = 300; console.info('Nulleinspeisung gestartet. Batterien: ' + batAnz); // RELAIS-SCHUTZ: Zeitpunkt des letzten Moduswechsels (Laden <-> Entladen) merken on({ id: DP_AC_MODE, change: 'ne' }, function () { lastSec_change_acModeAllowed = getNowSec(); }); // MAIN TRIGGER: reagiert auf den Stromzähler on({ id: DP_GRID_METER_TRIGGER, change: 'ne' }, function (obj) { let gridMeterValue = Math.ceil(obj.state.val || 0); let nowSec = getNowSec(); // 1. ZELLSPANNUNGEN UND GERÄTE-WERTE AUSLESEN // Es wird die niedrigste Zellspannung aller vorhandenen Batterien verwendet. let minCell = getSafeVal(DP_MIN_VOL_PACK1, 3.3); if (batAnz >= 2) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK2, 3.3)); if (batAnz >= 3) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK3, 3.3)); if (batAnz >= 4) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK4, 3.3)); if (batAnz >= 5) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK5, 3.3)); if (batAnz >= 6) minCell = Math.min(minCell, getSafeVal(DP_MIN_VOL_PACK6, 3.3)); let socLimitState = getSafeVal(DP_SOC_LIMIT, 0); let packState = getSafeVal(DP_PACK_STATE, 0); let currentSoc = getSafeVal(DP_ELECTRIC_LEVEL, 0); let minSocLimit = getSafeVal(DP_MIN_SOC, 10); let maxSocLimit = getSafeVal(DP_SOC_SET, 100); // 2. BATTERIE-ENTLADESCHUTZ if (socLimitState === 2 || (minCell <= batteryLockMinCellVoltage && packState !== 1)) { if (!batteryLock) { batteryLock = true; console.info('Zellschutz AKTIVIERT. Mindestspannung unterschritten oder SoC-Limit erreicht.'); } } // Freigabe nach der Sperre (erst nach Beruhigungszeit) if (minCell >= batteryUnlockMinCellVoltage && batteryLock && batteryRecoveryPending === 0 && socLimitState !== 2) { batteryRecoveryPending = 1; batteryRecoveryStartSec = nowSec; } if (batteryRecoveryPending === 1 && socLimitState !== 2 && (nowSec - batteryRecoveryStartSec >= batteryRecoveryTimeSec)) { if (minCell < batteryUnlockMinCellVoltage) { batteryRecoveryPending = 0; // Zellen wieder eingebrochen, Abbruch } else { batteryLock = false; batteryRecoveryPending = 0; console.info('Zellschutz ERFOLGREICH DEAKTIVIERT. Batterien wieder stabil.'); } } // true = Entladen ist gesperrt let protectionActive = (batteryLock || socLimitState === 2); // 3. aktuellen Hausverbrauch (ohne Bat) berechnen // positiv = Verbrauch / Netzbezug, negativ = Überschuss let netPowerWithoutBattery = (gridMeterValue - getSafeVal(DP_GRID_INPUT_POWER)) + getSafeVal(DP_OUTPUT_HOME_POWER); // 4. hoher Leistungsbedarf (criticalMode) // Darf NUR laufen, wenn KEIN Batterieschutz greift if (!protectionActive && gridMeterValue >= criticalGridPower && dplAktiv && (nowSec - lastSec_criticalMode > intervalSec_criticalMode)) { // criticalMode starten dplAktiv = false; let critLimit = Math.min(Math.ceil(Math.max(netPowerWithoutBattery, 0)), criticalOutputLimit); setState(DP_AUTO_IN_OUT_LIMIT, critLimit); console.info('Critical Mode AN: auto_in_out_Limit gesetzt auf: ' + critLimit + ' W'); lastSec_criticalMode = nowSec; lastSec_outputLimit_auto_in_out_Limit = nowSec; } else if (!dplAktiv && (protectionActive || (nowSec - lastSec_criticalMode > intervalSec_criticalMode))) { // criticalMode läuft: verlängern oder beenden if (gridMeterValue >= criticalGridPower && !protectionActive) { let critLimit = Math.min(Math.ceil(Math.max(netPowerWithoutBattery, 0)), criticalOutputLimit); if (critLimit !== getSafeVal(DP_OUTPUT_LIMIT)) { setState(DP_AUTO_IN_OUT_LIMIT, critLimit); console.info('Critical Mode VERLÄNGERT: auto_in_out_Limit angepasst auf: ' + critLimit + ' W'); } lastSec_criticalMode = nowSec; lastSec_outputLimit_auto_in_out_Limit = nowSec; } else { // Lastspitze vorbei ODER Batterieschutz, dann criticalMode beenden, normale Regelung wieder freigeben lastSec_outputLimit_auto_in_out_Limit = 0; lastSec_inputLimit_auto_in_out_Limit = 0; dplAktiv = true; lastSec_criticalMode = nowSec; console.info('Critical Mode AUS: Zurück zur normalen Regelung.'); } } // 5. normale Regelung Nulleinspeisung & Laderegelung if (dplAktiv) { // Sicherstellen, dass Zendure im SmartMode (1) läuft if (getSafeVal(DP_SMART_MODE) === 0) { setState(DP_SMART_MODE, 1); } let newLimit = 0; let currentAcMode = getSafeVal(DP_AC_MODE); let acModeTimeOk = (nowSec - lastSec_change_acModeAllowed >= intervalSec_change_acModeAllowed); // Aktuell gesetzten Wert ermitteln (Laden negativ, Entladen positiv) let currentActiveLimit = 0; if (getSafeVal(DP_INPUT_LIMIT) > 0) { currentActiveLimit = getSafeVal(DP_INPUT_LIMIT) * -1; } else if (getSafeVal(DP_OUTPUT_LIMIT) > 0) { currentActiveLimit = getSafeVal(DP_OUTPUT_LIMIT); } // Hysterese: bei kleiner Abweichung wird nichts geändert let difference = Math.abs(netPowerWithoutBattery - currentActiveLimit); let hysteresisHold = (difference < wattChangeThreshold); if (hysteresisHold) { newLimit = currentActiveLimit; } // FALL A: Überschuss vorhanden, dann Ladeleistung berechnen (Wert wird negativ) if (!hysteresisHold && netPowerWithoutBattery <= -100 - safetyReserve) { let safeSurplus = netPowerWithoutBattery + safetyReserve; let steppedLimit = Math.ceil(safeSurplus / chargingStep) * chargingStep; newLimit = steppedLimit > -100 ? 0 : steppedLimit; if (newLimit <= (max_inputLimit * -1)) { newLimit = max_inputLimit * -1; } } // FALL D: NOTABSCHALTUNG bei Batterieschutz oder leerem Akku if ((protectionActive || currentSoc <= minSocLimit) && getSafeVal(DP_OUTPUT_LIMIT) > 0) { setState(DP_AUTO_IN_OUT_LIMIT, 0); console.info('auto_in_out_Limit 0: Entladen gesperrt (Batterieschutz aktiv / MinSoC erreicht)'); lastSec_outputLimit_auto_in_out_Limit = nowSec; // FALL B: Netzbezug vorhanden, dann aus Akku entladen (Wert ist positiv) } else if (!protectionActive && currentSoc > minSocLimit && netPowerWithoutBattery > 0 && !hysteresisHold && (nowSec - lastSec_outputLimit_auto_in_out_Limit >= intervalSec_outputLimit)) { let targetDemand = Math.ceil(netPowerWithoutBattery); if (targetDemand <= 30) { newLimit = 30; } else if (targetDemand <= 60) { newLimit = 60; } else if (targetDemand <= 90) { newLimit = 90; } else if (targetDemand <= 100) { newLimit = 100; } else { newLimit = Math.ceil(targetDemand / dischargeStep) * dischargeStep; } if (newLimit >= max_outputLimit) { newLimit = max_outputLimit; } // Senden... Relais-Schutz: Wechsel vom Lade- in Entlade-Modus nur nach der Sperrzeit if (newLimit !== getSafeVal(DP_OUTPUT_LIMIT)) { if (currentAcMode !== 1 || acModeTimeOk) { setState(DP_AUTO_IN_OUT_LIMIT, newLimit); console.info('Entladen: auto_in_out_Limit gesetzt auf ' + newLimit + ' W'); lastSec_outputLimit_auto_in_out_Limit = nowSec; } } // FALL C: Überschuss oder kein Verbrauch, dann Laden bzw. Entladen beenden } else if (netPowerWithoutBattery <= 0 && (nowSec - lastSec_inputLimit_auto_in_out_Limit >= intervalSec_inputLimit)) { let currentPassMode = getSafeVal(DP_PASS); // Ladegrenze erreicht oder Gerät im Pass-Modus -> nicht laden let chargeBlocked = (socLimitState === 1 || currentSoc >= maxSocLimit || currentPassMode === 2); if (chargeBlocked && newLimit < 0) { newLimit = 0; } if (newLimit !== currentActiveLimit) { // Relais-Schutz: Wechsel vom Entlade- ins Lade-Modus nur nach der Sperrzeit (Stoppen ist immer erlaubt) if (newLimit === 0 || currentAcMode !== 2 || acModeTimeOk) { setState(DP_AUTO_IN_OUT_LIMIT, newLimit); console.info('auto_in_out_Limit gesetzt auf ' + newLimit + ' W (negativ = Laden, 0 = Aus)'); lastSec_inputLimit_auto_in_out_Limit = nowSec; if (newLimit === 0) { lastSec_outputLimit_auto_in_out_Limit = nowSec; } } } } } });Danke Dir, probier ich die Tage aus.
Hatte nach dem Firmware-Update auf 2.0.2 gestern den Fehlercode 33, der ja offensichtlich ein Bug zu sein scheint. Hab aber noch keine neue Firmware verfügbar bei mir.
Das mit dem Absinken deutlich unter 10% soll auch mit der Firmware zu tun haben, hab ich gestern gelesen, aber 100% sicher ist das natürlich nicht. Evtl schreib ich mal den Support an, ob ich vorgezogen werden kann mit dem Update.
Warte aktuell darauf, dass der Wechselrichter startet, aber die Sonne tut sich grad noch schwer... -
Danke Dir, probier ich die Tage aus.
Hatte nach dem Firmware-Update auf 2.0.2 gestern den Fehlercode 33, der ja offensichtlich ein Bug zu sein scheint. Hab aber noch keine neue Firmware verfügbar bei mir.
Das mit dem Absinken deutlich unter 10% soll auch mit der Firmware zu tun haben, hab ich gestern gelesen, aber 100% sicher ist das natürlich nicht. Evtl schreib ich mal den Support an, ob ich vorgezogen werden kann mit dem Update.
Warte aktuell darauf, dass der Wechselrichter startet, aber die Sonne tut sich grad noch schwer...@T-147
Neben einem reinen Software-Bug können es auch kurzzeitige Spannungsschwankungen oder Kriechströme an den MC4-Steckern der PV-Module sein. Ich würde an deiner Stelle die Steckverbindungen mal kontrollieren – nicht dass sich dort Feuchtigkeit eingeschlichen hat oder Kontaktprobleme vorhanden sind.
Sollte es sich beim Pro tatsächlich um einen Bug handeln: Nach meinen Analysen ist die V2.0.2 (bzw. die darin enthaltene ESP-Steuerungs-Firmware) – wenn auch vielleicht nicht absolut fehlerfrei – m. M. n. immer noch die stabilste Version. -
07.10.2026_21:20h
Da es dazu weltweit quasi null Infos gibt, dachte ich, ich teile meine bisherigen Erkenntnisse mal auszugsweise als kleinen Bericht mit euch.
Wer möchte kann den Bericht im spoiler lesen, für alle anderen ist der Beitrag dann kürzer und kann ignoriert werden :-)
edit 21.10.2026; 10:54h erledigt.
Suche vertrauenswürdige(n) Mitwirkende(n) für unabhängige, private Tests⚠️ Wichtiger Hinweis zur Vertraulichkeit:
Da es sich hierbei um ein experimentelles Setup handelt, suche ich Tester, die absolut verlässlich sind.
Ich bitte eindringlich darum, Testergebnisse, Script-Details und den Ablauf der Tests streng vertraulich zu behandeln.
Die Kommunikation soll ausschließlich im privaten Kreis (per PN/E-Mail) stattfinden und nicht öffentlich im Forum oder an anderen Stellen gepostet werden.
DurchgestrichenBitte melde dich nur, wenn du mit dieser Geheimhaltung einverstanden bist.Voraussetzungen:
- ioBroker
- Das zenSDK-Steuerungs-Script aus diesem Thread
- Zendure-App (nur für Erst-Verbindung nötig)
- Zendure-Gerät mit zenSDK-Unterstützung
Idealerweise vorhanden (vorzugsweise):
- AdGuard Home oder Pi-hole, um eine DNS-Umschreibung einzurichten
- Eigener Mosquitto-Broker (oder ein anderer MQTT-Broker)
und / oder:
- Eine FRITZ!Box (oder ein anderer Router), um dem Gerät die Internetverbindung zu sperren
Gesucht werden maximal 2 Testpersonen. Bei Interesse bitte ausschließlich per PN oder E-Mail bei mir melden, damit der Thread hier sauber bleibt. Danke!ztool.maxclaudi AT gmail . com
edit: Um Bots oder Fake-Anfragen auszuschließen, ist ein bestehender Account im ioBroker-Forum oder einem etablierten PV-Forum erforderlich.
Interessierte ohne Foren-Historie können leider nicht berücksichtigt werden.
Jedes aktive Mitglied – egal ob Profi oder Einsteiger – ist herzlich willkommen!
Bei Interesse bitte einfach per PM oder E-Mail melden.
-
@T-147
ich hab den SF800pro2 mit 2.0.2, war schon bei der Erstinbetreiebnahme drauf, mitZwei AB2000, ein 2 Jahre alter und der vom SF800pro2
Hatte letzte Woche auch "Tiefentladung" bis 2,56V(alter AB) bzw. 2,7V (neuerAB) am Morgen und er ist schon mehrfach im Einspeisemodus hängengeblieben aber bisher noch nie so Teifenladen. Ich musste dann eingreifen und aus dem Netz laden, was ich bisher vermieden habe weil vormittags keine Sonne. Als die Akkus wieder auf 20% waren hat er sich wieder gefangen und wieder normal gearbeitet.
Ich habe das SDK-Skript und den Blockly von maxclaudi, 4x 450Wp OSO/WNW, je eins an einem MPT.
Vorher hatte ich je zwei am SF1200+HM800.
Ich hab das Gefühl die Ausbeute war durch die OpenDTUonBatt besser, weniger ungewollte Einspeisung.peter
-
-
@T-147
ich hab den SF800pro2 mit 2.0.2, war schon bei der Erstinbetreiebnahme drauf, mitZwei AB2000, ein 2 Jahre alter und der vom SF800pro2
Hatte letzte Woche auch "Tiefentladung" bis 2,56V(alter AB) bzw. 2,7V (neuerAB) am Morgen und er ist schon mehrfach im Einspeisemodus hängengeblieben aber bisher noch nie so Teifenladen. Ich musste dann eingreifen und aus dem Netz laden, was ich bisher vermieden habe weil vormittags keine Sonne. Als die Akkus wieder auf 20% waren hat er sich wieder gefangen und wieder normal gearbeitet.
Ich habe das SDK-Skript und den Blockly von maxclaudi, 4x 450Wp OSO/WNW, je eins an einem MPT.
Vorher hatte ich je zwei am SF1200+HM800.
Ich hab das Gefühl die Ausbeute war durch die OpenDTUonBatt besser, weniger ungewollte Einspeisung.peter
@T-147
ich hab den SF800pro2 mit 2.0.2, war schon bei der Erstinbetreiebnahme drauf, mitZwei AB2000, ein 2 Jahre alter und der vom SF800pro2
Hatte letzte Woche auch "Tiefentladung" bis 2,56V(alter AB) bzw. 2,7V (neuerAB) am Morgen und er ist schon mehrfach im Einspeisemodus hängengeblieben aber bisher noch nie so Teifenladen. Ich musste dann eingreifen und aus dem Netz laden, was ich bisher vermieden habe weil vormittags keine Sonne. Als die Akkus wieder auf 20% waren hat er sich wieder gefangen und wieder normal gearbeitet.
Ich habe das SDK-Skript und den Blockly von maxclaudi, 4x 450Wp OSO/WNW, je eins an einem MPT.Bitte verwende statt Blockly mal das JS-Script aus #Post 610
Damit sollte der Batterieschutz übergeordnet greifen, falls die Firmware selbst einmal nicht rechtzeitig einlenkt.Vorher hatte ich je zwei am SF1200+HM800.
Ich hab das Gefühl die Ausbeute war durch die OpenDTUonBatt besser, weniger ungewollte Einspeisung.Dazu kannst du die Regelwerte im JS-Skript ganz einfach anpassen und optimieren. Teste dafür mal die Parameter im Konfigurationsbereich:
let intervalSec_outputLimit = 15; // Entladen frühestens nach X Sekunden. Standard: 15 s let intervalSec_inputLimit = 20; // Laden frühestens nach X Sekunden. Standard: 20 s let chargingStep = 50; // Schritte AC-Laden (z.B. 50 W, 100 W). Standard: 50 W let dischargeStep = 10; // Schritte Entladen, wird aufgerundet. Standard: 10 W let wattChangeThreshold = 20; // Hysterese Watt oder 15W testen let safetyReserve = 20; // Sicherheitsreserve gegen Netzbezug beim Laden. Standard: 20 W let criticalGridPower = 600; // Ab wie viel Watt Netzbezug gilt es als hoher Leistungsabruf. Standard: 600 W let criticalOutputLimit = 800; // Maximale Entladeleistung im Critical-Mode let intervalSec_criticalMode = 30; // So lange wird die Spitze gehalten (taktende Großverbraucher: Herd, Klima, Durchlauferhitzer) let intervalSec_change_acModeAllowed = 30; // Relais-Schutz z.B. 30s let batteryLockMinCellVoltage = 3.20; // Entladesperre z.B. 3.20 V let batteryUnlockMinCellVoltage = 3.25; // Freigabe nach der Sperre sek let batteryRecoveryTimeSec = 300; // Beruhigungszeit der Zellen in Sekunden. Standard: 300 s (5 min)Subjektiv empfinde ich die Wechselrichter von Hoymiles ebenfalls um Welten besser als die integrierten Zendure-Inverter. Deswegen nutze ich inzwischen auch die gridOff-Steckdose bzw. Hoymiles direkt am Netz und lade/entlade die Zendure-Geräte ausschließlich über AC 230V.
Trotz der zusätzlichen Wandlerverluste scheint das System inklusive der Regelung bei mir unterm Strich produktiver zu laufen, als die PV-Leistung direkt über DC in das Zendure-Gerät einzuspeisen.
Auch wenn es theoretisch durch die Wandlungsverluste (DC ➔ AC ➔ DC ➔ AC) ineffizienter sein müsste, zeigt die Praxis bei mir, dass die exzellente MPPT-Regelung der Hoymiles und deren extrem niedrige Latenz anscheinend die träge Zendure-DC-Regelung ausstechen.
Elektrotechnisch ist das eigentlich paradox und auf den ersten Blick schwer zu erklären – denn der direkte Weg über PV (DC) ➔ Laderegler ➔ Batterie (48V DC) müsste rein rechnerisch immer im Vorteil sein.
Dennoch arbeiten hier völlig unterschiedliche Herstellerphilosophien auf Protokoll- und Hardwareebene gegeneinander, und in meiner Praxis bewährt sich die AC-Variante deutlich besser.
Seit heute Nacht gibt es die Version 2.0.5
Kann man die bedenkenlos installieren oder sollte man lieber noch ein bisschen abwarten?Die V2.0.5 kann ich für dein spezifisches Gerät – und auch allgemein – nicht beurteilen.
Normalerweise fahre ich die Strategie: Abwarten.
Wenn das System aktuell stabil läuft, gibt es keinen akuten Grund für Eile. Falls du jedoch gravierende Probleme im laufenden Betrieb hast, würde ich das Update vorziehen.
Wenn alles unauffällig läuft: Lieber erst mal beobachten, was die Community berichtet. -
@T-147
ich hab den SF800pro2 mit 2.0.2, war schon bei der Erstinbetreiebnahme drauf, mitZwei AB2000, ein 2 Jahre alter und der vom SF800pro2
Hatte letzte Woche auch "Tiefentladung" bis 2,56V(alter AB) bzw. 2,7V (neuerAB) am Morgen und er ist schon mehrfach im Einspeisemodus hängengeblieben aber bisher noch nie so Teifenladen. Ich musste dann eingreifen und aus dem Netz laden, was ich bisher vermieden habe weil vormittags keine Sonne. Als die Akkus wieder auf 20% waren hat er sich wieder gefangen und wieder normal gearbeitet.
Ich habe das SDK-Skript und den Blockly von maxclaudi, 4x 450Wp OSO/WNW, je eins an einem MPT.Bitte verwende statt Blockly mal das JS-Script aus #Post 610
Damit sollte der Batterieschutz übergeordnet greifen, falls die Firmware selbst einmal nicht rechtzeitig einlenkt.Vorher hatte ich je zwei am SF1200+HM800.
Ich hab das Gefühl die Ausbeute war durch die OpenDTUonBatt besser, weniger ungewollte Einspeisung.Dazu kannst du die Regelwerte im JS-Skript ganz einfach anpassen und optimieren. Teste dafür mal die Parameter im Konfigurationsbereich:
let intervalSec_outputLimit = 15; // Entladen frühestens nach X Sekunden. Standard: 15 s let intervalSec_inputLimit = 20; // Laden frühestens nach X Sekunden. Standard: 20 s let chargingStep = 50; // Schritte AC-Laden (z.B. 50 W, 100 W). Standard: 50 W let dischargeStep = 10; // Schritte Entladen, wird aufgerundet. Standard: 10 W let wattChangeThreshold = 20; // Hysterese Watt oder 15W testen let safetyReserve = 20; // Sicherheitsreserve gegen Netzbezug beim Laden. Standard: 20 W let criticalGridPower = 600; // Ab wie viel Watt Netzbezug gilt es als hoher Leistungsabruf. Standard: 600 W let criticalOutputLimit = 800; // Maximale Entladeleistung im Critical-Mode let intervalSec_criticalMode = 30; // So lange wird die Spitze gehalten (taktende Großverbraucher: Herd, Klima, Durchlauferhitzer) let intervalSec_change_acModeAllowed = 30; // Relais-Schutz z.B. 30s let batteryLockMinCellVoltage = 3.20; // Entladesperre z.B. 3.20 V let batteryUnlockMinCellVoltage = 3.25; // Freigabe nach der Sperre sek let batteryRecoveryTimeSec = 300; // Beruhigungszeit der Zellen in Sekunden. Standard: 300 s (5 min)Subjektiv empfinde ich die Wechselrichter von Hoymiles ebenfalls um Welten besser als die integrierten Zendure-Inverter. Deswegen nutze ich inzwischen auch die gridOff-Steckdose bzw. Hoymiles direkt am Netz und lade/entlade die Zendure-Geräte ausschließlich über AC 230V.
Trotz der zusätzlichen Wandlerverluste scheint das System inklusive der Regelung bei mir unterm Strich produktiver zu laufen, als die PV-Leistung direkt über DC in das Zendure-Gerät einzuspeisen.
Auch wenn es theoretisch durch die Wandlungsverluste (DC ➔ AC ➔ DC ➔ AC) ineffizienter sein müsste, zeigt die Praxis bei mir, dass die exzellente MPPT-Regelung der Hoymiles und deren extrem niedrige Latenz anscheinend die träge Zendure-DC-Regelung ausstechen.
Elektrotechnisch ist das eigentlich paradox und auf den ersten Blick schwer zu erklären – denn der direkte Weg über PV (DC) ➔ Laderegler ➔ Batterie (48V DC) müsste rein rechnerisch immer im Vorteil sein.
Dennoch arbeiten hier völlig unterschiedliche Herstellerphilosophien auf Protokoll- und Hardwareebene gegeneinander, und in meiner Praxis bewährt sich die AC-Variante deutlich besser.
Seit heute Nacht gibt es die Version 2.0.5
Kann man die bedenkenlos installieren oder sollte man lieber noch ein bisschen abwarten?Die V2.0.5 kann ich für dein spezifisches Gerät – und auch allgemein – nicht beurteilen.
Normalerweise fahre ich die Strategie: Abwarten.
Wenn das System aktuell stabil läuft, gibt es keinen akuten Grund für Eile. Falls du jedoch gravierende Probleme im laufenden Betrieb hast, würde ich das Update vorziehen.
Wenn alles unauffällig läuft: Lieber erst mal beobachten, was die Community berichtet.Subjektiv empfinde ich die Wechselrichter von Hoymiles ebenfalls um Welten besser als die integrierten Zendure-Inverter. Deswegen nutze ich inzwischen auch die gridOff-Steckdose bzw. Hoymiles direkt am Netz und lade/entlade die Zendure-Geräte ausschließlich über AC 230V.
Trotz der zusätzlichen Wandlerverluste scheint das System inklusive der Regelung bei mir unterm Strich produktiver zu laufen, als die PV-Leistung direkt über DC in das Zendure-Gerät einzuspeisen.
Auch wenn es theoretisch durch die Wandlungsverluste (DC ➔ AC ➔ DC ➔ AC) ineffizienter sein müsste, zeigt die Praxis bei mir, dass die exzellente MPPT-Regelung der Hoymiles und deren extrem niedrige Latenz anscheinend die träge Zendure-DC-Regelung ausstechen.
Von wieviel Mehrertrag reden wir denn da? Macht das wirklich soviel aus?
-
@T-147
ich hab den SF800pro2 mit 2.0.2, war schon bei der Erstinbetreiebnahme drauf, mitZwei AB2000, ein 2 Jahre alter und der vom SF800pro2
Hatte letzte Woche auch "Tiefentladung" bis 2,56V(alter AB) bzw. 2,7V (neuerAB) am Morgen und er ist schon mehrfach im Einspeisemodus hängengeblieben aber bisher noch nie so Teifenladen. Ich musste dann eingreifen und aus dem Netz laden, was ich bisher vermieden habe weil vormittags keine Sonne. Als die Akkus wieder auf 20% waren hat er sich wieder gefangen und wieder normal gearbeitet.
Ich habe das SDK-Skript und den Blockly von maxclaudi, 4x 450Wp OSO/WNW, je eins an einem MPT.Bitte verwende statt Blockly mal das JS-Script aus #Post 610
Damit sollte der Batterieschutz übergeordnet greifen, falls die Firmware selbst einmal nicht rechtzeitig einlenkt.Vorher hatte ich je zwei am SF1200+HM800.
Ich hab das Gefühl die Ausbeute war durch die OpenDTUonBatt besser, weniger ungewollte Einspeisung.Dazu kannst du die Regelwerte im JS-Skript ganz einfach anpassen und optimieren. Teste dafür mal die Parameter im Konfigurationsbereich:
let intervalSec_outputLimit = 15; // Entladen frühestens nach X Sekunden. Standard: 15 s let intervalSec_inputLimit = 20; // Laden frühestens nach X Sekunden. Standard: 20 s let chargingStep = 50; // Schritte AC-Laden (z.B. 50 W, 100 W). Standard: 50 W let dischargeStep = 10; // Schritte Entladen, wird aufgerundet. Standard: 10 W let wattChangeThreshold = 20; // Hysterese Watt oder 15W testen let safetyReserve = 20; // Sicherheitsreserve gegen Netzbezug beim Laden. Standard: 20 W let criticalGridPower = 600; // Ab wie viel Watt Netzbezug gilt es als hoher Leistungsabruf. Standard: 600 W let criticalOutputLimit = 800; // Maximale Entladeleistung im Critical-Mode let intervalSec_criticalMode = 30; // So lange wird die Spitze gehalten (taktende Großverbraucher: Herd, Klima, Durchlauferhitzer) let intervalSec_change_acModeAllowed = 30; // Relais-Schutz z.B. 30s let batteryLockMinCellVoltage = 3.20; // Entladesperre z.B. 3.20 V let batteryUnlockMinCellVoltage = 3.25; // Freigabe nach der Sperre sek let batteryRecoveryTimeSec = 300; // Beruhigungszeit der Zellen in Sekunden. Standard: 300 s (5 min)Subjektiv empfinde ich die Wechselrichter von Hoymiles ebenfalls um Welten besser als die integrierten Zendure-Inverter. Deswegen nutze ich inzwischen auch die gridOff-Steckdose bzw. Hoymiles direkt am Netz und lade/entlade die Zendure-Geräte ausschließlich über AC 230V.
Trotz der zusätzlichen Wandlerverluste scheint das System inklusive der Regelung bei mir unterm Strich produktiver zu laufen, als die PV-Leistung direkt über DC in das Zendure-Gerät einzuspeisen.
Auch wenn es theoretisch durch die Wandlungsverluste (DC ➔ AC ➔ DC ➔ AC) ineffizienter sein müsste, zeigt die Praxis bei mir, dass die exzellente MPPT-Regelung der Hoymiles und deren extrem niedrige Latenz anscheinend die träge Zendure-DC-Regelung ausstechen.
Elektrotechnisch ist das eigentlich paradox und auf den ersten Blick schwer zu erklären – denn der direkte Weg über PV (DC) ➔ Laderegler ➔ Batterie (48V DC) müsste rein rechnerisch immer im Vorteil sein.
Dennoch arbeiten hier völlig unterschiedliche Herstellerphilosophien auf Protokoll- und Hardwareebene gegeneinander, und in meiner Praxis bewährt sich die AC-Variante deutlich besser.
Seit heute Nacht gibt es die Version 2.0.5
Kann man die bedenkenlos installieren oder sollte man lieber noch ein bisschen abwarten?Die V2.0.5 kann ich für dein spezifisches Gerät – und auch allgemein – nicht beurteilen.
Normalerweise fahre ich die Strategie: Abwarten.
Wenn das System aktuell stabil läuft, gibt es keinen akuten Grund für Eile. Falls du jedoch gravierende Probleme im laufenden Betrieb hast, würde ich das Update vorziehen.
Wenn alles unauffällig läuft: Lieber erst mal beobachten, was die Community berichtet.Bitte verwende statt Blockly mal das JS-Script aus #Post 610
Damit sollte der Batterieschutz übergeordnet greifen, falls die Firmware selbst einmal nicht rechtzeitig einlenkt.Dankeschön, habs eingepflegt und auf meine daten angepasst.
Schaun mer mal...petman
Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden 💗
Registrieren Anmelden


