Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. JavaScript
  5. Zendure zenSDK Lokal API, SmartMode, SolarFlow AC 800 Pro 2

NEWS

  • Neues YouTube-Video: Visualisierung im Devices-Adapter
    BluefoxB
    Bluefox
    6
    1
    101

  • Neuer ioBroker-Blog online: Monatsrückblick März/April 2026
    BluefoxB
    Bluefox
    8
    1
    1.8k

  • Verwendung von KI bitte immer deutlich kennzeichnen
    HomoranH
    Homoran
    11
    1
    758

Zendure zenSDK Lokal API, SmartMode, SolarFlow AC 800 Pro 2

Geplant Angeheftet Gesperrt Verschoben JavaScript
290 Beiträge 14 Kommentatoren 24.2k Aufrufe 13 Beobachtet
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • Bernd1967B Offline
    Bernd1967B Offline
    Bernd1967
    schrieb am zuletzt editiert von
    #239

    Ja, das hatte ich auch schon gelesen.
    Habe HEMS in der App aktiviert und wieder deaktiviert, funktioniert nicht.

    1 Antwort Letzte Antwort
    0
    • Bernd1967B Offline
      Bernd1967B Offline
      Bernd1967
      schrieb am zuletzt editiert von
      #240

      Okay, Fehler gefunden, das Mistding hat sich ne neue IP im LAN gegönnt und war deswegen nicht erreichbar.Die Daten trudeln jetzt rein.
      Super

      maxclaudiM 1 Antwort Letzte Antwort
      1
      • Bernd1967B Bernd1967

        Okay, Fehler gefunden, das Mistding hat sich ne neue IP im LAN gegönnt und war deswegen nicht erreichbar.Die Daten trudeln jetzt rein.
        Super

        maxclaudiM Offline
        maxclaudiM Offline
        maxclaudi
        schrieb am zuletzt editiert von
        #241

        @Bernd1967
        Freut mich.
        Dann bitte nicht vergessen: mindestens über den Router eine dauerhafte, feste IP zuzuweisen

        Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

        1 Antwort Letzte Antwort
        0
        • D Daniel 8

          @maxclaudi

          Habe gestern mal dein neues Script eingebunden. Irgendwie habe ich ein Problem, das er den Smartmode nicht immer auf 1 schaltet. Ich trigger auf änderung, lasse eine Email senden, das funktioniert immer. Und gleich im Anschluss steure ich auf 1. Kann es sein wenn der Status noch nicht aktualisert wurde das es dann zum Problem kommt? Habe jetzt mal eine Verweilzeit von 5 sekunden gemacht. Da scheint es zu funktionieren.

          Gibt es eigentlich eine Möglichkeit, zu sehen ob in der Warteschlange befehle sind?

          maxclaudiM Offline
          maxclaudiM Offline
          maxclaudi
          schrieb am zuletzt editiert von maxclaudi
          #242

          @Daniel-8 sagte:

          Habe jetzt mal eine Verweilzeit von 5 sekunden gemacht. Da scheint es zu funktionieren.

          Damit meinst Du:

          const minTimeBreakForSetDpSec = 5;
          

          oder intervall?

          minTimeBreakForSetDpSec ist eigentlich nicht nötig und nur eine Schutzfunktion, falls – wie Du richtig erkannt hast:

          Kann es sein wenn der Status noch nicht aktualisert wurde das es dann zum Problem kommt?

          oder

          • wenn ein script zu schnell commands schreibt
          • oder mehrere commands (fast) gleichzeitig feuern
            edit: dann bitte script(e) der Regelung kontrollieren.
          • oder das intervall zu groß ist.

          Gibt es eigentlich eine Möglichkeit, zu sehen ob in der Warteschlange befehle sind?

          Nein, nicht nötig und geht zu schnell.

          Bin gerade an einer kompletten Überarbeitung und einem neuen Skript, damit States nicht dauernd so oft geschrieben werden etc. Das geht leider nur schleppend voran, da mir momentan die Zeit fehlt und auch noch die Zeitverschiebung zu meinem Kontakt mit reinspielt.

          Edit PPS:
          Oder hast Du auf Änderung getriggert und sendest das command erst 5 sek. später?
          Falls ja, ist das ein guter Ansatz für einen stabilen Ablauf.
          Eventuell könntest du zusätzlich das Intervall noch etwas verkürzen. Das ist jedoch individuell vom Setup abhängig (WLAN-Qualität, Zendure-Geräte etc.).

          Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

          1 Antwort Letzte Antwort
          0
          • D Offline
            D Offline
            Daniel 8
            schrieb am zuletzt editiert von
            #243

            Ich habe Smartmode auf Änderung getrickert und wenn er auf 0 springt hat er gleich wieder 1 gesetzt. Und da habe ich jetzt ein Timeout mit 5 Sekunden rein gemacht. Seit dem funktioniert es.

            Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

            1 Antwort Letzte Antwort
            1
            • D Offline
              D Offline
              Daniel 8
              schrieb am zuletzt editiert von
              #244

              Ich habe heute mal angefangen mein ganzes Steuerungsscript umzuschreiben mit deinem Script zur Abfrage. Da ist mir aufgefallen, das im pass Modus der wert nicht 1 sondern 2 ist.

              Screenshot 2026-04-23 104848.jpg

              Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

              maxclaudiM 1 Antwort Letzte Antwort
              0
              • D Daniel 8

                Ich habe heute mal angefangen mein ganzes Steuerungsscript umzuschreiben mit deinem Script zur Abfrage. Da ist mir aufgefallen, das im pass Modus der wert nicht 1 sondern 2 ist.

                Screenshot 2026-04-23 104848.jpg

                maxclaudiM Offline
                maxclaudiM Offline
                maxclaudi
                schrieb am zuletzt editiert von
                #245

                @Daniel-8 sagte:

                Ich habe heute mal angefangen mein ganzes Steuerungsscript umzuschreiben mit deinem Script zur Abfrage. Da ist mir aufgefallen, das im pass Modus der wert nicht 1 sondern 2 ist.

                Screenshot 2026-04-23 104848.jpg

                Ok, laut Dokumentation sollte es eigentlich nur 0 und 1 geben.

                Das Skript schreibt exakt den Wert in den Datenpunkt, der im JSON-Stream unter dem Key pass geliefert wird.

                Warum dort eine 2 ankommt, obwohl das SDK nur 0 und 1 vorsieht, ist mir rätselhaft.
                Es gibt auch über die Cloud für pass nur 0 (Bypass aus) oder 1 (Bypass aktiv).

                Zur Steuerung wird eigentlich ein separater, interner Key verwendet (passMode). Dieser hat die Werte 0 (Automatik), 1 (immer ausgeschaltet) und 2 (immer eingeschaltet).
                pass selbst informiert normalerweise nur darüber, ob der Bypass aktiv ist oder nicht.

                Bleibt abzuwarten, ob Zendure hier etwas an der API-Struktur ändert oder ob es ein temporärer Fehler im zenSDK-Output ist/war.

                Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

                1 Antwort Letzte Antwort
                0
                • D Offline
                  D Offline
                  Daniel 8
                  schrieb am zuletzt editiert von
                  #246

                  Das könnten sie ja dann nur per Firmwareupdate beheben oder? Da warte ich immer bisschen ab welche Probleme da auftauchen.

                  Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

                  1 Antwort Letzte Antwort
                  0
                  • D Offline
                    D Offline
                    Daniel 8
                    schrieb am zuletzt editiert von Daniel 8
                    #247

                    Ich logge gerade die Variable pass mit. Irgendwie schaltet die so ziemlich oft am Tag. In der früh ist das ja noch ok. Aber ab ca. 10 Uhr hat der Akku eigentlich genug SOC das der Speicher nicht in den Bypass schalten muss. Ich bin mir auch nicht sicher ob der Wirklich schaltet oder das nur ein Anzeigefehler ist. Hat jemand ein ähnliches Verhalten. Ich habe einen 800Pro

                    0 = Bypass aus
                    2 = Bypass ein
                    Die Zahl dazwischen ist nur eine addierte Zahl, das ich sehe wie oft er geschalten hat

                    cf4f54c0-7176-482a-95e6-5e320dcb4e06-image.jpeg

                    Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

                    maxclaudiM 1 Antwort Letzte Antwort
                    0
                    • D Daniel 8

                      Ich logge gerade die Variable pass mit. Irgendwie schaltet die so ziemlich oft am Tag. In der früh ist das ja noch ok. Aber ab ca. 10 Uhr hat der Akku eigentlich genug SOC das der Speicher nicht in den Bypass schalten muss. Ich bin mir auch nicht sicher ob der Wirklich schaltet oder das nur ein Anzeigefehler ist. Hat jemand ein ähnliches Verhalten. Ich habe einen 800Pro

                      0 = Bypass aus
                      2 = Bypass ein
                      Die Zahl dazwischen ist nur eine addierte Zahl, das ich sehe wie oft er geschalten hat

                      cf4f54c0-7176-482a-95e6-5e320dcb4e06-image.jpeg

                      maxclaudiM Offline
                      maxclaudiM Offline
                      maxclaudi
                      schrieb am zuletzt editiert von maxclaudi
                      #248

                      @Daniel-8 sagte:

                      Ich logge gerade die Variable pass mit. Irgendwie schaltet die so ziemlich oft am Tag. In der früh ist das ja noch ok. Aber ab ca. 10 Uhr hat der Akku eigentlich genug SOC das der Speicher nicht in den Bypass schalten muss. Ich bin mir auch nicht sicher ob der Wirklich schaltet oder das nur ein Anzeigefehler ist. Hat jemand ein ähnliches Verhalten. Ich habe einen 800Pro

                      0 = Bypass aus
                      2 = Bypass ein
                      Die Zahl dazwischen ist nur eine addierte Zahl, das ich sehe wie oft er geschalten hat

                      @Daniel-8, habe dich nicht vergessen, habe nur gerade viel Arbeit.
                      Nebenher ist ein neues, verbessertes Skript in Arbeit und zu 80 % fertig.

                      Ich wundere mich sehr, dass dir bei so vielen Aufrufen des Threads bisher niemand geantwortet hat.

                      Kurz zum Thema:
                      pass (Info) zeigt bei dir viele Schaltvorgänge des Bypass.
                      Auffällig ist zudem, dass hier anscheinend der passMode gespiegelt wird. Statt der reinen Info 0/1 siehst du 0/2
                      (was normalerweise der echte Set Key für den Bypass-Modus passMode wäre).

                      Das kann aber durchaus so sein und zusätzlich an bestimmten Tagen auftreten.

                      Der Bypass schaltet am Anfang öfter ein und aus, weil die Batterien bei 100 % SoC nicht sofort dauerhaft stabil auf diesem Wert bleiben.
                      Das BMS gönnt den Batterien gegen Ende "Ruhephasen",
                      wodurch sie abkühlen.
                      Nach der Ladung bzw. in der Ruhephase sinkt die Spannung leicht wieder ab (das nennt man auch Sackspannung).
                      Dann wird gewartet und der Bypass wieder aufgehoben, damit die Batterien noch einmal „langsam“ nachgeladen werden.
                      Dies wiederholt sich ein paar Mal, bis die Batterien letzten Endes als wirklich voll gelten.
                      Das wird von der Firmware und dem BMS anhand diverser Parameter festgestellt – wie z. B. minVol, maxVol oder der Differenz dazwischen (Zelldrift), Temperatur usw.
                      So bestimmt das BMS den Gesundheitszustand (State of Health) und den echten „Full“-Status.
                      Dass die Firmware hier bei wechselhafter Bewölkung (fluktuierende PV-Leistung) oder wechselnden Lasten etwas „nervös“ reagiert, ist ein bekanntes Verhalten bei Solar-Firmware-Logiken.

                      Bei mir funktionierte das mit allen Zendure-Geräten bisher immer zufriedenstellend.

                      Große Ausnahme war und ist das automatische Abschalten des Bypass.

                      Deshalb lasse ich den Bypass zwar automatisch einschalten, aber das Ausschalten erledige ich manuell bzw. per Skript.

                      Dazu nutze ich:

                      • Astronomischer Sonnenuntergang + Versatz von -x Min.
                      • Ab dann wird geprüft, ob die PV-Leistung für x Min. unter x Watt liegt.

                      Wenn ja, setze ich Bypass auf „immer aus“ (passMode: 1). In der Nacht schalte ich dann wieder auf passMode: 0 (Bypass auf Automatik).

                      Leider ist (zumindest Stand heute, 28.04.2026) das Umschalten des Bypass-Modus im offiziellen zenSDK (noch?) nicht vorgesehen.

                      Bei der Verwendung eines 1600AC+ stört mich das weniger, da ich selbst entscheide, wann geladen/entladen wird und keine PV-DC-Anschlüsse vorhanden sind.
                      Aber bei Systemen mit direkten PV-Modul-Anschlüssen ist das natürlich.... nicht ideal.

                      Jetzt war's mal wieder doch nicht so "kurz zum Thema", sorry.

                      Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

                      1 Antwort Letzte Antwort
                      0
                      • D Offline
                        D Offline
                        Daniel 8
                        schrieb am zuletzt editiert von
                        #249

                        Vielen Dank für die Infos.
                        Ja das in der Früh der Bypass öfter hin und her schaltet sehe ich ja noch ein. Aber das er am Mittag hin und her schaltet ist komisch. Weil da der Akku definitiv nicht voll war. Er war gestern auf maximal 66%. Ich bin mir auch nicht sicher ob er wirklich umschaltet. Denn PassMode kann ich ja leider nicht umschalten beim Solarflow 800Pro. Zumindest habe ich noch keine Möglichkeit gefunden

                        Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

                        maxclaudiM 1 Antwort Letzte Antwort
                        0
                        • D Offline
                          D Offline
                          Daniel 8
                          schrieb am zuletzt editiert von
                          #250

                          @maxclaudi
                          "Nebenher ist ein neues, verbessertes Skript in Arbeit und zu 80 % fertig."

                          Was wird denn verbessert? hat es was mit meinem Smartmode zu tun? Ich hoffe ich muss nicht nochmal alles neu machen für mein Steuerungsscript.

                          Solarflow 800 Pro mit 1,3 Kwp / Iobroker / Homematic / Shellys / Mediola / Intertechno

                          1 Antwort Letzte Antwort
                          0
                          • P Offline
                            P Offline
                            peschu
                            schrieb am zuletzt editiert von
                            #251

                            Hallo,

                            ich habe ein für mich unerklärliches Problem mit dem Script. Alles läuft problemlos und dann kommt eine Fehlermeldung:

                            javascript.0
                            2026-04-30 21:35:55.654 info script.js.Scripte.Zendure_Pro_2: Stopping script

                            javascript.0
                            2026-04-30 21:35:55.654 error script.js.Scripte.Zendure_Pro_2: Script is calling setState more than 1000 times per minute! Stopping Script now! Please check your script!
                            Ich habe nur ein kleines Script laufen, was alle 10 Sekunden Setoutputlimit anhand eines Bedarfswertes ändert.

                            b5c7b53d-a8a6-4e8f-a05f-9110e4c74fcc-image.jpeg
                            Script.jpg

                            1 Antwort Letzte Antwort
                            0
                            • P Offline
                              P Offline
                              peschu
                              schrieb am zuletzt editiert von
                              #252

                              Scheinbar tritt der Fehler alle drei Minuten auf:

                              60de1600-7a9f-40cb-8277-34f4bd2e3e88-image.jpeg

                              1 Antwort Letzte Antwort
                              0
                              • P Offline
                                P Offline
                                peschu
                                schrieb am zuletzt editiert von
                                #253

                                Hat sich erledigt. Ich habe diese Erklärung zu den Einstellungen erst im Nachgang gefunden:
                                -> Instanzen -> javascript-Adapter -> Allgemeine Einstellungen -> "Maximale setState-Anfragen pro Minute pro Skript" auf 5000 erhöhen.

                                maxclaudiM 1 Antwort Letzte Antwort
                                0
                                • P peschu

                                  Hat sich erledigt. Ich habe diese Erklärung zu den Einstellungen erst im Nachgang gefunden:
                                  -> Instanzen -> javascript-Adapter -> Allgemeine Einstellungen -> "Maximale setState-Anfragen pro Minute pro Skript" auf 5000 erhöhen.

                                  maxclaudiM Offline
                                  maxclaudiM Offline
                                  maxclaudi
                                  schrieb am zuletzt editiert von maxclaudi
                                  #254

                                  @peschu und @Alle

                                  Bitte auch sicherstellen, dass Zendure-Gerät(e) immer die gleiche IP im Heimnetz zugewiesen bekommen.

                                  Beispiel FRITZ!Box 7590:
                                  Übersicht -> Heimnetz -> Netzwerk -> Netzwerkverbindungen.
                                  Hier Zendure-Gerät(e) ausfindig machen.
                                  Dann auf Stiftsymbol (rechts davon) klicken (bearbeiten).
                                  Oben klicken auf TAB (Reiter) "Heimnetz".

                                  "IPv4-Adresse dauerhaft zuweisen" aktivieren.

                                  Danach "übernehmen" (speichern).

                                  fitzbox.png

                                  Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

                                  maxclaudiM 1 Antwort Letzte Antwort
                                  0
                                  • Bernd1967B Offline
                                    Bernd1967B Offline
                                    Bernd1967
                                    schrieb am zuletzt editiert von
                                    #255

                                    @maxclaudi
                                    Kommt man über zenSDK auch über den selbst vergebenen Namen in der App für das Gerät heran ?

                                    1 Antwort Letzte Antwort
                                    0
                                    • P Offline
                                      P Offline
                                      peschu
                                      schrieb am zuletzt editiert von
                                      #256

                                      @maxclaudi
                                      Danke für die Erinnerung. Hatte ich glatt vergessen.

                                      1 Antwort Letzte Antwort
                                      1
                                      • maxclaudiM maxclaudi

                                        @peschu und @Alle

                                        Bitte auch sicherstellen, dass Zendure-Gerät(e) immer die gleiche IP im Heimnetz zugewiesen bekommen.

                                        Beispiel FRITZ!Box 7590:
                                        Übersicht -> Heimnetz -> Netzwerk -> Netzwerkverbindungen.
                                        Hier Zendure-Gerät(e) ausfindig machen.
                                        Dann auf Stiftsymbol (rechts davon) klicken (bearbeiten).
                                        Oben klicken auf TAB (Reiter) "Heimnetz".

                                        "IPv4-Adresse dauerhaft zuweisen" aktivieren.

                                        Danach "übernehmen" (speichern).

                                        fitzbox.png

                                        maxclaudiM Offline
                                        maxclaudiM Offline
                                        maxclaudi
                                        schrieb am zuletzt editiert von maxclaudi
                                        #257

                                        Zendure-Geräte Webserver: Steuerung über das zenSDK (HTTP)
                                        2026.05.02_00.39h; update 19.05.26 16:50h BatteryType.
                                        für das ioBroker-Forum
                                        In memory of Daisy 02.05.24 – miss you.

                                        Dieses Skript ermöglicht die lokale Steuerung eines Zendure-Geräts.
                                        Es funktioniert sofort und benötigt keinerlei Keys oder sonstige Authentifizierungen.
                                        Es ist mit APP und Cloud nutzbar.
                                        Oder auch nur lokal, wenn für Gerät(e) der Internetzugang gesperrt wird.
                                        Dann ist jedoch die Verwendung der App per WLAN nicht mehr möglich.
                                        Außerdem sollte eine Möglichkeit geschaffen werden, einen Zeitserver zu erreichen.
                                        Also nur die Zendure spezifischen URL sperren.
                                        Näher möchte ich hier nicht darauf eingehen.

                                        Voraussetzungen:

                                        • Hardware: Zendure-Geräte (Generation 2025/2026) mit integriertem Webserver.

                                        • Aktivierung: Vor der ersten Nutzung muss HEMS einmalig aktiviert, kurz abgewartet und anschließend wieder deaktiviert werden.

                                        • Netzwerk: Die IP-Adresse des Zendure-Geräts muss bekannt sein. Empfehle dringend, dem Gerät im Router oder Access Point eine dauerhafte, feste IP zuzuweisen.

                                        Wichtiger Hinweis zum Flash-Speicher:
                                        Ich bin kein Freund von automatischen Befehlsketten, die für den Nutzer nicht nachvollziehbar sind – vor allem, wenn sie zu unnötigen Schreibvorgängen im Flash-Speicher führen.

                                        Nach aktuellem Stand ist sicher: Wenn smartMode: 1 gesetzt ist, werden zumindest die Werte für outputLimit und inputLimit lediglich in den RAM geschrieben.

                                        Ein Modewechsel (z. B. acMode, Energiepläne, Automodi, MQTT-Konfiguration) wird hingegen fast immer in den Flash-Speicher geschrieben.
                                        Dabei wird oft nicht nur der einzelne Wert, sondern die gesamte Konfiguration dauerhaft gespeichert.


                                        Neue Datenpunkte unter "control"
                                        Im aktuellen Skript gibt es zusätzliche Datenpunkte sowie den Ordner automaticKonfig mit zwei Schaltern (Boolean):

                                        1. auto_inputLimitMode (Watt)
                                          Hier kann ein Wert in Watt für das Ladelimit (inputLimit) gesetzt werden.
                                          Das Skript prüft daraufhin automatisch:
                                        • Ist acMode: 1 und outputLimit: 0 W gesetzt?

                                        • Falls nicht, wird automatisch acMode: 1 und outputLimit: 0 gesetzt, bevor mit dem gewählten Wert vom Netz geladen wird.

                                        • Ist der Schalter input_output_LimitMode_smartMode_RAM aktiviert, wird vor dem Senden zusätzlich geprüft, ob smartMode: 1 aktiv ist.
                                          Wenn nicht, wird dieser automatisch mitgesendet.

                                        • Prinzip: Es wird nur gesendet, was zwingend nötig ist (Vorab-Prüfung).

                                        1. auto_outputLimitMode (Watt)
                                          Dies ist das Gegenstück zum auto_inputLimitMode für die Entladesteuerung.

                                        2. smartModeWatcher (Schalter)
                                          Wenn dieser Slider aktiviert ist (true), wird bei jedem empfangenen Report automatisch geprüft, ob smartMode: 1 gesetzt ist.
                                          Sollte der Wert auf 0 stehen, setzt das Skript ihn automatisch wieder auf 1. Dieser Slider kann manuell oder per Skript (de-)aktiviert werden.

                                        Weitere Hinweise

                                        • inverseMaxPower: Dieser Wert sollte nicht zur laufenden Regelung verwendet werden. Er definiert die Obergrenze, die der Wechselrichter maximal ausgeben darf, und wird sehr wahrscheinlich in den Flash geschrieben.

                                        • chargeMaxLimit:
                                          Mit Vorsicht zu genießen. Diesen Wert am besten nicht für regelmäßige Limit-Anpassungen verwenden.

                                        • Verbraucher-Geräte:
                                          Vorsicht bei Consumer-Produkten (auch Zendure); hier wird oft bei jeder Parameteränderung die komplette Konfiguration in den Flash geschrieben.

                                        • mDNS: Funktioniert zwar, hat sich in Tests jedoch als unzuverlässig erwiesen. Eine feste IP-Adresse ist die bessere Wahl.

                                        • Struktur-Update: Die Verzeichnisse befinden sich nun direkt im Hauptordner:

                                        • control (inkl. automaticKonfig)

                                        • packData (unter Cxxxxx finden sich die jeweiligen Batteriedaten)

                                        • properties

                                        Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

                                        maxclaudiM D 3 Antworten Letzte Antwort
                                        0
                                        • maxclaudiM maxclaudi

                                          Zendure-Geräte Webserver: Steuerung über das zenSDK (HTTP)
                                          2026.05.02_00.39h; update 19.05.26 16:50h BatteryType.
                                          für das ioBroker-Forum
                                          In memory of Daisy 02.05.24 – miss you.

                                          Dieses Skript ermöglicht die lokale Steuerung eines Zendure-Geräts.
                                          Es funktioniert sofort und benötigt keinerlei Keys oder sonstige Authentifizierungen.
                                          Es ist mit APP und Cloud nutzbar.
                                          Oder auch nur lokal, wenn für Gerät(e) der Internetzugang gesperrt wird.
                                          Dann ist jedoch die Verwendung der App per WLAN nicht mehr möglich.
                                          Außerdem sollte eine Möglichkeit geschaffen werden, einen Zeitserver zu erreichen.
                                          Also nur die Zendure spezifischen URL sperren.
                                          Näher möchte ich hier nicht darauf eingehen.

                                          Voraussetzungen:

                                          • Hardware: Zendure-Geräte (Generation 2025/2026) mit integriertem Webserver.

                                          • Aktivierung: Vor der ersten Nutzung muss HEMS einmalig aktiviert, kurz abgewartet und anschließend wieder deaktiviert werden.

                                          • Netzwerk: Die IP-Adresse des Zendure-Geräts muss bekannt sein. Empfehle dringend, dem Gerät im Router oder Access Point eine dauerhafte, feste IP zuzuweisen.

                                          Wichtiger Hinweis zum Flash-Speicher:
                                          Ich bin kein Freund von automatischen Befehlsketten, die für den Nutzer nicht nachvollziehbar sind – vor allem, wenn sie zu unnötigen Schreibvorgängen im Flash-Speicher führen.

                                          Nach aktuellem Stand ist sicher: Wenn smartMode: 1 gesetzt ist, werden zumindest die Werte für outputLimit und inputLimit lediglich in den RAM geschrieben.

                                          Ein Modewechsel (z. B. acMode, Energiepläne, Automodi, MQTT-Konfiguration) wird hingegen fast immer in den Flash-Speicher geschrieben.
                                          Dabei wird oft nicht nur der einzelne Wert, sondern die gesamte Konfiguration dauerhaft gespeichert.


                                          Neue Datenpunkte unter "control"
                                          Im aktuellen Skript gibt es zusätzliche Datenpunkte sowie den Ordner automaticKonfig mit zwei Schaltern (Boolean):

                                          1. auto_inputLimitMode (Watt)
                                            Hier kann ein Wert in Watt für das Ladelimit (inputLimit) gesetzt werden.
                                            Das Skript prüft daraufhin automatisch:
                                          • Ist acMode: 1 und outputLimit: 0 W gesetzt?

                                          • Falls nicht, wird automatisch acMode: 1 und outputLimit: 0 gesetzt, bevor mit dem gewählten Wert vom Netz geladen wird.

                                          • Ist der Schalter input_output_LimitMode_smartMode_RAM aktiviert, wird vor dem Senden zusätzlich geprüft, ob smartMode: 1 aktiv ist.
                                            Wenn nicht, wird dieser automatisch mitgesendet.

                                          • Prinzip: Es wird nur gesendet, was zwingend nötig ist (Vorab-Prüfung).

                                          1. auto_outputLimitMode (Watt)
                                            Dies ist das Gegenstück zum auto_inputLimitMode für die Entladesteuerung.

                                          2. smartModeWatcher (Schalter)
                                            Wenn dieser Slider aktiviert ist (true), wird bei jedem empfangenen Report automatisch geprüft, ob smartMode: 1 gesetzt ist.
                                            Sollte der Wert auf 0 stehen, setzt das Skript ihn automatisch wieder auf 1. Dieser Slider kann manuell oder per Skript (de-)aktiviert werden.

                                          Weitere Hinweise

                                          • inverseMaxPower: Dieser Wert sollte nicht zur laufenden Regelung verwendet werden. Er definiert die Obergrenze, die der Wechselrichter maximal ausgeben darf, und wird sehr wahrscheinlich in den Flash geschrieben.

                                          • chargeMaxLimit:
                                            Mit Vorsicht zu genießen. Diesen Wert am besten nicht für regelmäßige Limit-Anpassungen verwenden.

                                          • Verbraucher-Geräte:
                                            Vorsicht bei Consumer-Produkten (auch Zendure); hier wird oft bei jeder Parameteränderung die komplette Konfiguration in den Flash geschrieben.

                                          • mDNS: Funktioniert zwar, hat sich in Tests jedoch als unzuverlässig erwiesen. Eine feste IP-Adresse ist die bessere Wahl.

                                          • Struktur-Update: Die Verzeichnisse befinden sich nun direkt im Hauptordner:

                                          • control (inkl. automaticKonfig)

                                          • packData (unter Cxxxxx finden sich die jeweiligen Batteriedaten)

                                          • properties

                                          maxclaudiM Offline
                                          maxclaudiM Offline
                                          maxclaudi
                                          schrieb am zuletzt editiert von maxclaudi
                                          #258

                                          NEU
                                          Zendure-Geräte Webserver: Steuerung über das zenSDK (HTTP)
                                          2026.05.02_00.39h für das ioBroker-Forum; update 19.05.26 16:50h BatteryType.
                                          In memory of Daisy 02.05.24 – miss you.

                                          Viel Spaß!


                                          // ioBroker JavaScript: Zendure zenSDK Adapter-Ersatz für ein Zendure-Gerät.
                                          // 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 2026.05.02_00.39h für das ioBroker-Forum; update 19.05.26 16:50h BatteryType.
                                          // In memory of Daisy 02.05.24 – miss you.
                                          // 
                                          // EIN WORT IN EIGENER SACHE:
                                          // Dieses Skript basiert auf vielen Stunden Hardware-Tests und Analysen (besonders zum Flash-Schutz).
                                          // In der Vergangenheit wurden meine Erkenntnisse oft ohne Erwähnung in andere Projekte übernommen.
                                          // Ich teile diesen Code gerne. Wer diese Logik in öffentliche Adapter integriert, ist herzlich 
                                          // eingeladen – ich bitte jedoch um die Fairness, die Quelle zu nennen. 
                                          // Das ist der "Lohn" für meine Zeit und Forschung.
                                          //----------------------------------------------------------------------------------------------------
                                          // Konfiguration
                                          //
                                          // Hinweis bei mehreren Zendure-Geräten:
                                          //   -> Für jedes Gerät ein eigenes Skript mit individueller Konfiguration verwenden!
                                          //   -> IP-Adresse anpassen.
                                          //   -> maxInputLimit / maxOutputLimit (abhängig vom Gerätetyp) einstellen.
                                          //   -> Intervall: getIntervalMs = 5000 ms (Standard). 
                                          //      Bei Verbindungsproblemen oder WLAN-Lags wird ein Wert von mindestens 8000 ms empfohlen.
                                          //
                                          // Empfehlung zur Geräteanzahl:
                                          //   • Bis zu 3 Geräte: völlig unkritisch.
                                          //   • 4 Geräte: problemlos möglich.
                                          //   • Mehr als 4 Geräte: nicht empfohlen. Aber abhängig von Systemleistung und Intervall prüfen.
                                          //
                                          // Das offizielle MQTT ist mit einer Aktualisierungsrate von bis zu 90 Sek. zu langsam.
                                          // Ich empfehle die Nutzung des zenSDK.
                                          // Hinweis: Das (De-)Aktivieren von MQTT sowie die MQTT-Verbindungsüberwachung werden nicht unterstützt.
                                          //
                                          // Damit neue Datenpunkte automatisch aus dem JSON erstellt werden können:
                                          // -> Instanzen -> JavaScript-Adapter -> Allgemeine Einstellungen -> "Kommando 'setObject' erlauben" aktivieren!
                                          //
                                          // Bei kurzem Abfrageintervall:
                                          // -> Instanzen -> JavaScript-Adapter -> Allgemeine Einstellungen -> 
                                          //    "Maximale setState-Anfragen pro Minute pro Skript" auf 5000 erhöhen.
                                          //    (Testweise reicht ein geringerer Wert wie 2000; das Skript wurde optimiert).
                                          //
                                          // Datenpunkte im Ordner "control" werden automatisch aktualisiert.
                                          //----------------------------------------------------------------------------------------------------
                                          //----------------------------------------------------------------------------------------------------
                                          // CONFIG
                                          //----------------------------------------------------------------------------------------------------
                                          
                                          // IP Zendure Gerät
                                          //Beispiel: const IP = "192.168.40.20";
                                          const IP = "192.168.40.20";  // IP des Zendure Geräts
                                          // Bitte sicherstellen:
                                          // richtige IP verwendet?
                                          // Im Router dem Zendure-Gerät eine feste, dauerhafte IP zuweisen!
                                          
                                          //maximum inputLimit -> Maximal mögliche (unterstützte) Ladeleistung des Zendure-Geräts 
                                          //Beispiele: SF800 800W / SF800 PRO: 1000W / 1600AC: 1600 / SF2400AC: 2400W
                                          const maxInputLimit = 1600;
                                          
                                          //maximum outputLimit -> Maximal möglich (unterstützte) Entladeleistung des Zendure-Geräts
                                          //Beispiele: SF800 800W / SF800 PRO: 800W / 1600AC: 1600 / SF2400AC: 2400W
                                          const maxOutputLimit = 1600;
                                          
                                          // Haupt-Verzeichnis für das Zendure-Gerät
                                          // Der Name für das Hauptverzeichnis kann frei gewählt werden.
                                          // Muss aber bei mehreren Skripten und Zendure-Geräte unterschiedlich sein.
                                          // Beispiel für "1600plus_01":
                                          // const folderZendureApi = '0_userdata.0.zendure.' + "1600ACplus_01";
                                          const folderZendureApi = '0_userdata.0.zendure.' + "zenSDK_01";
                                          
                                          // Timout Handler HTTP GET /POST
                                          // Wichtig:
                                          // getTimeoutMs < getIntervalMs
                                          // postTimeoutMs < getIntervalMs
                                          // Bei instabiler Verbindung ggf. erhöhen (z. B. 3000–5000 ms).
                                          const getTimeoutMs = 1500;  // Empfehlung: 2000 ms.
                                          const postTimeoutMs = 1500; // Empfehlung: 2000 ms.
                                          
                                          // GET intervall
                                          // Empfehlung: >= 5000 ms.
                                          // Kleinere Werte möglich, aber m. M. nach sinnfrei und nicht empfohlen (Last / Stabilität).
                                          const getIntervalMs = 5000; // Intervall für GET 5000ms. Bei Problemen erhöhen. NICHT < 5000!
                                          
                                          //----------------------------------------------------------------------------------------------------
                                          // END CONFIG
                                          //----------------------------------------------------------------------------------------------------
                                          
                                          let rxNewRam = "";
                                          let rxOldRam = "";
                                          let rxDiffRam = "";
                                          let txRam = "";
                                          
                                          const dpSmartRAM = folderZendureApi + ".control.automaticKonfig.input_output_LimitMode_smartMode_RAM";
                                          const dpSmartWatcher = folderZendureApi + ".control.automaticKonfig.smartModeWatcher";
                                          
                                          // helper
                                          function getRxNew() { return rxNewRam; }
                                          function setRxNew(val) {
                                              rxNewRam = val;
                                          }
                                          
                                          function getRxOld() { return rxOldRam; }
                                          function setRxOld(val) {
                                              rxOldRam = val;
                                          }
                                          
                                          function getRxDiff() { return rxDiffRam; }
                                          function setRxDiff(val) {
                                              rxDiffRam = val;
                                          }
                                          
                                          function setTx(val) {
                                              txRam = val;
                                          }
                                          
                                          const postCooldownMs = 2000;
                                          const batchWindowMs = 300;
                                          
                                          let postActive = false;
                                          let postQueue = {};
                                          let batchTimer = null;
                                          let getTimer = null;
                                          
                                          let retryCount = 0; 
                                          const maxRetries = 2; 
                                          let getErrorCount = 0; 
                                          let SN = '';
                                          
                                          // Struktur sicherstellen
                                          setTimeout(() => {
                                              ensureStructure();
                                          }, 100);
                                          
                                          function ensureStructure() {
                                              const folders = [
                                                  folderZendureApi,
                                                  folderZendureApi + ".properties",
                                                  folderZendureApi + ".packData",
                                                  folderZendureApi + ".control",
                                                  folderZendureApi + ".control.automaticKonfig"
                                              ];
                                              folders.forEach(path => {
                                                  if (!existsObject(path)) {
                                                      setObject(path, {
                                                          type: "folder",
                                                          common: { name: path.split(".").pop() },
                                                          native: {}
                                                      });
                                                  }
                                              });
                                              if (!existsState(dpSmartRAM)) {
                                                  createState(dpSmartRAM, false, { name: "Input/Output Limit Mode SmartMode RAM", type: "boolean", role: "switch", read: true, write: true });
                                              }
                                              if (!existsState(dpSmartWatcher)) {
                                                  createState(dpSmartWatcher, false, { name: "Smart Mode Watcher", type: "boolean", role: "switch", read: true, write: true });
                                              }
                                          	if (existsState(dpSmartRAM)) setState(dpSmartRAM, false, true);
                                          	if (existsState(dpSmartWatcher)) setState(dpSmartWatcher, false, true);
                                          }
                                          
                                          // Control
                                          const schemaControl = {
                                          	acMode: {
                                                  name: "set acMode; 1: input charge, 2: output discharge",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 1,
                                                  max: 2,
                                                  apiKey: "acMode",
                                              },
                                          	
                                          	chargeMaxLimit: {
                                                  name: "set Charge Max Limit",
                                                  unit: "W",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: maxInputLimit,
                                                  apiKey: "chargeMaxLimit",
                                              },
                                          	
                                          	gridOffMode: {
                                                  name: "set gridOffMode; 0: Normal mode, 1: Economic mode, 2: OFF",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 2,
                                                  apiKey: "gridOffMode",
                                              },
                                          	
                                          	gridReverse: {
                                                  name: "set gridReverse; 0: Disabled, 1: Allowed reverse flow, 2: Forbidden reverse flow",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 2,
                                                  apiKey: "gridReverse",
                                              },
                                          	
                                          	gridStandard: {
                                                  name: "set gridStandard; 0: Germany 1: France 2: Austria 3: Switzerland 4: Netherlands 5: Spain 6: Belgium 7: Greece 8: Denmark 9: Italy",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 9,
                                                  apiKey: "gridStandard",
                                              },
                                          	
                                          	inputLimit: {
                                                  name: "set inputLimit",
                                                  unit: "W",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: maxInputLimit,
                                                  apiKey: "inputLimit",
                                              },
                                          	
                                          	inverseMaxPower: {
                                                  name: "set inverseMaxPower; Max inverter output Power Limit",
                                                  unit: "W",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 200,
                                                  max: maxOutputLimit,
                                          		step: 100,
                                                  apiKey: "inverseMaxPower",
                                              },
                                          	
                                          	minSoc: {
                                                  name: "set minSoc; minimum SOC 0-50",
                                                  unit: "%",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 50,
                                                  apiKey: "minSoc",
                                                  transformWrite: (val) => val * 10
                                              },
                                          	
                                          	outputLimit: {
                                                  name: "set outputLimit",
                                                  unit: "W",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: maxOutputLimit,
                                                  apiKey: "outputLimit",
                                              },
                                          	
                                          	smartMode: {
                                                  name: "set smartMode; parameter are written to: 1: RAM / 0: Flash",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 1,
                                                  apiKey: "smartMode",
                                              },
                                          	
                                          	socSet: {
                                                  name: "set socSet; SOC Target 70%-100%",
                                                  unit: "%",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 70,
                                                  max: 100,
                                                  apiKey: "socSet",
                                                  transformWrite: (val) => val * 10
                                              },
                                          	
                                          	lampSwitch: {
                                                  name: "set lamp switch; 0: lamp off / 1: lamp on",
                                                  role: "level",
                                                  type: "number",
                                                  write: true,
                                                  min: 0,
                                                  max: 1,
                                                  apiKey: "lampSwitch",
                                              }
                                          };
                                          
                                          createControlStates();
                                           
                                          function createControlStates() {
                                              const base = folderZendureApi + ".control";
                                              Object.keys(schemaControl).forEach(key => {
                                                  const def = schemaControl[key];
                                                  const dp = `${base}.${key}`;
                                                  if (!existsState(dp)) {
                                                      createState(dp, 0, {
                                                          name: def.name, type: def.type, role: def.role, unit: def.unit,
                                                          read: true, write: true, min: def.min, max: def.max
                                                      });
                                                  }
                                              });
                                          		
                                          	const extraStates = [
                                          		{ id: `${base}.auto_inputLimitMode`, name: "Set InputLimit (Automatic)", unit: "W", min: 0, max: maxInputLimit },
                                          		{ id: `${base}.auto_outputLimitMode`, name: "Set OutputLimit (Automatic)", unit: "W", min: 0, max: maxOutputLimit }
                                          	];
                                           
                                          	extraStates.forEach(def => {
                                          		if (!existsState(def.id)) {
                                          			createState(def.id, 0, {
                                          				name: def.name, type: "number", role: "level", unit: def.unit,
                                          				read: true, write: true, min: def.min, max: def.max
                                          			});
                                          		}
                                          	});
                                          }
                                          
                                          on({ id: new RegExp(`^${folderZendureApi}\\.control\\.`), change: "ne" }, obj => {
                                              if (obj.state.ack) return; 
                                              const key = obj.id.split('.').pop();
                                          	
                                              if (key === "auto_inputLimitMode") {
                                                  handleInputLimitMode(obj.state.val);
                                                  setState(obj.id, obj.state.val, true);
                                                  return;
                                              }
                                           
                                              if (key === "auto_outputLimitMode") {
                                                  handleOutputLimitMode(obj.state.val);
                                                  setState(obj.id, obj.state.val, true);
                                                  return;
                                              }
                                          	
                                              const def = schemaControl[key];
                                              if (!def) return;
                                           
                                              let val = obj.state.val;
                                              if (def.min !== undefined && val < def.min) val = def.min;
                                              if (def.max !== undefined && val > def.max) val = def.max;
                                              if (def.transformWrite) val = def.transformWrite(val);
                                           
                                              sendToDevice(def.apiKey, val);
                                              setState(obj.id, obj.state.val, true);
                                          });
                                          
                                          function sendToDevice(apiKey, value) {
                                          	if (!SN || SN === "null" || SN === "") return;
                                              const payload = { sn: SN, properties: {} };
                                              payload.properties[apiKey] = value;
                                              setTx(JSON.stringify(payload));
                                              queuePost({ [apiKey]: value });
                                          }
                                          
                                          function queuePost(obj) {
                                              Object.assign(postQueue, obj);
                                              if (batchTimer) return;
                                              batchTimer = setTimeout(() => {
                                                  batchTimer = null;
                                                  executePost();
                                              }, batchWindowMs);
                                          }
                                          
                                          function executePost() {
                                              if (postActive) return;
                                              if (Object.keys(postQueue).length === 0) return;
                                              postActive = true;
                                              stopGetLoop();
                                              const payload = { sn: SN, properties: { ...postQueue } };
                                              postQueue = {};
                                              const json = JSON.stringify(payload);
                                              setTx(json); 
                                              httpPost(`http://${IP}/properties/write`, json, { timeout: postTimeoutMs, responseType: "text" }, (err, response) => {
                                                  let success = false;
                                                  if (!err && response && response.statusCode === 200) {
                                                      try {
                                                          const data = JSON.parse(response.data);
                                                          success = data.success === true && data.code === 200;
                                                      } catch (e) { success = false; }
                                                  }
                                                  if (!success) {
                                                      retryCount++;
                                                      if (retryCount <= maxRetries) {
                                                          log(`POST Retry ${retryCount}/${maxRetries}`, "warn");
                                                          setTimeout(() => {
                                                              postQueue = { ...payload.properties };
                                                              postActive = false;
                                                              executePost();
                                                          }, postCooldownMs);
                                                          return;
                                                      }
                                                      log("POST endgültig fehlgeschlagen", "error");
                                                      retryCount = 0;
                                                      finishPost(false);
                                                      return;
                                                  }
                                                  retryCount = 0;
                                                  finishPost(true);
                                              });
                                          }
                                          
                                          function finishPost(success) {
                                              if (!success) { syncControlFromProperties(); }
                                          	setTimeout(() => { postActive = false; startGetLoop(); }, postCooldownMs);
                                          	}
                                          
                                          function syncControlFromProperties() {
                                              const baseCtrl = folderZendureApi + ".control";
                                              const baseProp = folderZendureApi + ".properties";
                                           
                                              Object.keys(schemaControl).forEach(ctrlKey => {
                                                  const def = schemaControl[ctrlKey];
                                                  const apiKey = def.apiKey || ctrlKey;
                                           
                                                  const propState = getState(`${baseProp}.${apiKey}`);
                                                  if (!propState || propState.val === undefined) return;
                                           
                                                  const ctrlId = `${baseCtrl}.${ctrlKey}`;
                                          		const ctrlState = getState(ctrlId);
                                          		const ctrlVal = ctrlState ? ctrlState.val : undefined;
                                                  const propVal = propState.val;
                                           
                                                  if (ctrlVal !== propVal) {
                                                      setState(ctrlId, propVal, true);
                                                  }
                                              });
                                          
                                              const inputProp = getState(`${baseProp}.inputLimit`)?.val;
                                              if (inputProp !== undefined) {
                                                  const id = `${baseCtrl}.auto_inputLimitMode`;
                                                  if (getState(id)?.val !== inputProp) {
                                                      setState(id, inputProp, true);
                                                  }
                                              }
                                          
                                              const outputProp = getState(`${baseProp}.outputLimit`)?.val;
                                              if (outputProp !== undefined) {
                                                  const id = `${baseCtrl}.auto_outputLimitMode`;
                                                  if (getState(id)?.val !== outputProp) {
                                                      setState(id, outputProp, true);
                                                  }
                                              }
                                          }
                                          
                                          function startGetLoop() {
                                          	if (getTimer) {
                                              clearInterval(getTimer);
                                          	}
                                              getTimer = setInterval(() => {
                                                  if (postActive) return;
                                                  const url = `http://${IP}/properties/report`;
                                                  httpGet(url, { timeout: getTimeoutMs, responseType: 'text' }, (err, response) => {
                                                      if (err || !response || response.statusCode !== 200) {
                                                          getErrorCount++;
                                                          if (getErrorCount <= 3) log(`GET Fehler (${getErrorCount}): ${err || response?.statusCode}`, "warn");
                                                          if (getErrorCount === 4) log("Keine Verbindung möglich. Zendure-Geräte IP prüfen!", "error");
                                                          return;
                                                      }
                                                      if (getErrorCount > 0) log("Verbindung wieder OK", "info");
                                                      getErrorCount = 0;
                                                      if (!response.data) return;
                                                      setRxNew(response.data);
                                                      handleRxNewUpdate(response.data);
                                                  });
                                              }, getIntervalMs);
                                          }
                                          
                                          function stopGetLoop() { if (getTimer) { clearInterval(getTimer); getTimer = null; } }
                                           
                                          function handleInputLimitMode(val) {
                                              const currentAcMode = getState(folderZendureApi + ".properties.acMode")?.val;
                                              const currentOutput = getState(folderZendureApi + ".properties.outputLimit")?.val;
                                          	const currentSmartMode = getState(folderZendureApi + ".properties.smartMode")?.val;
                                              const smartRAMActive = getState(dpSmartRAM)?.val;
                                           
                                              const payload = {};
                                              if (currentAcMode !== 1) payload.acMode = 1;
                                              if (currentOutput !== 0) payload.outputLimit = 0;
                                          	if (smartRAMActive === true && currentSmartMode !== 1) payload.smartMode = 1;
                                              
                                              payload.inputLimit = val;
                                              sendBatch(payload);
                                          }
                                          
                                          function handleOutputLimitMode(val) {
                                              const currentAcMode = getState(folderZendureApi + ".properties.acMode")?.val;
                                              const currentInput = getState(folderZendureApi + ".properties.inputLimit")?.val;
                                          	const currentSmartMode = getState(folderZendureApi + ".properties.smartMode")?.val;
                                              const smartRAMActive = getState(dpSmartRAM)?.val;
                                           
                                              const payload = {};
                                              if (currentAcMode !== 2) payload.acMode = 2;
                                              if (currentInput !== 0) payload.inputLimit = 0;
                                          	if (smartRAMActive === true && currentSmartMode !== 1) payload.smartMode = 1;
                                           
                                              payload.outputLimit = val;
                                              sendBatch(payload);
                                          }
                                          
                                          function sendBatch(properties) {
                                              if (!SN || SN === "null" || SN === "") return;
                                              const payload = { sn: SN, properties: properties };
                                              setTx(JSON.stringify(payload)); 
                                          	queuePost(properties); 
                                          }
                                          
                                          const schema = {
                                              properties: {
                                                  BatVolt: {
                                                      name: "Battery Voltage",
                                                      unit: "V",
                                                      role: "value.voltage",
                                                      type: "number"
                                                  },
                                          		Fanmode: {
                                                      name: "Fanmode - 0: Fan off, 1: Fan on. / Unauthorized modification is not recommended.",
                                                      role: "value",
                                                      type: "number"
                                                  },	
                                          		Fanspeed: {
                                                      name: "Fanspeed - 0: Auto, 1: 1st gear, 2: 2nd gear / Unauthorized modification is not recommended.",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		acMode: {
                                                      name: "acMode - 1: input charge / 2: output discharge",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		acStatus: {
                                                      name: "AC state 0-2",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		batCalTime: {
                                                      name: "batCalTime - Battery Calibration Time. Unauthorized modifications are not recommended",
                                          			unit: "min",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		chargeMaxLimit: {
                                                      name: "chargeMaxLimit - Max charge power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		dataReady: {
                                                      name: "Data ready flag - 0: Data not ready, 1: Data ready",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		dcStatus: {
                                                      name: "dcStatus - DC State 0-2",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		electricLevel: {
                                                      name: "electricLevel - Average SOC of all Batterys",
                                                      unit: "%",
                                                      role: "value.battery",
                                                      type: "number"
                                                  },
                                          		gridInputPower: {
                                                      name: "gridInputPower - Grid Input Power to Battery",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		gridOffMode: {
                                                      name: "gridOffMode - 0: Normal mode, 1: Economic mode, 2: OFF",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		gridOffPower: {
                                                      name: "gridOffPower - Off-grid power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		gridReverse: {
                                                      name: "gridReverse - 0: Disabled, 1: Allowed reverse flow, 2: Forbidden reverse flow",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		gridStandard: {
                                                      name: "gridStandard - 0: Germany 1: France 2: Austria 3: Switzerland 4: Netherlands 5: Spain 6: Belgium 7: Greece 8: Denmark 9: Italy",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		gridState: {
                                                      name: "gridState - Grid connection state, 0: Not connected, 1: Connected",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		heatState: {
                                                      name: "heatState - Battery Heat State, 0: Not heating, 1: heating",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		hyperTmp: {
                                                      name: "Temperature",
                                                      unit: "°C",
                                                      role: "value.temperature",
                                                      type: "number"
                                                  },
                                          		inputLimit: {
                                                      name: "inputLimit - AC charging power limit to Battery",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		inverseMaxPower: {
                                                      name: "inverseMaxPower - Max inverter output Power Limit",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		lampSwitch: {
                                                      name: "lampSwitch - Lamp state, 0: lamp off / 1: lamp on",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		minSoc: {
                                                      name: "minSoc - Minimum SOC 0%-50%",
                                                      unit: "%",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		outputHomePower: {
                                                      name: "outputHomePower - Output to home",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		outputLimit: {
                                                      name: "outputLimit - Output power limit",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		outputPackPower: {
                                                      name: "outputPackPower - Battery charge power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		packInputPower: {
                                                      name: "packInputPower - Battery discharge power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		packState: {
                                                      name: "packState - Battery State, 0: Standby, 1: Charging, 2: Discharging",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		pass: {
                                                      name: "pass - 0: Bypass Automatic, 1: Bypass OFF, 2: Bypass ON",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		pvStatus: {
                                                      name: "pvStatus - PV State producing, 0: Stopped, 1: Running",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		remainOutTime: {
                                                      name: "remainOutTime - Estimated discharge time in minutes, if not predictable: 59940",
                                          			unit: "min",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		reverseState: {
                                                      name: "reverseState - Reverse flow, 0: No, 1: Reverse flow",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		smartMode: {
                                                      name: "smartMode - 1: parameter are written to RAM / 0: parameter are written to flash",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		socLimit: {
                                                      name: "socLimit - 0: normal, 1: Charge limit reached, 2: Discharge limit reached",
                                                      role: "value",
                                                      type: "number"
                                                  },		
                                                  socSet: {
                                                      name: "socSet - SOC Target 70%-100%",
                                                      unit: "%",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		socStatus: {
                                                      name: "socStatus - SOC calibration Info, 0: No Calibrating / 1: Calibrating",
                                                      role: "value",
                                                      type: "number"
                                                  },
                                          		solarInputPower: {
                                                      name: "solarInputPower - Total Solar Input Power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower1: {
                                                      name: "solarPower1 - Solar line 1 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower2: {
                                                      name: "solarPower2 - Solar line 2 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower3: {
                                                      name: "solarPower3 - Solar line 3 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower4: {
                                                      name: "solarPower4 - Solar line 4 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower5: {
                                                      name: "solarPower5 - Solar line 5 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		solarPower6: {
                                                      name: "solarPower6 - Solar line 6 input power",
                                          			unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  }
                                              },
                                              packData: {
                                                  batcur: {
                                                      name: "Battery Current flow - negativ: discharge / positiv: charge",
                                                      unit: "A",
                                                      role: "value.current",
                                                      type: "number"
                                                  },
                                          		maxTemp: {
                                                      name: "Battery - max. Stored temperature value",
                                                      unit: "°C",
                                                      role: "value.temperature",
                                                      type: "number"
                                                  },
                                          		maxVol: {
                                                      name: "maxVol - Max cell voltage",
                                                      unit: "V",
                                                      role: "value.voltage",
                                                      type: "number"
                                                  },
                                          		minVol: {
                                                      name: "minVol - Min cell voltage",
                                                      unit: "V",
                                                      role: "value.voltage",
                                                      type: "number"
                                                  },
                                          		packType: {
                                                      name: "Pack Type",
                                                      role: "indicator",
                                                      type: "number"
                                                  },
                                          		power: {
                                                      name: "Battery pack power",
                                                      unit: "W",
                                                      role: "value.power",
                                                      type: "number"
                                                  },
                                          		sn: {
                                                      name: "Battery pack serial number",
                                                      role: "indicator",
                                                      type: "string"
                                                  },
                                          		socLevel: {
                                                      name: "socLevel - State of charge in Percent",
                                          			unit: "%",
                                                      role: "value.battery",
                                                      type: "number"
                                                  },
                                          		state: {
                                          			name: "Battery state, 0: Standby, 1: Charging, 2: Discharging",
                                                      role: "indicator",
                                                      type: "number"
                                                  },
                                          		totalVol: {
                                          			name: "Battery Total Voltage",
                                                      unit: "V",
                                                      role: "value.voltage",
                                                      type: "number"
                                                  }
                                              }
                                          };
                                          
                                          function formatTime(unix) {
                                              if (unix === undefined || unix === null) return "";
                                              const d = new Date(unix * 1000);
                                              const timeOptions = { timeZone: "Europe/Berlin", hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false };
                                              const dateOptions = { timeZone: "Europe/Berlin", day: "2-digit", month: "2-digit", year: "2-digit" };
                                              return `${d.toLocaleTimeString("de-DE", timeOptions)}, ${d.toLocaleDateString("de-DE", dateOptions)}`;
                                          }
                                          
                                          function getBatteryType(sn, model) {
                                              let batType = "";
                                              if (!sn || typeof sn !== "string") return "unknown";
                                              if (sn.startsWith("A")) {
                                                  batType = "AB1000";
                                              } 
                                              else if (sn.startsWith("B")) {
                                                  batType = "AB1000S";
                                              } 
                                              else if (sn.startsWith("C")) {
                                                  const sub = sn.length > 3 ? sn[3] : "";
                                                  if (sub === "F") batType = "AB2000S";
                                                  else if (sub === "E") batType = "AB2000X";
                                                  else if (sub === "A") batType = "AB2000X internal";
                                                  else batType = "AB2000";
                                              } 
                                              else if (sn.startsWith("F")) {
                                                  batType = "AB3000X";
                                              }
                                              else if (sn.startsWith("J")) {
                                                  const sub = sn.length > 3 ? sn[3] : "";
                                                  if (sub === "A") batType = "Internal 2,4kWh";
                                                  else batType = "unknown internal";
                                              }
                                              else if (sn.startsWith("G")) {
                                                  const sub = sn.length > 3 ? sn[3] : "";
                                                  if (sub === "A") batType = "AB3000L";
                                                  else batType = "unknown AB3000?";
                                              }
                                              if (model && typeof model === "string" && model.trim()) {
                                                  batType = model.trim();
                                              }
                                              return batType || "unknown";
                                          }
                                          
                                          function writeMainKeys(json) {
                                              const keys = ["timestamp", "messageId", "sn", "version", "product"];
                                              keys.forEach(key => {
                                                  if (json[key] === undefined) return;
                                          		if (key === "sn" && SN === '') { SN = json[key]; }
                                                  const dp = `${folderZendureApi}.${key}`;
                                                  if (existsState(dp)) {
                                                      if (getState(dp).val !== json[key]) { setState(dp, json[key], true); }
                                                  } else {
                                                      createState(dp, json[key], { name: key, type: typeof json[key], role: "info", read: true, write: false });
                                                  }
                                              });
                                          }
                                          
                                          function writeProperties(obj) {
                                              if (!obj) return;
                                              const base = folderZendureApi + ".properties";
                                              Object.keys(obj).forEach(key => {
                                                  const dp = `${base}.${key}`;
                                                  const val = obj[key];
                                                  const meta = schema.properties?.[key] || {};
                                                  if (existsState(dp)) {
                                                      if (getState(dp).val !== val) { setState(dp, val, true); }
                                                  } else {
                                                      createState(dp, val, { name: meta.name || key, type: meta.type || typeof val, role: meta.role || "value", unit: meta.unit, read: true, write: false });
                                                  }
                                              });
                                          }
                                          
                                          function writePackData(arr) {
                                              if (!Array.isArray(arr)) return;
                                              const base = folderZendureApi + ".packData";
                                              arr.forEach(pack => {
                                                  if (!pack.sn) return;
                                                  const folder = `${base}.${pack.sn}`;
                                                  if (!existsObject(folder)) {
                                                      setObject(folder, { type: "folder", common: { name: pack.sn }, native: {} });
                                                  }
                                                  Object.keys(pack).forEach(key => {
                                                      const dp = `${folder}.${key}`;
                                                      const val = pack[key];
                                          			const meta = schema.packData?.[key] || {};
                                                      if (existsState(dp)) {
                                                          if (getState(dp).val !== val) { setState(dp, val, true); }
                                                      } else {
                                                          createState(dp, val, { name: meta.name || key, type: meta.type || typeof val, role: meta.role || "value", unit: meta.unit, read: true, write: false });
                                                      }
                                                  });
                                              });
                                          }
                                          
                                          function buildDiff(oldJson, newJson) {
                                              if (!oldJson || !newJson) return null;
                                              const diff = {};
                                              const mainKeys = ["timestamp", "messageId", "sn", "version", "product"];
                                          	mainKeys.forEach(key => {
                                                  if (newJson[key] !== undefined && newJson[key] !== oldJson[key]) { diff[key] = newJson[key]; }
                                              });
                                              if (newJson.properties) {
                                                  const propDiff = {};
                                                  Object.keys(newJson.properties).forEach(key => {
                                                      const newVal = newJson.properties[key];
                                                      const oldVal = oldJson.properties ? oldJson.properties[key] : undefined;
                                                      if (newVal !== oldVal) { propDiff[key] = newVal; }
                                                  });
                                                  if (Object.keys(propDiff).length > 0) { diff.properties = propDiff; }
                                              }
                                              if (Array.isArray(newJson.packData)) {
                                                  const packDiff = [];
                                                  const oldMap = {};
                                                  if (Array.isArray(oldJson.packData)) {
                                                      oldJson.packData.forEach(p => { if (p.sn) oldMap[p.sn] = p; });
                                                  }
                                                  newJson.packData.forEach(newPack => {
                                                      if (!newPack.sn) return;
                                                      const oldPack = oldMap[newPack.sn];
                                                      const singleDiff = { sn: newPack.sn };
                                                      let changed = false;
                                                      Object.keys(newPack).forEach(key => {
                                                          if (key === "sn") return;
                                                          const newVal = newPack[key];
                                                          const oldVal = oldPack ? oldPack[key] : undefined;
                                                          if (newVal !== oldVal) { singleDiff[key] = newVal; changed = true; }
                                                      });
                                                      if (changed) { packDiff.push(singleDiff); }
                                                  });
                                                  if (packDiff.length > 0) { diff.packData = packDiff; }
                                              }
                                              return Object.keys(diff).length === 0 ? null : diff;
                                          }
                                          
                                          function handleRxNewUpdate(val) {
                                              if (!val) return;
                                              let newJson;
                                              try { newJson = JSON.parse(val); } catch (e) { log("rxNew parse error: " + e, "warn"); return; }
                                              const smartModeWatcher = getState(dpSmartWatcher)?.val;
                                              if (smartModeWatcher === true && newJson.properties && newJson.properties.smartMode === 0) {
                                                  //log("SmartModeWatcher: smartMode ist 0! Erzwinge RAM-Modus (1)...", "info");
                                                  queuePost({ smartMode: 1 });
                                              }
                                              const oldStr = getRxOld(); 
                                              if (!oldStr || oldStr === "null" || oldStr === "") {
                                          		let full = transformJson(JSON.parse(JSON.stringify(newJson)));
                                          		writeMainKeys(full);
                                          		if (full.properties) {
                                          			writeProperties(full.properties);
                                          			const base = folderZendureApi + ".control";
                                                      Object.keys(schemaControl).forEach(ctrlKey => {
                                                          const def = schemaControl[ctrlKey];
                                                          const apiKey = def.apiKey || ctrlKey;
                                                          if (full.properties[apiKey] !== undefined) { setState(`${base}.${ctrlKey}`, full.properties[apiKey], true); }
                                                      });
                                                      if (full.properties.inputLimit !== undefined) { setState(`${base}.auto_inputLimitMode`, full.properties.inputLimit, true); }
                                                      if (full.properties.outputLimit !== undefined) { setState(`${base}.auto_outputLimitMode`, full.properties.outputLimit, true); }	
                                          		} 
                                          		if (full.packData) { writePackData(full.packData); }
                                          		setRxOld(val); setRxDiff(""); return;
                                          	}
                                              let oldJson;
                                              try { oldJson = JSON.parse(oldStr); } catch (e) { setRxOld(val); return; }
                                          	const isNewer = (newJson.timestamp && oldJson.timestamp && newJson.timestamp > oldJson.timestamp) || (!oldJson.timestamp && newJson.timestamp);
                                              if (!isNewer) return;
                                              const diff = buildDiff(oldJson, newJson);
                                              if (diff && Object.keys(diff).length > 0) {
                                                  const diffStr = JSON.stringify(diff);
                                                  setRxDiff(diffStr); handleRxDiffUpdate(diffStr); 
                                              } else { setRxDiff(""); }
                                              setRxOld(val);
                                          }
                                          
                                          function handleRxDiffUpdate(val) {
                                              if (!val) return;
                                              let diff;
                                              try { diff = JSON.parse(val); } catch (e) { log("rxDiff parse error: " + e, "warn"); return; }
                                              diff = transformJson(diff);
                                          	if (diff.properties) { syncControlFromDiff(diff); }							   
                                              writeMainKeys(diff);
                                              if (diff.properties) { writeProperties(diff.properties); }
                                              if (diff.packData) { writePackData(diff.packData); }
                                          }
                                          
                                          function syncControlFromDiff(diff) {
                                              if (!diff || !diff.properties) return;
                                              const base = folderZendureApi + ".control";
                                          	if (diff.properties.inputLimit !== undefined) { setState(`${base}.auto_inputLimitMode`, diff.properties.inputLimit, true); }
                                          	if (diff.properties.outputLimit !== undefined) { setState(`${base}.auto_outputLimitMode`, diff.properties.outputLimit, true); }	
                                          	Object.keys(schemaControl).forEach(ctrlKey => {
                                          		const def = schemaControl[ctrlKey];
                                          		const apiKey = def.apiKey || ctrlKey;
                                          		if (diff.properties[apiKey] !== undefined) { setState(`${base}.${ctrlKey}`, diff.properties[apiKey], true); }
                                          	}); 
                                          }
                                          
                                          function createOrSet(id, val, common) {
                                              if (existsState(id)) {
                                                  if (getState(id).val !== val) { setState(id, val, true); }
                                              } else { createState(id, val, { read: true, write: false, ...common }); }
                                          }
                                          
                                          function transformJson(obj) {
                                              if (!obj) return obj;
                                              if (obj.timestamp !== undefined && obj.timestamp !== null) {
                                                  const formatted = formatTime(obj.timestamp);
                                                  createOrSet(`${folderZendureApi}.timeUpdateTimestamp`, formatted, { type: "string", role: "text", name: "TimeUpdate (timestamp)" });
                                              }
                                              if (obj.properties) {
                                                  Object.keys(obj.properties).forEach(key => {
                                                      let val = obj.properties[key];
                                                      switch (key) {
                                          				case "BatVolt": val = val / 100; break;
                                          				case "acCouplingState": {
                                          					let states = [];
                                          					if (val & (1 << 0)) states.push("AC-coupled input present");
                                          					if (val & (1 << 1)) states.push("AC input present flag");
                                          					if (val & (1 << 2)) states.push("AC-coupled overload");
                                          					if (val & (1 << 3)) states.push("Excess AC input power");
                                          					const statusText = states.length > 0 ? states.join(", ") : "Normal / No Flags";
                                          					createOrSet(`${folderZendureApi}.properties.acCouplingState_String`, statusText, { type: "string", role: "text", name: "AC Coupling State (Text)" });
                                          				} break;
                                          				case "hyperTmp": val = (val - 2731) / 10.0; break;
                                                          case "minSoc":
                                          				case "socSet": val = val / 10; break;
                                                          case "ts":
                                          					if (val !== undefined && val !== null) {
                                          						const formatted = formatTime(val);
                                          						createOrSet(`${folderZendureApi}.properties.timeUpdateTs`, formatted, { type: "string", role: "text", name: "TimeUpdate (ts)" });
                                          					}
                                          					break;
                                                      }
                                                      obj.properties[key] = val;
                                                  });
                                              }
                                              if (Array.isArray(obj.packData)) {
                                          		obj.packData.forEach(pack => {
                                          			if (pack.sn) {
                                          				const batType = getBatteryType(pack.sn, pack.model);
                                          				createOrSet(`${folderZendureApi}.packData.${pack.sn}.model`, batType, { type: "string", role: "text", name: "Battery Model" });
                                          			}
                                          		}); 	
                                                  obj.packData.forEach(pack => {
                                                      Object.keys(pack).forEach(key => {
                                                          let val = pack[key];
                                                          switch (key) {
                                          					case "batcur":
                                          						if (val > 32767) { val = val - 65536; }
                                          						val = val / 10; break;
                                                              case "maxTemp": val = (val - 2731) / 10; break;
                                          					case "maxVol":
                                          					case "minVol":
                                          					case "totalVol": val = val / 100; break;
                                          					case "softVersion":
                                                                  const major = Math.floor(val / 4096);
                                                                  const minor = Math.floor((val % 4096) / 256);
                                                                  const patch = val % 256;
                                                                  val = `V${major}.${minor}.${patch}`; break;  
                                                          }
                                                          pack[key] = val;
                                                      });
                                                  });
                                              }
                                              return obj;
                                          }
                                          
                                          startGetLoop();
                                          
                                          

                                          Ich schreibe meistens sehr direkt – bitte nicht falsch verstehen, es ist nie böse gemeint. Das ist einfach mein Stil und niemals abwertend gemeint.

                                          maxclaudiM 1 Antwort Letzte Antwort
                                          0

                                          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
                                          Antworten
                                          • In einem neuen Thema antworten
                                          Anmelden zum Antworten
                                          • Älteste zuerst
                                          • Neuste zuerst
                                          • Meiste Stimmen


                                          Support us

                                          ioBroker
                                          Community Adapters
                                          Donate

                                          579

                                          Online

                                          32.9k

                                          Benutzer

                                          83.0k

                                          Themen

                                          1.3m

                                          Beiträge
                                          Community
                                          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                                          ioBroker Community 2014-2025
                                          logo
                                          • Anmelden

                                          • Du hast noch kein Konto? Registrieren

                                          • Anmelden oder registrieren, um zu suchen
                                          • Erster Beitrag
                                            Letzter Beitrag
                                          0
                                          • Home
                                          • Aktuell
                                          • Tags
                                          • Ungelesen 0
                                          • Kategorien
                                          • Unreplied
                                          • Beliebt
                                          • GitHub
                                          • Docu
                                          • Hilfe