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 SmartMode:1 SolarFlow2400 AC SolarFlow800 ( u. Pro)

NEWS

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

  • Verwendung von KI bitte immer deutlich kennzeichnen
    HomoranH
    Homoran
    9
    1
    286

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    18
    1
    921

Zendure SmartMode:1 SolarFlow2400 AC SolarFlow800 ( u. Pro)

Geplant Angeheftet Gesperrt Verschoben JavaScript
242 Beiträge 11 Kommentatoren 17.7k Aufrufe 12 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.
  • C cbrocker

    Hallo,
    ich lese hier hin und wieder mit und habe mir auch den Adapter von nograx mal heruntergeladen, aber noch nicht wirklich eingerichtet. Bisher lese ich ein paar Daten vom SF800 per http request aus.

    Ich habe mal mit KI ein Script erstellen lassen, das mir den Tagesertrag anhand der laufenden PV-Produktion berechnet, aber der Wert stimmt nicht ganz mit dem in der App überein.

    Frage: werden im Adapter von nograx die PV-Daten (Erträge für Tag, Monat, Jahr usw.) ausgelesen oder berechnet?

    Danke

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

    @cbrocker sagte in Zendure SmartMode:1 SolarFlow2400 AC SolarFlow800 ( u. Pro):

    Ich habe mal mit KI ein Script erstellen lassen, das mir den Tagesertrag anhand der laufenden PV-Produktion berechnet, aber der Wert stimmt nicht ganz mit dem in der App überein.

    Nachtrag:
    Du kannst davon ausgehen, dass Dein Script genauer ist als die App-Anzeige.
    Anders macht das Zendure auch nicht.

    Es gibt mehrere keys: xxx_PowerXCycle mit entsprechenden Werten.
    u. a. auch für aktuelle PV-Leistung
    z.B.: solarPower1Cycle mit xW für MPPT1 etc.

    Der Mittel-Wert solarPower1Cycle dient der Aggregation von Daten für Statistiken und Diagramme

    Während solarPower1 (ca. Echtzeitwert) für offizielle, lokale Anbindung übertragen wird, wird solarPower1Cycle (Zykluswert/Mittelwert) ca alle 60 sek aktualisiert und nur zur Cloud übertragen.
    (Solange Wert-Änderungen kommen, habe ich Intervalle von 58~61 sek. geloggt.)
    solarPower1Cycle ist also der gemittelte oder kumulierte Wert über 60 sek.

    Die Zendure-Cloud nutzt diese Cycle-Werte, um die Datenbanklast zu reduzieren.
    Statt tausende Einzelwerte pro Tag zu speichern, werden diese 1-Minuten-Pakete genutzt, um Tages-, Monats- und Jahreserträge zu berechnen und in den App-Diagrammen darzustellen.

    solarPower1Cycle und andere Cycle-Werte werden (bisher) nicht bei offizieller lokaler Anbindung in properties übertragen.
    Nur wenn man Cloud-DNS auf lokale IP umprogrammiert oder umleitet.

    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

      Ergebnis war positiv heute Nacht. Er hat wie sonst auch ca. 2% verloren.

      Die Änderung am Script war doch nicht so einfach, weil er am unteren soc nicht abgeschaltet hat. Habe es bisschen geändert und hoffe das es so läuft.

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

      @Daniel-8 und @mabbi und Alle
      habe nun endlich ein neues Gerät zum testen erhalten.

      Dabei fiel mir gleich in meinem bisherigen Script die unübersichtliche Struktur auf.

      Auch beim Start gab es Warnungen, wenn erstmals neue Verzeichnisse angelegt wurden.
      Hat mir niemand geschrieben.

      Korrigiert und optimiert.

      Das Script ist ein vollwertiger Adpater-Ersatz.

      Das -1 setzen wurde entfernt.
      Beim setzen eines Control-State wird der Wert gesendet und gleich mit dem bestätigten Wert aktualisiert.

      Intervall von 8 s (für die State-Abfrage/Report) läuft mit diesem Script problemlos (Queue Sicherung), wenn Netzwerkverbindung Zendure <> WLAN-Router ok ist.
      edit: Verwende selbst 6 sek.

      MQTT (lokal) ist per Slider (boolean default deaktiviert).
      Wenn deaktiviert, ist die MQTT-Script-Funktion komplett ausgeschaltet:

      • MQTT-Intervall wird nicht ausgeführt
      • dadurch keine MQTT-Statusabfrage
      • kein Ein-/Auschalten von lokalem MQTT möglich
      • MQTT- Datenfelder im Kofig-Block sind dann bedeutungslos.

      Keine Fehler bei Start. Fehlende Verzeichnisse und Datenpunkte werden automatisch erstellt.

      Sollten neue Datenpunkte hinzukommen (durch Frimwareupdate) werden sie als Datenpunkte automatisch erstellt.

      Neue Struktur.
      Haupt-Verzeichnis kann im Konfigblock leicht auf einen sinnvollen, eigenen Namen geändert werden.

      Der Verzeichnis-Name muss bei mehreren Geräten aber unterschiedlich sein.

      Script ist erprobt. Einige keys, die mir bekannt sind, wurden unter control nicht aufgenommen, weil sie Geräte-spezifisch sind, Gefahren darstellen und/oder (noch?) nicht offiziell unterstützt werden.... wie auch immer.

      Bin etwas entäuscht von zenSDK.
      Manche keys werden von dem Zendure-Gerät-Webserver nicht oder unregelmäßig aktualisiert.

      Neue Struktur des Scripts:
      script.png

      minTimeBreakForSetDpSec = 5;
      Ist einstellbar. 5 sek. haben sich bei mir bewährt.
      Nach dem setzen eines Befehls müssen mindestens x sek. vergangen sein um einen neuen zu senden.


      edit / update:
      wenn man nicht per script oder (Fehlern in scripts) ständig neue Werte feuert, kann auf die Pause verzichtet werden mit Wert: 0

      Die Eingabe einer Seriennummer ist nicht mehr erforderlich.


      Es sind mehrere Sicherungen eingebaut.
      Kommentare im Konfig-Bereich bitte lesen.

      Script ist ein Adapter-Ersatz.
      In meinen Augen der ehrlichste.
      Es werden keine Befehle und keine Befehlsketten gesendet, von denen man nichts weiß.
      Volle Verantwortung bei dem user.
      Auch smartMode wird nicht automatisch geschaltet.

      // ioBroker JavaScript: Zendure zenSDK Adapter-Ersatz
      // für alle Geräte ab 2025 die zenSDK unterstützen wie
      // SF800, SF800 PLUS, 800Pro, 1600AC, SF2400AC usw.
      // by maxclaudi 2026.04.19_01.15h for ioBroker Forum
      //------------------------------------------------------------------------------------
      // konfiguration
      //
      // Hinweis bei mehreren Zendure-Geräten:
      // - Für jedes Gerät ein eigenes Script mit individueller Konfiguration verwenden!
      //   -> IP-Adresse
      //   -> MQTT-Daten (Broker, Port, Benutzer, Passwort) falls Abfrage verwendet werden soll. Sonst nicht nötig.
      //   -> maxInputLimit / maxOutputLimit (abhängig vom Gerätetyp)
      //   -> Intervalle (Standard): intervalGet = 6s, intervalMqtt = 300s – können gleich bleiben
      //
      // Empfehlung:
      //   • 3 Geräte: völlig unkritisch
      //   • 4 Geräte: problemlos möglich
      //   • mehr als 4: nicht empfohlen
      //
      // MQTT-Abfrage ist per default false=disabled. Lokales, offizielles MQTT ist mit bis zu 90sek Aktualisierungsrate zu langsam.
      // Empfehle zenSDK zu verwenden.
      // Wer offizielles, lokale MQTT dennoch benutzen möchte und überwachen möchte kann den Datenpunkt mit dem Slider einschalten.
      // Standard ist bei script-Start MQTT-Abfrage ausgeschaltet und wird dann vom script komplett deaktiviert.
      // Bei Deaktivierung auch kein Intervall und keine Aktualisierung.
      //
      // Damit neue Datenpunkte automatisch aus dem JSON erstellt werden:
      // -> Instanzen -> javascript-Adapter -> Allgemeine Einstellungen -> Enable command "setObject“ aktivieren!
      // Bei kurzem Intervall:
      // -> Instanzen -> javascript-Adapter -> Allgemeine Einstellungen -> "Maximale setState-Anfragen pro Minute pro Skript" auf 5000 erhöhen.
      //
      // Datenpunkte bei set werden automatisch aktualisiert und nicht auf -1 zurück gesetzt.
      // Seriennummer wird automatisch ermittelt.
      //------------------------------------------------------------------------------------
      
      //------------------------------------------------------------------------------------
      // CONFIG
      //------------------------------------------------------------------------------------
      // Intervalle für Abfragen (Sekunden)
      const intervalGet = 6;                  // sek Intervall für GET report (empfohlen: 8, nicht <5) intervalGet MUSS größer sein als timeoutHttp !!
      const intervalMqtt = 300;               // sek MQTT-Status (default: 300 sek, > intervalGet) wird nur ausgeführt wenn Abfrage über SetMqttEnable eingeschaltet wird.
      
      // IP des Zendure Geräts
      const IP = "192.168.40.20";             // IP des Zendure Geräts
                   
      // MQTT Broker Konfiguration
      const mqttBrokerIp = "192.168.40.200";  // IP MQTT Broker und in App eingestellt 
      const mqttPort = 1883;                  // PORT MQTT Broker und in App eingestellt           
      const mqttUsername = "Daisy";           // MQTT Username
      const mqttPassword = "coco";            // MQTT Passwort
      
      //maximum inputLimit SF800 800W / SF800 PRO: 1000W / 1600AC: 1600 / SF2400AC: 2400W
      const maxInputLimit = 1000;
      
      //maximum outputLimit SF800 800W / SF800 PRO: 800W / 1600AC: 1600 / SF2400AC: 2400W
      const maxOutputLimit = 800;
      
      // Pause (Wert in Sekunden) die vergangen sein muss bevor ein neuer Befehl gesendet werden kann.
      const minTimeBreakForSetDpSec = 0; // 5 s hat sich bei mir bewährt. 0 funktioniert auch testweise.
      
      // Haupt-Verzeichnis für das Zendure-Gerät
      // Der Name für das Hauptverzeichnis kann frei gewählt werden.
      // 
      // Beispiel für "1600plus_01":
      // const folderZendureApi = '0_userdata.0.zendure.' + "1600ACplus_01";
      const folderZendureApi = '0_userdata.0.zendure.' + "zenSDK";
      //
      // Timout Handler HTTP GET /POST
      // timeoutHttp MUSS kleiner sein als intervalGet!! Besser nicht ändern. Standard: 2000ms
      const timeoutHttp = 2000; // Timeout in ms für alle HTTP-Anfragen (Zendure)
      //------------------------------------------------------------------------------------
      // End of config
      //------------------------------------------------------------------------------------
      
      const mqttStateAskingDefault = false; // nicht verändern! Kann bei laufendem script ein- oder ausgeschaltet werden
      let lastMqttSet = 0;
      let mqttInterval = null;
      let SN = "zendureDevice";
      //------------------------------------------------------------------------------------
      // dp
      //------------------------------------------------------------------------------------
      
      const dpSetSmartMode        = folderZendureApi + ".control.setSmartMode";
      const dpSetAcMode           = folderZendureApi + ".control.setAcMode";
      const dpSetInputLimit       = folderZendureApi + ".control.setInputLimit";
      const dpSetOutputLimit      = folderZendureApi + ".control.setOutputLimit";
      const dpSetSocSet           = folderZendureApi + ".control.setSocSet";
      const dpSetMinSoc           = folderZendureApi + ".control.setMinSoc";
      const dpSetGridReverse      = folderZendureApi + ".control.setGridReverse";
      const dpSetGridStandard     = folderZendureApi + ".control.setGridStandard";
      const dpSetInverseMaxPower  = folderZendureApi + ".control.setInverseMaxPower";
      const dpSetChargeMaxLimit   = folderZendureApi + ".control.setChargeMaxLimit";
      const dpSetGridOffMode      = folderZendureApi + ".control.setGridOffMode";
      
      const dpSetMqttEnable       = folderZendureApi + ".control.localMqtt.EnableScriptControlLocalMqtt";
      const dpSetMqttConnect      = folderZendureApi + ".control.localMqtt.SetConnectlocalMqtt";
      const dpMqttConnectInfo     = folderZendureApi + ".control.localMqtt.InfoLocalMqttConnected";
      
      const dpTimestamp           = folderZendureApi + ".timestamp";
      
      //------------------------------------------------------------------------------------
      // mapping
      //------------------------------------------------------------------------------------
      const dpMap = {
          [dpSetSmartMode]:       { key: "smartMode", min: 0, max: 1 },
          [dpSetAcMode]:          { key: "acMode", min: 1, max: 2 },
          [dpSetInputLimit]:      { key: "inputLimit", min: 0, max: maxInputLimit },
          [dpSetOutputLimit]:     { key: "outputLimit", min: 0, max: maxOutputLimit },
          [dpSetSocSet]:          { key: "socSet", transform: v => v*10, min: 70, max: 100 },
          [dpSetMinSoc]:          { key: "minSoc", transform: v => v*10, min: 5, max: 50 },
          [dpSetGridReverse]:     { key: "gridReverse", min: 0, max: 2 },
          [dpSetGridStandard]:    { key: "gridStandard", min: 0, max: 2 },
          [dpSetInverseMaxPower]: { key: "inverseMaxPower", min: 600, max: maxOutputLimit },
          [dpSetChargeMaxLimit]:  { key: "chargeMaxLimit", min: 0, max: maxInputLimit },
      	[dpSetGridOffMode]:     { key: "gridOffMode", min: 0, max: 2 }
      };
      
      //------------------------------------------------------------------------------------
      // QUEUE
      //------------------------------------------------------------------------------------
      const curlQueue = [];
      let curlRunning = false;
      
      function runQueue() {
          if (curlRunning || curlQueue.length === 0) return;
          const task = curlQueue.shift();
          curlRunning = true;
          task.fn(() => {
              curlRunning = false;
              runQueue();
          });
      }
      
      //------------------------------------------------------------------------------------
      // helper
      //------------------------------------------------------------------------------------
      function delay(ms) {
          return new Promise(resolve => setTimeout(resolve, ms));
      }
      
      function formatTime(ts) {
          const d = new Date(ts * 1000);
          const pad = n => n.toString().padStart(2, "0");
          return `${pad(d.getDate())}.${pad(d.getMonth()+1)}.${d.getFullYear().toString().slice(-2)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
      }
      
      function handleHttpError(context, err, options) {
      	const transient = [
              "EHOSTUNREACH", "ECONNRESET", "ECONNREFUSED", "ETIMEDOUT",
              "socket hang up", "ENETUNREACH", "EAI_AGAIN", "ENOTFOUND"
          ];
      	
      	const msg = err && err.message ? err.message : String(err);
          const isTransient = transient.some(code => msg.includes(code));
       
          //info_error
      	//log(`${context}: ${isTransient ? "war vorübergehend im Intervall nicht erfolgreich:" : "Warnung"} (${msg})`, isTransient ? "info" : "warn");
          log(`${context}: ${isTransient ? "war vorübergehend im Intervall nicht erfolgreich:" : "Warnung"} (${msg})`, "info");
       
          // set Timestamp
          if (options && options.timestamp) {
              setState(options.timestamp, formatTime(Math.floor(Date.now() / 1000)), true);
          }
      }
      
      //------------------------------------------------------------------------------------
      // CREATE STATES
      //------------------------------------------------------------------------------------
      const dataPoints = [
          { id: dpSetSmartMode, val: 0, common: { name: "Smart Mode 0:FLASH 1:RAM",desc: "Flash write behavior", type: "number", role: "state", min: 0, max: 1 } },
          { id: dpSetAcMode, val: 1, common: { name: "AC Mode 1:charge mode 2:discharge mode", type: "number", role: "state", min: 1, max: 2 } },
          { id: dpSetInputLimit, val: 0, common: { name: "Input Limit AC charge limit", type: "number", role: "state", min: 0, max: maxInputLimit, unit: 'W' } },
          { id: dpSetOutputLimit, val: 0, common: { name: "Output Limit", type: "number", role: "state", min: 0, max: maxOutputLimit, unit: 'W' } },
          { id: dpSetSocSet, val: 70, common: { name: "SOC Set (Target SOC 70%-100%)", type: "number", role: "state", min: 70, max: 100, unit: '%' } },
          { id: dpSetMinSoc, val: 5, common: { name: "Min SOC (Minimum SOC 5%-50%)", type: "number", role: "state", min: 5, max: 50, unit: '%' } },
          { id: dpSetGridReverse, val: 0, common: { name: "Reverse flow control 0: Disabled, 1: Allowed reverse flow, 2: Forbidden reverse flow", type: "number", role: "state", min: 0, max: 2 } },
          { id: dpSetGridStandard, val: 0, common: { name: "Grid Standard (0: Germany 1: France 2: Austria...)", desc: "(3: Switzerland 4: Netherlands 5: Spain 6: Belgium 7: Greece 8: Denmark 9: Italy)", type: "number", role: "state", min: 0, max: 9 } },
          { id: dpSetInverseMaxPower, val: 600, common: { name: "Max inverter output Power", type: "number", role: "state", min: 600, max: maxOutputLimit, unit: 'W' } },
          { id: dpSetChargeMaxLimit, val: 0, common: { name: "Charge Max Limit", type: "number", role: "state", min: 0, max: maxInputLimit, unit: 'W' } },
      	{ id: dpSetGridOffMode, val: 0, common: { name: "Grid Off Mode 0: Standard Mode  1: Economic Mode  2: Closure", type: "number", role: "state", min: 0, max: 2 } },
      	{ id: dpSetMqttEnable, val: mqttStateAskingDefault, common: { name: "Enable Script-Control of Local Mqtt: Off ON", type: "boolean", role: "state", read: true, write: true } },
          { id: dpSetMqttConnect, val: 0, common: { name: "Set Connect localMqtt -> only if EnableScriptControlLocalMqtt: on", type: "number", role: "indicator", read: true, write: true } },
          { id: dpMqttConnectInfo, val: 0, common: { name: "Info Local Mqtt Connected 0:off 1:on -> only if EnableScriptControlLocalMqtt: on", type: "number", role: "indicator", read: true, write: false } },
          { id: dpTimestamp, val: "", common: { name: "Timestamp", type: "string", role: "state", read: true, write: false } }
      ];
      
      async function startScript() {
          console.log("Erstelle Datenpunkte...");
          for (const dp of dataPoints) {
              await createStateAsync(dp.id, dp.val, dp.common);
          }
          
          setState(dpSetMqttEnable, mqttStateAskingDefault, true);
          console.log("Datenpunkte bereit. Starte Abfragen...");
          setInterval(getReport, intervalGet * 1000);
          getReport(); 
      }
      
      startScript();
      
      
      //------------------------------------------------------------------------------------
      // TRIGGERS (SET)
      //------------------------------------------------------------------------------------
      Object.keys(dpMap).forEach(id => {
          let lastSetTime = 0;
      
          on({ id: id, ack: false }, obj => {
              const val = obj.state.val;
              const { min, max } = dpMap[id];
      
              if (val >= min && val <= max) {
                  const now = Date.now();
                  if (now - lastSetTime >= minTimeBreakForSetDpSec * 1000) {
                      lastSetTime = now;
                      setControlDP(id, val);
                  }
              }
          });
      });
      
      // MQTT POST nur wenn enable=true + rate limit
      on({ id: dpSetMqttConnect, ack: false }, obj => {
      
          if (!getState(dpSetMqttEnable).val) return;
      
          const now = Date.now();
          if (now - lastMqttSet < minTimeBreakForSetDpSec * 1000) return;
      
          lastMqttSet = now;
      
          const val = parseInt(obj.state.val, 10);
          if (val === 0 || val === 1) setMqttConnect(val);
      });
      
      //------------------------------------------------------------------------------------
      // HTTP
      //------------------------------------------------------------------------------------
      const http = require("http");
      
      function setControlDP(id, val) {
          const { key, transform } = dpMap[id];
          const value = transform ? transform(val) : val;
      
          curlQueue.push({
              fn: done => {
                  const payload = JSON.stringify({ sn: SN, properties: { [key]: value } });
      
                  const req = http.request({
                      hostname: IP,
                      port: 80,
                      path: "/properties/write",
                      method: "POST",
                      headers: { 
                          "Content-Type": "application/json", 
                          "Content-Length": Buffer.byteLength(payload) 
                      }
                  }, res => {
                      res.on("data", () => {});
                      res.on("end", () => {
                          // nach Schreiben sofort anfordern
                          curlQueue.unshift({ fn: d => getReportInternal(d) });
                          done(); // freigeben
                      });
                  });
      
                  // Timeout
                  req.setTimeout(timeoutHttp, () => {
                      req.destroy(); // Verbindung hart abbrechen
                      handleHttpError("POST Timeout", "Gerät antwortet nicht", { timestamp: dpTimestamp });
                      done(); // WICHTIG: Queue freigeben, damit nächste Befehle folgen können
                  });
      
                  // Fehler
                  req.on("error", err => { 
                      handleHttpError("POST Error", err, { timestamp: dpTimestamp }); 
                      done();
                  });
      
                  req.write(payload);
                  req.end();
              }
          });
      
          runQueue();
      }
      
      
      function getReport() {
          curlQueue.push({ fn: done => getReportInternal(done) });
          runQueue();
      }
      
      function getReportInternal(done) {
          const req = http.request({
              hostname: IP,
              port: 80,
              path: "/properties/report",
              method: "GET"
          }, res => {
              let data = "";
              res.on("data", chunk => data += chunk);
              res.on("end", async () => {
                  try {
                      const json = JSON.parse(data);
                      if (json.properties) {
                          Object.keys(dpMap).forEach(dp => {
                              const { key } = dpMap[dp];
                              if (json.properties[key] !== undefined) {
                                  setState(dp, json.properties[key], true);
                              }
                          });
                      }
                      setState(dpTimestamp, formatTime(Math.floor(Date.now()/1000)), true);
                      await processJson(json);
                  } catch (e) {
                      log("GET parse error: " + e, "info");
                  }
                  done(); // WICHTIG: Queue freigeben nach Erfolg
              });
          });
      
          
          // Fehler
          req.on("error", err => { 
              handleHttpError("GET Error", err, { timestamp: dpTimestamp }); 
              done(); // WICHTIG: Queue freigeben bei Fehler
          });
      
          // Timeout
          req.setTimeout(timeoutHttp, () => {
              req.destroy(); // Verbindung abbrechen
              handleHttpError("GET Timeout", "Gerät antwortet nicht", { timestamp: dpTimestamp });
              done(); // WICHTIG: Queue freigeben bei Zeitüberschreitung
          });
          req.end();
      }
      
      //------------------------------------------------------------------------------------
      // MQTT
      //------------------------------------------------------------------------------------
      
      // Enable-Schalter nur Steuerung, kein POST
      on({ id: dpSetMqttEnable, ack: false }, obj => {
      
          const enable = !!obj.state.val;
          setState(dpSetMqttEnable, enable, true);
      
          if (enable) {
      
              // sofort GET
              curlQueue.push({ fn: d => getMqttStatusInternal(d) });
              runQueue();
      
              // Intervall start
              if (!mqttInterval) {
                  mqttInterval = setInterval(() => {
                      curlQueue.push({ fn: d => getMqttStatusInternal(d) });
                      runQueue();
                  }, intervalMqtt * 1000);
              }
      
          } else {
      
              if (mqttInterval) {
                  clearInterval(mqttInterval);
                  mqttInterval = null;
              }
          }
      });
      
      function getMqttStatusInternal(done) {
      
          const req = http.request({
              hostname: IP,
              port: 80,
              path: "/rpc?method=HA.Mqtt.GetStatus",
              method: "GET"
          }, res => {
      
              let data = "";
      
              res.on("data", chunk => data += chunk);
      
              res.on("end", () => {
      
                  try {
                      const json = JSON.parse(data);
                      const state = json.connected ? 1 : 0;
      
                      // readonly
                      setState(dpMqttConnectInfo, state, true);
      
                      // sync setDP (OHNE trigger)
                      setState(dpSetMqttConnect, state, true);
      
                  } catch (e) {
                      log("MQTT parse error: " + e, "info");
                  }
      
                  done();
              });
          });
      
          req.on("error", err => { handleHttpError("MQTT GET", err, { timestamp: dpTimestamp }); done(); });
      
          req.end();
      }
      
      function setMqttConnect(enable) {
      
          const payload = JSON.stringify({
              sn: SN,
              method: "HA.Mqtt.SetConfig",
              params: {
                  config: {
                      enable: !!enable,
                      server: mqttBrokerIp,
                      port: mqttPort,
                      protocol: "mqtt",
                      username: mqttUsername,
                      password: mqttPassword
                  }
              }
          });
      
          curlQueue.push({
              fn: done => {
      
                  const req = http.request({
                      hostname: IP,
                      port: 80,
                      path: "/rpc",
                      method: "POST",
                      headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(payload) }
                  }, res => {
                      res.on("data", () => {});
                      res.on("end", () => done());
                  });
      
                  req.on("error", err => { handleHttpError("MQTT POST", err, { timestamp: dpTimestamp }); done(); });
      
                  req.write(payload);
                  req.end();
              }
          });
      
          runQueue();
      }
      
      //------------------------------------------------------------------------------------
      // JSON
      //------------------------------------------------------------------------------------
      async function processJson(obj) {
          try {
              if (!obj || !obj.product) return;
       
              const product = obj.product;
              const basePath = `${folderZendureApi}.${product}`;
      		
      		if (obj.sn) {
                  SN = obj.sn;
              }
       
              // create product folder if not exist
              if (!existsObject(basePath)) {
                  setObject(basePath, {
                      type: 'folder',
                      common: { name: product },
                      native: {},
                  });
              }
       
              // create main keys
              const mainKeys = ['timestamp', 'messageId', 'sn', 'version', 'product'];
              for (const key of mainKeys) {
                  if (obj[key] !== undefined) {
                      const statePath = `${basePath}.${key}`;
                      if (existsState(statePath)) {
                          setState(statePath, obj[key], true);
                      } else {
                          createState(statePath, obj[key], {
                              name: key,
                              type: typeof obj[key],
                              role: 'info',
                              read: true,
                              write: false,
                          });
                      }
                  }
              }
       
              // properties
              if (obj.properties) {
                  await iter(`${basePath}.properties`, obj.properties);
              }
       
              // PackData
              if (obj.packData && Array.isArray(obj.packData)) {
                  await iter(`${basePath}`, { packData: obj.packData, timestamp: obj.timestamp });
              }
          } catch (e) {
              log(`Error processing JSON: ${e}`, 'info');
          }
      }
       
      //------------------------------------------------------------------------------------
      // Battery
      //------------------------------------------------------------------------------------
      function getBatteryType(sn, model) {
        let batType = '';
        if (sn?.startsWith('A')) batType = 'AB1000';
        else if (sn?.startsWith('B')) batType = 'AB1000S';
        else if (sn?.startsWith('C')) batType = sn[3] === 'F' ? 'AB2000S' : (sn[3] === 'E' || sn[3] === 'A') ? 'AB2000X' : 'AB2000';
        else if (sn?.startsWith('F')) batType = 'AB3000X';
        if (model?.trim()) batType = model.trim();
        return batType || 'unknown';
      } 
       
      //------------------------------------------------------------------------------------
      // helper Iteration
      //------------------------------------------------------------------------------------
      async function iter(id, obj) {
          try {
      		if (!obj || typeof obj !== "object") {
                 //log("iter: Ungültiges oder leeres Objekt übersprungen", "info");
                 return;
                 }
      		for (let i in obj) {
                  if (i === 'packData' && Array.isArray(obj[i])) {
                      const ts = obj.timestamp ? obj.timestamp * 1000 : Date.now();
                      for (const pack of obj[i]) {
                          if (!pack.sn) continue;
                          const sn = pack.sn;
                          const path = `${id}.packData.${sn}`;
       
                          if (!existsObject(path)) {
                              setObject(path, {
                                  type: 'folder',
                                  common: { name: sn },
                                  native: {},
                              });
                          }
       
                          for (let [key, val] of Object.entries(pack)) {
                              const statePath = `${path}.${key}`;
                              switch (key) {
                                  case 'batcur':
                                      val = (val << 16 >> 16) / 10;
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);;
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Battery Current',
                                              type: 'number',
                                              desc: 'battery current',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: 'A',
                                          });
                                      }
                                      break;
      							case 'heatState':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Heat State, 0: Not heating, 1: heating',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                          });
                                      }
                                      break;		
      							case 'maxTemp':
                                      val = (val - 2731) / 10;
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Highest Akku Temperature',
                                              type: 'number',
                                              desc: 'maximum temperature',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: '°C',
                                          });
                                      }
                                      break;
                                  case 'maxVol':
                                      val = val / 100;
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Highest Cell Voltage',
                                              type: 'number',
                                              desc: 'highest cell voltage',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: 'V',
                                          });
                                      }
                                      break;
                                  case 'minVol':
                                      val = val / 100;
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Lowest Cell Voltage',
                                              type: 'number',
                                              desc: 'lowest cell voltage',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: 'V',
                                          });
                                      }
                                      break;
      							case 'packType':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'packType',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                          });
                                      }
                                      break;
      							case 'power':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Battery Power',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: 'W',
                                          });
                                      }
      								break;
      							case 'sn':
                                  const batType = getBatteryType(val, pack.model);
                                  // Modelltyp als Datenpunkt setzen/erstellen
                                  const modelPath = `${path}.model`;
                                  if (existsState(modelPath)) {
      								setState(modelPath, batType, true);
                                      } else {
                                          createState(modelPath, batType, {
                                          name: 'Battery Model',
                                          type: 'string',
                                          role: 'text',
                                          read: true,
                                          write: false,
                                          });
                                         }
                                      break;
      							case 'socLevel':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Battery SoC Level',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: '%',
                                          });
                                      }
      								break;
      							case 'softVersion':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Battery Software Version',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                          });
                                      }
      								break;
      							case 'state':
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Battery, 0: Standby, 1: Charging, 2: Discharging',
                                              type: 'number',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                          });
                                      }
      								break;	
                                  case 'totalVol':
                                      val = val / 100;
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: 'Total Voltage',
                                              type: 'number',
                                              desc: 'total voltage',
                                              role: 'value',
                                              read: true,
                                              write: false,
                                              unit: 'V',
                                          });
                                      }
                                      break;
                                  default:
                                      if (existsState(statePath)) {
                                          setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                              name: key,
                                              type: typeof val,
                                              role: 'value',
                                              read: true,
                                              write: false,
                                          });
                                      }
                                      break;
                              }
                          }
                      }
                  } else {
                      const ts = Date.now();
                      const statePath = `${id}.${i}`;
                      let val = obj[i];
       
                      switch (i) {
                          case 'BatVolt':
                              val = val / 100;
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Battery Voltage',
                                      type: 'number',
                                      desc: 'battery voltage',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: 'V',
                                  });
                              }
                              break;
      					case 'batCalTime':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Battery calibration time in minutes. Unauthorized modifications are not recommended',
                                      type: 'number',
                                      desc: 'battery voltage',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: 'min',
                                  });
                              }
                              break;
      					case 'chargeMaxLimit':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'maximum Charge Power Limit',
                                      type: 'number',
                                      desc: 'Maximum permissible charging power',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: 'W',
                                  });
                              }
                              break;
                          case 'acMode':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'acMode, 1: input mode / 2: output mode',
                                      type: 'number',
                                      desc: '1: charging / 2: discharging',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;
      					case 'dataReady':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Data Ready, 0: Not ready, 1: Ready',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;	
      					case 'dcStatus':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'dcStatus, 0: Stopped, 1: Battery input, 2: Battery output',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;						
      					case 'electricLevel':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Total Battery Charge Level',
                                      type: 'number',
                                      desc: 'SoC',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: '%',
                                  });
                              }
                              break;
      					case 'FMVolt':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Voltage activation value',
                                      type: 'number',
                                      desc: 'SoC',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: 'V',
                                  });
                              }
                              break;
                          case 'gridInputPower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Grid Input Power to Battery',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                      unit: 'W',
                                  });
                              }
                              break;
                          case 'gridReverse':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: '0: Disabled, 1: Allowed reverse flow, 2: Forbidden reverse flow',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;
                          case 'gridStandard':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Grid connection standard 0: Germany 1: France 2: Austria',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;
                          case 'gridState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Grid connection state, 0: Not connected, 1: Connected',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;									
                          case 'heatState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Heat State, 0: Not heating, 1: heating',
                                      type: 'number',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;		
      					case 'hyperTmp':
                              val = (val - 2731) / 10.0;
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Enclosure Temperature',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          unit: '°C',
                                          });
                                      }
                              break;
      					case 'inputLimit':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'AC charging power limit to Battery',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          unit: 'W',
                                          });
                                      }
                              break;
      					case 'inverseMaxPower': 
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Max inverter output Power Limit',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          unit: 'W',
                                          });
                                      }
                              break;
      					case 'minSoc':
                              val = val / 10;
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
      							setState(dpSetMinSoc, val, true);							   
                                      } else {
                                          createState(statePath, val, {
                                          name: 'min SoC',
                                          type: 'number',
                                          desc: 'minimum Battery SoCset',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          unit: '%',
                                          });
                                      }
                              break;
      					case 'outputHomePower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'outputHomePower',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      							        unit: 'W',
                                          });
      								}
                              break;
      					case 'outputLimit':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Output power limit',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      							        unit: 'W',
                                          });
      								}
                              break;
      					case 'outputPackPower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Output power to battery pack (charging)',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      							        unit: 'W',
                                          });
      								}
                              break;
      					case 'packInputPower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Battery pack input power (discharging)',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      							        unit: 'W',
                                          });
      								}
                              break;
      					case 'packNum':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Number of battery packs',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;
      					case 'packState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Battery State, 0: Standby, 1: Charging, 2: Discharging',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;
      					case 'pass':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Bypass, 0: No, 1: Yes',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;
      					case 'pvStatus':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'PV State producing, 0: Stopped, 1: Running',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;
                          case 'acStatus':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'AC state 0-2',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;							
      					case 'remainOutTime':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Estimated discharge time in minutes, if not predictable: 59940',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'min',
                                          });
      								}
                              break;		
      					case 'reverseState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Reverse flow, 0: No, 1: Reverse flow',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;			
      					case 'rssi':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: 'Received Signal Strength Indicator',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'dBm',
                                          });
      								}
                              break;
      					case 'gridOffPower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Off-grid power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
      					case 'lampSwitch':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Lamp state 0: off / 1: on',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'gridOffMode':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Off-grid mode',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'IOTState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'IoT connection',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'fanSwitch':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Fan state 0:off 1:on',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'fanSpeed':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Fan level',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'faultLevel':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Fault severity',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'bindstate':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Bind state',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'VoltWakeup':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Voltage wake-up',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'OldMode':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Legacy mode',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'OTAState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'OTA state',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'LCNState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'LCN state',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'factoryModeState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'factory Mode State, should be: 0',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'phaseSwitch':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Phase Switch',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'is_error':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Error flag 0: no Error  1: Error',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'smartMode':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
      									createState(statePath, val, {
                                          name: '1: parameter written to RAM / 0: parameter is written to flash.',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
      								}
                              break;
      					case 'sn':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: 'Device serial number',
                                      type: 'string',
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;
      					case 'socLimit':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'socLimit-Info 0: normal, 1: Charge limit reached, 2: Discharge limit reached',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'socSet':
                              val = val / 10;
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
      							setState(dpSetSocSet, val, true);			
                                      } else {
                                          createState(statePath, val, {
                                          name: 'max SoC',
                                          type: 'number',
                                          desc: 'maximum Battery SoCset',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          unit: '%',
                                          });
                                      }
                              break;
      					case 'socStatus':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Info of Calibrating, 0: No / 1: Calibrating',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'solarInputPower':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Total Solar Input Power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower1':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 1 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower2':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 2 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower3':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 3 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower4':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 4 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower5':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 5 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
                          case 'solarPower6':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Solar line 6 input power',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
      									unit: 'W',
                                          });
                                      }
                              break;
      					case 'timeZone':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Timezone',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'tsZone':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Timezone offset',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
      					case 'acCouplingState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
      									name: 'AC Coupling State',
      									type: 'number',
      									role: 'value',
      									read: true,
      									write: false
      									});
                                      }
      						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";
      						const stringPath = statePath + "_String"; // acCouplingState_String
      						if (existsState(stringPath)) {
      						setState(stringPath, statusText, true);
      						} else {
      							createState(stringPath, statusText, { name: 'AC Coupling State Info', type: 'string', role: 'text', read: true, write: false });
      						}
      					break;
      					case 'dryNodeState':
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                                      } else {
                                          createState(statePath, val, {
                                          name: 'Dry contact status 1: Connected 0: Connected(May be reversed depending on actual wiring)',
                                          type: 'number',
                                          role: 'value',
                                          read: true,
                                          write: false,
                                          });
                                      }
                              break;
                          case 'timestamp':
                              const timestampVal = obj[i];
                              const timestampFormatted = formatTime(timestampVal);
                              if (existsState(statePath)) setState(statePath, timestampVal, true);
                              else createState(statePath, timestampVal, {
                                  name: 'Unix timestamp',
                                  type: 'number',
                                  desc: 'unix timestamp in Seconds since Jan 01 1970 (UTC)',
                                  role: 'value',
                                  read: true,
                                  write: false,
                              });
                              if (existsState(id + '.timeUpdateTimestamp')) setState(id + '.timeUpdateTimestamp', timestampFormatted, true);
                              else createState(id + '.timeUpdateTimestamp', timestampFormatted, {
                                  name: 'TimeUpdate (timestamp)',
                                  type: 'string',
                                  desc: 'unix timestamp in readable Format (timestamp)',
                                  read: true,
                                  write: false,
                              });
                              break;
                          case 'ts':
                              const tsVal = obj[i];
                              const tsFormatted = formatTime(tsVal);
                              if (existsState(statePath)) setState(statePath, tsVal, true);
                              else createState(statePath, tsVal, {
                                  name: 'System timestamp (ts)',
                                  type: 'number',
                                  desc: 'System timestamp in Seconds since Jan 01 1970 (UTC)',
                                  role: 'value',
                                  read: true,
                                  write: false,
                              });
                              if (existsState(id + '.timeUpdateTs')) setState(id + '.timeUpdateTs', tsFormatted, true);
                              else createState(id + '.timeUpdateTs', tsFormatted, {
                                  name: 'TimeUpdate (ts)',
                                  type: 'string',
                                  desc: 'System timestamp in readable Format (ts)',
                                  read: true,
                                  write: false,
                              });
                              break;			
                          default:
                              if (existsState(statePath)) {
                                  setState(statePath, val, true);
                              } else {
                                  createState(statePath, val, {
                                      name: i,
                                      type: typeof val,
                                      role: 'value',
                                      read: true,
                                      write: false,
                                  });
                              }
                              break;
                      }
                  }
              }
          } catch (e) {
              log(`Error in iter: ${e}`, 'info');
          }
      }
      
      
      

      Euch allen viel Sonne und weiterhin viel Freude.

      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
      1
      • D Online
        D Online
        Daniel 8
        schrieb am zuletzt editiert von Daniel 8
        #233

        Ich weiß aktuell gerade nicht was für eine scriptVersion ich laufen habe. Hatte aber meines Wissens nach keinerlei Fehlermeldung beim statt des scripts. Im Moment habe ich auch noch alles über mqtt laufen außer die smartMode Abfrage.
        Bin froh wenn gerade mal alles läuft und ich nichts basteln muss, da mir dazu auch die Zeit fehlt.
        Also habe ich das richtig interpretiert, das eine 8 Sekundenabfrage kein Problem darstellt und zwischen dem senden immer 5 Sekunden Pause sind?

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

        maxclaudiM 1 Antwort Letzte Antwort
        0
        • D Daniel 8

          Ich weiß aktuell gerade nicht was für eine scriptVersion ich laufen habe. Hatte aber meines Wissens nach keinerlei Fehlermeldung beim statt des scripts. Im Moment habe ich auch noch alles über mqtt laufen außer die smartMode Abfrage.
          Bin froh wenn gerade mal alles läuft und ich nichts basteln muss, da mir dazu auch die Zeit fehlt.
          Also habe ich das richtig interpretiert, das eine 8 Sekundenabfrage kein Problem darstellt und zwischen dem senden immer 5 Sekunden Pause sind?

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

          @Daniel-8 sagte:

          Also habe ich das richtig interpretiert, das eine 8 Sekundenabfrage kein Problem darstellt

          Richtig.
          Es kann auch mit 6 Sek. gefahrlos getestet werden.
          Das Skript arbeitet mit einer Warteschlange (Queue). Das heißt, alle Anfragen (Watt lesen oder Werte schreiben) werden nacheinander abgearbeitet. Damit das stabil bleibt, müssen die Intervalle auf die Timeout-Zeit (2 Sek.) abgestimmt sein.
          Voraussetzung ist eine gute, stabile und nicht überlastete WLAN-Verbindung.
          Evtl. ein extra WLAN mit Access Point (AP) nur für Zendure-Gerät(e).


          Abfrage-Intervall (GET)

          const intervalGet = 8;
          

          Standard (Empfohlen): 8 Sekunden
          Technisches Minimum: 5 Sekunden

          @Daniel-8 sagte:
          und zwischen dem senden immer 5 Sekunden Pause sind?

          Richtig.
          Man kann zwar theoretisch schneller Befehle im ioBroker auslösen, aber das Skript lässt diese erst nach der eingestellten Pause, der Reihe nach, in die Warteschlange.

          Sende-Pause (POST)

          const minTimeBreakForSetDpSec = 5;
          

          Standard (Empfohlen): 5 Sekunden
          Technisches Minimum: 4 Sekunden

          EDIT:
          Siehe vorheriges POST.
          Pause kann mit Wert: 0 komplett deaktiviert werden.

          const minTimeBreakForSetDpSec = 0;
          

          Warum diese Mindestwerte?
          Stabilität.

          1. Die 2x-Timeout-Regel:
            Sobald Du einen Wert sendest (POST), schickt das Skript sofort eine Abfrage (GET) hinterher, um den Status zu aktualisieren.
            Im Fehlerfall (WLAN-Lag) dauert dieser Vorgang bis zu 4 Sekunden (2x 2 Sek. bei 2000ms Timeout). Die Sende-Pause muss also immer länger als diese 4 Sekunden sein, sonst stauen sich die Befehle in der Warteschlange..

          2. Abfrage-Puffer:
            Das Abfrage-Intervall (GET) muss deutlich über dem Timeout liegen, damit das Skript Zeit hat, die Warteschlange nach einem Fehler sauber zu leeren.


          Wichtig: Bei schlechtem WLAN

          Wenn das WLAN nicht absolut stabil ist, sollte man die Zeiten nicht verringern, sondern eher erhöhen:

          • intervalGet: auf 10–12 Sekunden
          • minTimeBreak (Pause): auf 8 Sekunden

          Bei schlechtem Empfang laufen Anfragen evtl. oft in den 2-Sekunden-Timeout.
          Wenn man dann zu schnell neue Anfragen nachschiebt, "verstopft" die Kommunikation zum Zendure-Gerät komplett und der interne Prozessor (ESP) kommt nicht mehr hinterher.
          Könnte evtl. sogar die Kommunikation beenden.
          Nur so ist sichergestellt, dass über HTTP alles reibungslos funktioniert.
          Mir ist kein Weg bekannt, das auf andere Weise "sicherer" über HTTP zu gewährleisten.

          Mit den Standard-Einstellungen funktioniert es im Dauerbetrieb sehr zuverlässig.

          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
          1
          • maxclaudiM maxclaudi

            @Daniel-8 sagte:

            Also habe ich das richtig interpretiert, das eine 8 Sekundenabfrage kein Problem darstellt

            Richtig.
            Es kann auch mit 6 Sek. gefahrlos getestet werden.
            Das Skript arbeitet mit einer Warteschlange (Queue). Das heißt, alle Anfragen (Watt lesen oder Werte schreiben) werden nacheinander abgearbeitet. Damit das stabil bleibt, müssen die Intervalle auf die Timeout-Zeit (2 Sek.) abgestimmt sein.
            Voraussetzung ist eine gute, stabile und nicht überlastete WLAN-Verbindung.
            Evtl. ein extra WLAN mit Access Point (AP) nur für Zendure-Gerät(e).


            Abfrage-Intervall (GET)

            const intervalGet = 8;
            

            Standard (Empfohlen): 8 Sekunden
            Technisches Minimum: 5 Sekunden

            @Daniel-8 sagte:
            und zwischen dem senden immer 5 Sekunden Pause sind?

            Richtig.
            Man kann zwar theoretisch schneller Befehle im ioBroker auslösen, aber das Skript lässt diese erst nach der eingestellten Pause, der Reihe nach, in die Warteschlange.

            Sende-Pause (POST)

            const minTimeBreakForSetDpSec = 5;
            

            Standard (Empfohlen): 5 Sekunden
            Technisches Minimum: 4 Sekunden

            EDIT:
            Siehe vorheriges POST.
            Pause kann mit Wert: 0 komplett deaktiviert werden.

            const minTimeBreakForSetDpSec = 0;
            

            Warum diese Mindestwerte?
            Stabilität.

            1. Die 2x-Timeout-Regel:
              Sobald Du einen Wert sendest (POST), schickt das Skript sofort eine Abfrage (GET) hinterher, um den Status zu aktualisieren.
              Im Fehlerfall (WLAN-Lag) dauert dieser Vorgang bis zu 4 Sekunden (2x 2 Sek. bei 2000ms Timeout). Die Sende-Pause muss also immer länger als diese 4 Sekunden sein, sonst stauen sich die Befehle in der Warteschlange..

            2. Abfrage-Puffer:
              Das Abfrage-Intervall (GET) muss deutlich über dem Timeout liegen, damit das Skript Zeit hat, die Warteschlange nach einem Fehler sauber zu leeren.


            Wichtig: Bei schlechtem WLAN

            Wenn das WLAN nicht absolut stabil ist, sollte man die Zeiten nicht verringern, sondern eher erhöhen:

            • intervalGet: auf 10–12 Sekunden
            • minTimeBreak (Pause): auf 8 Sekunden

            Bei schlechtem Empfang laufen Anfragen evtl. oft in den 2-Sekunden-Timeout.
            Wenn man dann zu schnell neue Anfragen nachschiebt, "verstopft" die Kommunikation zum Zendure-Gerät komplett und der interne Prozessor (ESP) kommt nicht mehr hinterher.
            Könnte evtl. sogar die Kommunikation beenden.
            Nur so ist sichergestellt, dass über HTTP alles reibungslos funktioniert.
            Mir ist kein Weg bekannt, das auf andere Weise "sicherer" über HTTP zu gewährleisten.

            Mit den Standard-Einstellungen funktioniert es im Dauerbetrieb sehr zuverlässig.

            maxclaudiM Offline
            maxclaudiM Offline
            maxclaudi
            schrieb zuletzt editiert von
            #235

            Dufte 2 neue Geräte testen.

            Herzlichen Dank an die Leihsteller (die nicht genannt werden möchten) für das Vertrauen und den Rabatt beim Übernehmen eines Geräts.

            Schade ist nur, dass die gesetzliche EN 18031-Norm bei MQTT/TLS umgesetzt werden musste, was für mich keinen Mehrwert bedeutet.
            Das Problem ist die fehlende Flexibilität:
            Durch die strikte TLS-Umsetzung (Certificate Pinning) lassen sich die Geräte leider nicht mehr mit einem lokalen MQTT-Broker als Cloud-Ersatz verwenden.

            Das herkömmliche 'offizielle, lokale MQTT' ist mit der langsamen Aktualisierung, der anderen Struktur und weniger Möglichkeiten zu reglementiert und für mich leider völlig unbrauchbar.

            Hoffe nur, dass das zenSDK nicht weiter eingeschränkt wird.

            Noch einmal vielen Dank.

            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 Online
              D Online
              Daniel 8
              schrieb zuletzt editiert von
              #236

              @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?

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

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

                @maxclaudi
                Hab dein Script (Version 2026.04.19_01.15h) jetzt mal mit dem Solarflow 800 Pro 2 getestet (Firmware 1.02) .
                Kann ich dieses Script für Windows nehmen ?

                Ich erhalte beim Start folgenden Fehler:

                GET parse error: SyntaxError: Unexpected token 'N', "Not Found" is not valid JSON
                
                maxclaudiM 1 Antwort Letzte Antwort
                0
                • Bernd1967B Bernd1967

                  @maxclaudi
                  Hab dein Script (Version 2026.04.19_01.15h) jetzt mal mit dem Solarflow 800 Pro 2 getestet (Firmware 1.02) .
                  Kann ich dieses Script für Windows nehmen ?

                  Ich erhalte beim Start folgenden Fehler:

                  GET parse error: SyntaxError: Unexpected token 'N', "Not Found" is not valid JSON
                  
                  maxclaudiM Offline
                  maxclaudiM Offline
                  maxclaudi
                  schrieb zuletzt editiert von
                  #238

                  @Bernd1967
                  sorry im meeting.
                  Firmware aktuell?
                  Danach oder wenn ja:
                  To enable the local API, add HEMS and then exit to apply.

                  Also HEMS aktivieren. etwas warten und danach wieder deaktivieren.

                  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
                  • Bernd1967B Offline
                    Bernd1967B Offline
                    Bernd1967
                    schrieb 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 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 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 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

                          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

                          584

                          Online

                          32.8k

                          Benutzer

                          82.8k

                          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