Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • 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. ioBroker Allgemein
  4. Venus V3.0 API Token

NEWS

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    17
    1
    488

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    5.2k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    1.4k

Venus V3.0 API Token

Geplant Angeheftet Gesperrt Verschoben ioBroker Allgemein
25 Beiträge 9 Kommentatoren 1.4k Aufrufe 8 Watching
  • Ä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.
  • D Offline
    D Offline
    derkleinschreiber
    schrieb am zuletzt editiert von derkleinschreiber
    #12

    Hallo.
    Dein Linux Image ist offenbar Openbsd basiert, deshalb brauchst du einen anden Install code.. aber das hat ja geklappt.

    Der "Error" ist kein Error.. im log steht das nur weil du / ich den Output als "Fehler" Ausgabe deklarierst.

    Im 2ten Beispiel hast du 2 sachen geändert.

    1. Du fragst als GetDevice ab.. -> Das must du wiklirch nur einmalig nach dem einschalten des Venus machen. Er öffnet darauf hin die Api und antwortet solang bis er wirklich aus war. Danach schickst du direkt das nächste Kommando. Eventuell ist dem Venus oder dem Netzwerk zu schnell.. und es gibt dann keine Antwort.

    Mach mal 3 Programme raus und starte die nacheinander. Oder mach einfach mal 2 Sekunden Pause dazwischen.. Erst GetDevice, dann GetMode, und dann Bat.getmode..

    echo '{ "id": 1, "method": "ES.GetMode", "params": { "id": 0 } }'| nc -u -w 1 192.168.178.149 30000 -> "-w 1" bedeutet nach einer Sekunde verbindung abbrechen und ausgeben. Eventuell ist noch gar kein Antwort-Paket angekommen - oder das Anfrage-Paket ist nicht beim Marstek angekommen..

    Vielleicht hast du auch beim kopieren der Befehle nen Fehler gemacht. IP / Port ? und mir ist aufgefallen das man aus der API Doku nicht rauskopieren kann. (Die Klammern sind dann immer falsch).

    Du kannst die Netcat Befehle auch erst alle direkt auf der Console testen mit und ohne -w "Sekunden" . Dann kannst du sehen ob du überhaupt direkt jedes mal ne Antwort bekommst und auch mal gucken wie schnell das klappt.

    nachtrag: Welche Firmware Version hast auf dem Venus ? Und ist es Version 1 2 oder 3
    nachtrag2: ich lass mir auch den gesendeten Befehl ins log schreiben, so kann man sehen oder tatsächlich der richitge Befehl gesendet wird (wegen dem hochkomma problem - ich weiß nicht ob das bei OpenBsd genauso klappt wie bei mir)

    1 Antwort Letzte Antwort
    0
    • S Offline
      S Offline
      schneire
      schrieb am zuletzt editiert von
      #13

      Bei mir läuft auf dem Venus 3.0 eine Firmware V147.117.112 leider nicht ohne Probleme so dass ich deshalb auch Firmware-Fehler / API-Fehler vermute. Mal sehen was mit den Support für einen Version kommt. Und auch mit Pausen waren noch nicht erfolgreich.

      influxdb2.7, mqtt, Grafana, Raspberry Pi5, Venus-Os m.Raspi3, JK-BMS

      1 Antwort Letzte Antwort
      0
      • T Offline
        T Offline
        technogodder
        schrieb am zuletzt editiert von
        #14

        Hallo, ich habe seit gestern auch den Marstek Venus E 3.0 und habe den Support angeschrieben, dass ich ebenfalls eine Freigabe für Smarthome benötige. Sie haben mir heute geantwortet, dass sie jetzt für mich MQTT freigeschaltet haben. Eigentlich benötige ich in iobroker den Füllstand, ob lädt oder entlädt, und die Leistung.

        Jetzt stehe ich allerdings auf dem Schlauch, normalerweise müsste ich doch jetzt meine iobroker-ip und port irgendwo in der Marstek-App eingeben oder habe ich einen Denkfehler? Neue Einstellungen habe ich jetzt nicht in der App, nur das bekannte "Local API" und den Port.

        1 Antwort Letzte Antwort
        0
        • D derkleinschreiber

          Hallo !
          vielen Dank für den Code !

          Api freischalten geht seit etwa Dezember direkt in der App.

          Geht einwandfrei !

          --> ein bischen Offtopic: Sollte jemand lieber mit Blockly "programmieren" geht das sehr einfach mit exec aufrufen (mit netcat = nc)

          echo '{"id":1,"method":"Bat.GetStatus","params":{"id":0}}' | nc -u -w 1 192.168.178.xyz 30000

          Alles andere aus der API kann man damit auch abfragen / übertragen / Modes setzen etc. Habs grad probiert. Wichtig ist nur das vorher einmalig :

          echo '{ "id": 0, "method": "Marstek.GetDevice", "params": { "ble_mac":"0" } } ' | nc -u -w 1 192.168.178.255 30000 gesendet wird damit er die UDP API aktiviert.

          Manchmnal antwort mein Marstek Venus E v3 erst beim 2ten mal. Offenbar muss er nach längerer Zeit immer erst auffwachen.

          K Offline
          K Offline
          KSN
          schrieb am zuletzt editiert von
          #15

          @derkleinschreiber sagte in Venus V3.0 API Token:

          --> ein bischen Offtopic: Sollte jemand lieber mit Blockly "programmieren" geht das sehr einfach mit exec aufrufen (mit netcat = nc)

          echo '{"id":1,"method":"Bat.GetStatus","params":{"id":0}}' | nc -u -w 1 192.168.178.xyz 30000

          Alles andere aus der API kann man damit auch abfragen / übertragen / Modes setzen etc. Habs grad probiert. Wichtig ist nur das vorher einmalig :

          echo '{ "id": 0, "method": "Marstek.GetDevice", "params": { "ble_mac":"0" } } ' | nc -u -w 1 192.168.178.255 30000 gesendet wird damit er die UDP API aktiviert.

          WIe @derkleinschreiber oben sagte, versuche ich, meine Venus E 3.0 (am LAN) und CT002 über die API auszulesen mit netcat.
          Venus Version ist V148.
          ping auf die Adresse geht.
          Wenn ich Kommandos sende erhalte ich auch eine Antwort, alledings immer einen Fehler.
          Prinzipiell scheint daher die Venus ja zu antworten.

          auch nach mehrmaligem Senden von Bat.GetStatus :
          Kommando:
          MARSTEK_Result=echo '{ "id": 0, "method": "Marstek.GetDevice", "params": { "ble_mac":"0"}} ' | nc -u -w 1 192.168.2.33 30000
          Ergebnis:
          MARSTEK_Result={ "id": 0, "src": "VenusE 3.0-bc2a33ad06aa", "error": { "code": -32700, "message": "Parse error", "data": 402 } }

          Hat jemand eine Idee, woran es liegen kann?

          Herzlichen Dank für euren Support!

          L 1 Antwort Letzte Antwort
          0
          • K KSN

            @derkleinschreiber sagte in Venus V3.0 API Token:

            --> ein bischen Offtopic: Sollte jemand lieber mit Blockly "programmieren" geht das sehr einfach mit exec aufrufen (mit netcat = nc)

            echo '{"id":1,"method":"Bat.GetStatus","params":{"id":0}}' | nc -u -w 1 192.168.178.xyz 30000

            Alles andere aus der API kann man damit auch abfragen / übertragen / Modes setzen etc. Habs grad probiert. Wichtig ist nur das vorher einmalig :

            echo '{ "id": 0, "method": "Marstek.GetDevice", "params": { "ble_mac":"0" } } ' | nc -u -w 1 192.168.178.255 30000 gesendet wird damit er die UDP API aktiviert.

            WIe @derkleinschreiber oben sagte, versuche ich, meine Venus E 3.0 (am LAN) und CT002 über die API auszulesen mit netcat.
            Venus Version ist V148.
            ping auf die Adresse geht.
            Wenn ich Kommandos sende erhalte ich auch eine Antwort, alledings immer einen Fehler.
            Prinzipiell scheint daher die Venus ja zu antworten.

            auch nach mehrmaligem Senden von Bat.GetStatus :
            Kommando:
            MARSTEK_Result=echo '{ "id": 0, "method": "Marstek.GetDevice", "params": { "ble_mac":"0"}} ' | nc -u -w 1 192.168.2.33 30000
            Ergebnis:
            MARSTEK_Result={ "id": 0, "src": "VenusE 3.0-bc2a33ad06aa", "error": { "code": -32700, "message": "Parse error", "data": 402 } }

            Hat jemand eine Idee, woran es liegen kann?

            Herzlichen Dank für euren Support!

            L Offline
            L Offline
            logaems
            schrieb am zuletzt editiert von logaems
            #16

            @KSN
            setze als ble_mac mal die Bluetoothadresse des Gerätes ein. SIe steht auf dem Aufkleber des Gerätes. So eingeben, wie sie dort steht ... also anstellle der "0" "12ab34cd .."
            Irgendwie sehe ich das in der v2.0 Doku der API nicht mehr. Ich hatte nach der v1.0 gearbeitet
            Es wird ja mit einem parsing-Fehler geantwortet. Vielleicht musst du die "0" auch ohne "" senden. Ich las mal irgendwo, dass Marstek die Variablentypen auch mal ändert.

            1 Antwort Letzte Antwort
            0
            • H Nicht stören
              H Nicht stören
              Hansi1234
              schrieb am zuletzt editiert von Hansi1234
              #17

              puh weil ich jetzt ewig herumgetan habe, hier meine Tip: Nach dem Ändern der Ports von 30000 auf 2220 ging es. Hab das Script @stephan61 von ChatGPT erweitern lassen. @technogodder das gleiche Problem hatte ich auch. Versuchs mit der Portänderung und folgendem Script:

              /***********************
               MARSTEK VENUS E UDP
               erweiterte Version
              ***********************/
              
              const DEVICE_IP = "192.168.179.103";
              const DEVICE_PORT = 2220;
              
              const POLL_INTERVAL = 10; // Sekunden
              const TIMEOUT = 30; // Sekunden bis Gerät als offline gilt
              const DEBUG = false;
              
              const dgram = require("dgram");
              let socket = dgram.createSocket("udp4");
              
              let lastResponse = Date.now();
              
              /***********************
               STATES
              ***********************/
              
              const BASE = "0_userdata.0.marstek.";
              
              const STATES = {
                  soc: BASE + "battery.soc",
                  batteryPower: BASE + "battery.power",
                  gridPower: BASE + "grid.power",
                  pvPower: BASE + "pv.power",
                  temperature: BASE + "device.temperature",
                  online: BASE + "device.online"
              };
              
              createState(STATES.soc, 0, { name: "Battery SOC", unit: "%", type: "number", role: "value.battery" });
              createState(STATES.batteryPower, 0, { name: "Battery Power", unit: "W", type: "number", role: "value.power" });
              createState(STATES.gridPower, 0, { name: "Grid Power", unit: "W", type: "number", role: "value.power" });
              createState(STATES.pvPower, 0, { name: "PV Power", unit: "W", type: "number", role: "value.power" });
              createState(STATES.temperature, 0, { name: "Temperature", unit: "°C", type: "number", role: "value.temperature" });
              createState(STATES.online, false, { name: "Device Online", type: "boolean", role: "indicator.reachable" });
              
              /***********************
               JSON RPC REQUESTS
              ***********************/
              
              const requests = {
              
                  battery: JSON.stringify({
                      id: 1,
                      method: "Bat.GetStatus",
                      params: { id: 0 }
                  }),
              
                  energy: JSON.stringify({
                      id: 2,
                      method: "ES.GetStatus",
                      params: { id: 0 }
                  }),
              
                  discover: JSON.stringify({
                      id: 0,
                      method: "Marstek.GetDevice",
                      params: { ble_mac: "0" }
                  })
              };
              
              /***********************
               UDP MESSAGE
              ***********************/
              
              socket.on("message", (msg) => {
              
                  const text = msg.toString();
              
                  if (DEBUG) log("UDP: " + text);
              
                  lastResponse = Date.now();
                  setState(STATES.online, true, true);
              
                  try {
              
                      const data = JSON.parse(text);
              
                      if (!data.result) return;
              
                      const r = data.result;
              
                      // SOC
                      if (r.soc !== undefined) {
                          setState(STATES.soc, Number(r.soc), true);
                      }
              
                      if (r.bat_soc !== undefined) {
                          setState(STATES.soc, Number(r.bat_soc), true);
                      }
              
                      // Batterie Leistung
                      if (r.bat_power !== undefined) {
                          setState(STATES.batteryPower, Number(r.bat_power), true);
                      }
              
                      // Netzleistung
                      if (r.ongrid_power !== undefined) {
                          setState(STATES.gridPower, Number(r.ongrid_power), true);
                      }
              
                      // PV Leistung
                      if (r.pv_power !== undefined) {
                          setState(STATES.pvPower, Number(r.pv_power), true);
                      }
              
                      // Temperatur
                      if (r.temp !== undefined) {
                          setState(STATES.temperature, Number(r.temp), true);
                      }
              
                  } catch (e) {
              
                      log("Parse Fehler: " + e, "error");
              
                  }
              
              });
              
              /***********************
               ERROR HANDLING
              ***********************/
              
              socket.on("error", (err) => {
              
                  log("UDP Fehler: " + err.message, "error");
              
              });
              
              /***********************
               SOCKET START
              ***********************/
              
              socket.on("listening", () => {
              
                  const addr = socket.address();
              
                  log("Marstek UDP gestartet: " + addr.address + ":" + addr.port);
              
              });
              
              socket.bind();
              
              /***********************
               POLLING
              ***********************/
              
              function pollDevice() {
              
                  try {
              
                      socket.send(requests.energy, 0, requests.energy.length, DEVICE_PORT, DEVICE_IP);
                      socket.send(requests.battery, 0, requests.battery.length, DEVICE_PORT, DEVICE_IP);
              
                  } catch (e) {
              
                      log("Send Fehler: " + e, "error");
              
                  }
              
              }
              
              schedule("*/" + POLL_INTERVAL + " * * * * *", pollDevice);
              
              /***********************
               DISCOVERY
              ***********************/
              
              setTimeout(() => {
              
                  if (DEBUG) log("Discovery Request");
              
                  socket.send(requests.discover, 0, requests.discover.length, DEVICE_PORT, DEVICE_IP);
              
              }, 5000);
              
              /***********************
               OFFLINE CHECK
              ***********************/
              
              setInterval(() => {
              
                  if (Date.now() - lastResponse > TIMEOUT * 1000) {
              
                      setState(STATES.online, false, true);
              
                  }
              
              }, 5000);
              
              1 Antwort Letzte Antwort
              0
              • G Offline
                G Offline
                Gismoh
                schrieb am zuletzt editiert von Gismoh
                #18

                Habe nun auch komplett umgeschwenkt auf die Api Steuerung.
                Mit der neuen Firmware hatte ich zwar auch die Api Funktion in der App, aber der Speicher hatte nicht geantwortet.
                Der Support hatte mir dann neuere Firmware freigeschaltet, und ja hat geklappt, die Speicher kann ich nun via API regeln.
                Das Laden hatte via Skript schon mal geklappt, mal sehen, wie es sich nachher verhält, beim endladen. Das neue Skript ist noch "frisch".

                ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                H 1 Antwort Letzte Antwort
                0
                • G Gismoh

                  Habe nun auch komplett umgeschwenkt auf die Api Steuerung.
                  Mit der neuen Firmware hatte ich zwar auch die Api Funktion in der App, aber der Speicher hatte nicht geantwortet.
                  Der Support hatte mir dann neuere Firmware freigeschaltet, und ja hat geklappt, die Speicher kann ich nun via API regeln.
                  Das Laden hatte via Skript schon mal geklappt, mal sehen, wie es sich nachher verhält, beim endladen. Das neue Skript ist noch "frisch".

                  H Nicht stören
                  H Nicht stören
                  Hansi1234
                  schrieb am zuletzt editiert von
                  #19

                  @Gismoh sagte in Venus V3.0 API Token:

                  Habe nun auch komplett umgeschwenkt auf die Api Steuerung.
                  Mit der neuen Firmware hatte ich zwar auch die Api Funktion in der App, aber der Speicher hatte nicht geantwortet.
                  Der Support hatte mir dann neuere Firmware freigeschaltet, und ja hat geklappt, die Speicher kann ich nun via API regeln.
                  Das Laden hatte via Skript schon mal geklappt, mal sehen, wie es sich nachher verhält, beim endladen. Das neue Skript ist noch "frisch".

                  Kannst du deinen Stand hier aktuell halten? Mein Script ist überhaupt noch nicht ausgereift und mit meiner Shelly Emulation hab ich nur Probleme

                  G 1 Antwort Letzte Antwort
                  0
                  • H Hansi1234

                    @Gismoh sagte in Venus V3.0 API Token:

                    Habe nun auch komplett umgeschwenkt auf die Api Steuerung.
                    Mit der neuen Firmware hatte ich zwar auch die Api Funktion in der App, aber der Speicher hatte nicht geantwortet.
                    Der Support hatte mir dann neuere Firmware freigeschaltet, und ja hat geklappt, die Speicher kann ich nun via API regeln.
                    Das Laden hatte via Skript schon mal geklappt, mal sehen, wie es sich nachher verhält, beim endladen. Das neue Skript ist noch "frisch".

                    Kannst du deinen Stand hier aktuell halten? Mein Script ist überhaupt noch nicht ausgereift und mit meiner Shelly Emulation hab ich nur Probleme

                    G Offline
                    G Offline
                    Gismoh
                    schrieb am zuletzt editiert von
                    #20

                    @Hansi1234 gerne.
                    Wie gesagt kann die steuern, das das Skript zwischen laden und entladen wechselt.
                    Aber das Timing stimmt aktuell nicht, bin gerade aktiv am testen und quasi am "debuggen".

                    ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                    H 1 Antwort Letzte Antwort
                    0
                    • G Gismoh

                      @Hansi1234 gerne.
                      Wie gesagt kann die steuern, das das Skript zwischen laden und entladen wechselt.
                      Aber das Timing stimmt aktuell nicht, bin gerade aktiv am testen und quasi am "debuggen".

                      H Nicht stören
                      H Nicht stören
                      Hansi1234
                      schrieb zuletzt editiert von
                      #21

                      @Gismoh ja, Stichwort Hysterese. Aber gab's da nicht ein Adapter Nulleinspeisung oä?
                      Hast du es zufällig geschafft, den Akku via uni-meter zu betreiben?

                      G 2 Antworten Letzte Antwort
                      0
                      • H Hansi1234

                        @Gismoh ja, Stichwort Hysterese. Aber gab's da nicht ein Adapter Nulleinspeisung oä?
                        Hast du es zufällig geschafft, den Akku via uni-meter zu betreiben?

                        G Offline
                        G Offline
                        Gismoh
                        schrieb zuletzt editiert von
                        #22

                        @Hansi1234 ne, unimeter habe ich ja gar nicht versucht. Wollte es ja ohne zusätzlichen Code machen, bei mir war ja alles nur im IOBroker als JS. Hatte dort die Regelung nicht hinbekommen, steuern konnte ich ja.
                        Hatte dies nun komplett verworfen und habe gestern mit der Steuerung über Api angefangen.
                        Ein Adapter "Nulleinspeisung" kenne ich nicht.

                        ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                        1 Antwort Letzte Antwort
                        0
                        • H Hansi1234

                          @Gismoh ja, Stichwort Hysterese. Aber gab's da nicht ein Adapter Nulleinspeisung oä?
                          Hast du es zufällig geschafft, den Akku via uni-meter zu betreiben?

                          G Offline
                          G Offline
                          Gismoh
                          schrieb zuletzt editiert von Gismoh
                          #23

                          @Hansi1234 habe das Regelskript mal sehr verkürzt und viel Funktionen rausgenommen (von ca. 1300 Zeilen auf ca. 200) und teste dies gerade.
                          Neuberechnung auch nur 1x je Minute.
                          Sieht bisher sauber aus, evtl. wollte ich auch direkt zu viel auf einmal.

                          Dies ist mein aktuelles kleines Testscript: (aktuell nur für das endladen)
                          Aber nur für Testzwecke, denn es sind keine Fallbacks etc. eingebaut - lasse ich gerade auch nur unter Aufsicht laufen)

                          // ============================================================
                          // MARSTEK_3 Hauptskript
                          // v1.0.0
                          //
                          // Datenpfad: 0_userdata.0.Akku_PV.Marstek_3.
                          //
                          // Logik:
                          // - Jede Minute: Tibber lesen
                          // - Formel: plug_real + tibber = neues Ziel
                          // - 50/50 auf beide Speicher
                          // - Keine Suppression, keine Verteilung, keine Sonderfaelle
                          // ============================================================
                          
                          const dgram = require('dgram');
                          
                          const DP       = '0_userdata.0.Akku_PV.Marstek_3.';
                          const TIBBER   = 'tibberlink.0.LocalPulse.0.Power';
                          const PLUG_28  = 'shelly.1.shellyplugsg3#3528#1.Relay0.Power';
                          const PLUG_29  = 'shelly.1.shellyplugsg3#3529#1.Relay0.Power';
                          const IP_28    = '192.168.145.179';
                          const IP_29    = '192.168.145.155';
                          const PORT     = 30000;
                          
                          const INTERVALL_MS = 60000; // 1 Minute
                          const MAX_W        = 800;   // Hartgrenze pro Speicher
                          const MIN_W        = 50;    // unter MIN_W -> 0W senden
                          const EV_W         = 10;    // Eigenverbrauch Speicher (Elektronik)
                          
                          let udpClient = null;
                          let ivMain    = null;
                          
                          // ------------------------------------------------------------
                          // Datenpunkte anlegen
                          // ------------------------------------------------------------
                          function initDP() {
                              createState(DP + 'einstellungen.aktiv', true,
                                  { name: 'Steuerung aktiv', type: 'boolean', read: true, write: true });
                              createState(DP + 'einstellungen.max_w_pro_speicher', MAX_W,
                                  { name: 'Max W pro Speicher', type: 'number', unit: 'W', read: true, write: true });
                              createState(DP + 'einstellungen.min_w', MIN_W,
                                  { name: 'Min W (unter diesem Wert -> 0W)', type: 'number', unit: 'W', read: true, write: true });
                          
                              createState(DP + 'status.tibber_w', 0,
                                  { name: 'Tibber aktuell', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.plug_28_w', 0,
                                  { name: 'Plug 3528', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.plug_29_w', 0,
                                  { name: 'Plug 3529', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.ziel_gesamt_w', 0,
                                  { name: 'Ziel gesamt', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.gesendet_28_w', 0,
                                  { name: 'Gesendet 3528', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.gesendet_29_w', 0,
                                  { name: 'Gesendet 3529', type: 'number', unit: 'W', read: true, write: false });
                              createState(DP + 'status.letzte_regelung', '',
                                  { name: 'Letzte Regelung', type: 'string', read: true, write: false });
                          }
                          
                          // ------------------------------------------------------------
                          // UDP
                          // ------------------------------------------------------------
                          function initUDP() {
                              udpClient = dgram.createSocket('udp4');
                              udpClient.on('error', function(e) { log('UDP Fehler: ' + e.message, 'warn'); });
                              udpClient.bind(30002, function() { log('✅ UDP bereit (Port 30002)'); });
                          }
                          
                          function sendManual(ip, watt) {
                              if (!udpClient) return;
                              const power = Math.round(watt); // positiv = entladen, negativ = laden
                              const msg = JSON.stringify({
                                  id: 1, method: 'ES.SetMode',
                                  params: { id: 0, config: {
                                      mode: 'Manual',
                                      manual_cfg: {
                                          time_num: 1,
                                          start_time: '00:00:00',
                                          end_time: '23:59:59',
                                          week_set: 127,
                                          power: power,
                                          enable: 1
                                      }
                                  }}
                              });
                              udpClient.send(Buffer.from(msg), PORT, ip, function(err) {
                                  if (err) log('UDP Send Fehler (' + ip + '): ' + err.message, 'warn');
                              });
                          }
                          
                          // ------------------------------------------------------------
                          // Hilfsfunktionen
                          // ------------------------------------------------------------
                          function safeVal(path, fallback) {
                              try {
                                  const s = getState(path);
                                  if (!s || s.val === null || s.val === undefined) return fallback;
                                  const n = parseFloat(s.val);
                                  return isNaN(n) ? fallback : n;
                              } catch(e) { return fallback; }
                          }
                          
                          function safeBool(path, fallback) {
                              try {
                                  const s = getState(path);
                                  if (!s || s.val === null) return fallback;
                                  return !!s.val;
                              } catch(e) { return fallback; }
                          }
                          
                          // ------------------------------------------------------------
                          // Hauptregelung
                          // ------------------------------------------------------------
                          function regeln() {
                              if (!safeBool(DP + 'einstellungen.aktiv', true)) {
                                  log('⏸️ Steuerung deaktiviert');
                                  return;
                              }
                          
                              const maxW = safeVal(DP + 'einstellungen.max_w_pro_speicher', MAX_W);
                              const minW = safeVal(DP + 'einstellungen.min_w', MIN_W);
                          
                              // Werte lesen
                              const tibber  = safeVal(TIBBER, 0);
                              const plug28  = safeVal(PLUG_28, 0);
                              const plug29  = safeVal(PLUG_29, 0);
                              const plugGes = plug28 + plug29;
                          
                              // Diagnose-Datenpunkte
                              setState(DP + 'status.tibber_w',   Math.round(tibber));
                              setState(DP + 'status.plug_28_w',  Math.round(plug28));
                              setState(DP + 'status.plug_29_w',  Math.round(plug29));
                          
                              // Real entladene Leistung (negativ = Entladen beim Shelly Plug)
                              const realEntladen = plugGes < -EV_W ? Math.abs(plugGes) : 0;
                          
                              // Tempomat-Formel
                              let zielGesamt = realEntladen + tibber;
                              zielGesamt = Math.max(0, zielGesamt);
                          
                              setState(DP + 'status.ziel_gesamt_w', Math.round(zielGesamt));
                          
                              // Unter Minimum -> Standby
                              if (zielGesamt < minW) {
                                  log('⏸️ Standby: Ziel ' + Math.round(zielGesamt) + 'W < Min ' + minW + 'W');
                                  sendManual(IP_28, 0);
                                  sendManual(IP_29, 0);
                                  setState(DP + 'status.gesendet_28_w', 0);
                                  setState(DP + 'status.gesendet_29_w', 0);
                                  setState(DP + 'status.letzte_regelung',
                                      new Date().toLocaleTimeString() + ' | Standby');
                                  return;
                              }
                          
                              // 50/50 aufteilen, begrenzen
                              let w28 = Math.min(Math.round(zielGesamt / 2), maxW);
                              let w29 = Math.min(Math.round(zielGesamt / 2), maxW);
                          
                              // Senden
                              sendManual(IP_28, w28);
                              sendManual(IP_29, w29);
                          
                              setState(DP + 'status.gesendet_28_w', w28);
                              setState(DP + 'status.gesendet_29_w', w29);
                          
                              const ts = new Date().toLocaleTimeString();
                              const info = ts + ' | Tibber: ' + Math.round(tibber) + 'W' +
                                           ' | Plug: ' + Math.round(plugGes) + 'W' +
                                           ' | Ziel: ' + Math.round(zielGesamt) + 'W' +
                                           ' | 3528: ' + w28 + 'W | 3529: ' + w29 + 'W';
                          
                              setState(DP + 'status.letzte_regelung', info);
                              log('📤 ' + info);
                          }
                          
                          // ------------------------------------------------------------
                          // Start / Stop
                          // ------------------------------------------------------------
                          function start() {
                              log('🚀 MARSTEK_3 Hauptskript v1.0.0 gestartet');
                              initDP();
                              initUDP();
                          
                              setTimeout(function() {
                                  regeln(); // sofort einmal
                                  ivMain = setInterval(regeln, INTERVALL_MS);
                                  log('✅ Regelintervall: 60s');
                              }, 2000);
                          }
                          
                          start();
                          
                          onStop(function() {
                              if (ivMain) { clearInterval(ivMain); }
                              if (udpClient) {
                                  sendManual(IP_28, 0);
                                  sendManual(IP_29, 0);
                                  setTimeout(function() {
                                      try { udpClient.close(); } catch(e) {}
                                  }, 500);
                              }
                              log('🛑 MARSTEK_3 gestoppt - 0W gesendet');
                          }, 1500);
                          

                          ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                          H 1 Antwort Letzte Antwort
                          0
                          • G Gismoh

                            @Hansi1234 habe das Regelskript mal sehr verkürzt und viel Funktionen rausgenommen (von ca. 1300 Zeilen auf ca. 200) und teste dies gerade.
                            Neuberechnung auch nur 1x je Minute.
                            Sieht bisher sauber aus, evtl. wollte ich auch direkt zu viel auf einmal.

                            Dies ist mein aktuelles kleines Testscript: (aktuell nur für das endladen)
                            Aber nur für Testzwecke, denn es sind keine Fallbacks etc. eingebaut - lasse ich gerade auch nur unter Aufsicht laufen)

                            // ============================================================
                            // MARSTEK_3 Hauptskript
                            // v1.0.0
                            //
                            // Datenpfad: 0_userdata.0.Akku_PV.Marstek_3.
                            //
                            // Logik:
                            // - Jede Minute: Tibber lesen
                            // - Formel: plug_real + tibber = neues Ziel
                            // - 50/50 auf beide Speicher
                            // - Keine Suppression, keine Verteilung, keine Sonderfaelle
                            // ============================================================
                            
                            const dgram = require('dgram');
                            
                            const DP       = '0_userdata.0.Akku_PV.Marstek_3.';
                            const TIBBER   = 'tibberlink.0.LocalPulse.0.Power';
                            const PLUG_28  = 'shelly.1.shellyplugsg3#3528#1.Relay0.Power';
                            const PLUG_29  = 'shelly.1.shellyplugsg3#3529#1.Relay0.Power';
                            const IP_28    = '192.168.145.179';
                            const IP_29    = '192.168.145.155';
                            const PORT     = 30000;
                            
                            const INTERVALL_MS = 60000; // 1 Minute
                            const MAX_W        = 800;   // Hartgrenze pro Speicher
                            const MIN_W        = 50;    // unter MIN_W -> 0W senden
                            const EV_W         = 10;    // Eigenverbrauch Speicher (Elektronik)
                            
                            let udpClient = null;
                            let ivMain    = null;
                            
                            // ------------------------------------------------------------
                            // Datenpunkte anlegen
                            // ------------------------------------------------------------
                            function initDP() {
                                createState(DP + 'einstellungen.aktiv', true,
                                    { name: 'Steuerung aktiv', type: 'boolean', read: true, write: true });
                                createState(DP + 'einstellungen.max_w_pro_speicher', MAX_W,
                                    { name: 'Max W pro Speicher', type: 'number', unit: 'W', read: true, write: true });
                                createState(DP + 'einstellungen.min_w', MIN_W,
                                    { name: 'Min W (unter diesem Wert -> 0W)', type: 'number', unit: 'W', read: true, write: true });
                            
                                createState(DP + 'status.tibber_w', 0,
                                    { name: 'Tibber aktuell', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.plug_28_w', 0,
                                    { name: 'Plug 3528', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.plug_29_w', 0,
                                    { name: 'Plug 3529', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.ziel_gesamt_w', 0,
                                    { name: 'Ziel gesamt', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.gesendet_28_w', 0,
                                    { name: 'Gesendet 3528', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.gesendet_29_w', 0,
                                    { name: 'Gesendet 3529', type: 'number', unit: 'W', read: true, write: false });
                                createState(DP + 'status.letzte_regelung', '',
                                    { name: 'Letzte Regelung', type: 'string', read: true, write: false });
                            }
                            
                            // ------------------------------------------------------------
                            // UDP
                            // ------------------------------------------------------------
                            function initUDP() {
                                udpClient = dgram.createSocket('udp4');
                                udpClient.on('error', function(e) { log('UDP Fehler: ' + e.message, 'warn'); });
                                udpClient.bind(30002, function() { log('✅ UDP bereit (Port 30002)'); });
                            }
                            
                            function sendManual(ip, watt) {
                                if (!udpClient) return;
                                const power = Math.round(watt); // positiv = entladen, negativ = laden
                                const msg = JSON.stringify({
                                    id: 1, method: 'ES.SetMode',
                                    params: { id: 0, config: {
                                        mode: 'Manual',
                                        manual_cfg: {
                                            time_num: 1,
                                            start_time: '00:00:00',
                                            end_time: '23:59:59',
                                            week_set: 127,
                                            power: power,
                                            enable: 1
                                        }
                                    }}
                                });
                                udpClient.send(Buffer.from(msg), PORT, ip, function(err) {
                                    if (err) log('UDP Send Fehler (' + ip + '): ' + err.message, 'warn');
                                });
                            }
                            
                            // ------------------------------------------------------------
                            // Hilfsfunktionen
                            // ------------------------------------------------------------
                            function safeVal(path, fallback) {
                                try {
                                    const s = getState(path);
                                    if (!s || s.val === null || s.val === undefined) return fallback;
                                    const n = parseFloat(s.val);
                                    return isNaN(n) ? fallback : n;
                                } catch(e) { return fallback; }
                            }
                            
                            function safeBool(path, fallback) {
                                try {
                                    const s = getState(path);
                                    if (!s || s.val === null) return fallback;
                                    return !!s.val;
                                } catch(e) { return fallback; }
                            }
                            
                            // ------------------------------------------------------------
                            // Hauptregelung
                            // ------------------------------------------------------------
                            function regeln() {
                                if (!safeBool(DP + 'einstellungen.aktiv', true)) {
                                    log('⏸️ Steuerung deaktiviert');
                                    return;
                                }
                            
                                const maxW = safeVal(DP + 'einstellungen.max_w_pro_speicher', MAX_W);
                                const minW = safeVal(DP + 'einstellungen.min_w', MIN_W);
                            
                                // Werte lesen
                                const tibber  = safeVal(TIBBER, 0);
                                const plug28  = safeVal(PLUG_28, 0);
                                const plug29  = safeVal(PLUG_29, 0);
                                const plugGes = plug28 + plug29;
                            
                                // Diagnose-Datenpunkte
                                setState(DP + 'status.tibber_w',   Math.round(tibber));
                                setState(DP + 'status.plug_28_w',  Math.round(plug28));
                                setState(DP + 'status.plug_29_w',  Math.round(plug29));
                            
                                // Real entladene Leistung (negativ = Entladen beim Shelly Plug)
                                const realEntladen = plugGes < -EV_W ? Math.abs(plugGes) : 0;
                            
                                // Tempomat-Formel
                                let zielGesamt = realEntladen + tibber;
                                zielGesamt = Math.max(0, zielGesamt);
                            
                                setState(DP + 'status.ziel_gesamt_w', Math.round(zielGesamt));
                            
                                // Unter Minimum -> Standby
                                if (zielGesamt < minW) {
                                    log('⏸️ Standby: Ziel ' + Math.round(zielGesamt) + 'W < Min ' + minW + 'W');
                                    sendManual(IP_28, 0);
                                    sendManual(IP_29, 0);
                                    setState(DP + 'status.gesendet_28_w', 0);
                                    setState(DP + 'status.gesendet_29_w', 0);
                                    setState(DP + 'status.letzte_regelung',
                                        new Date().toLocaleTimeString() + ' | Standby');
                                    return;
                                }
                            
                                // 50/50 aufteilen, begrenzen
                                let w28 = Math.min(Math.round(zielGesamt / 2), maxW);
                                let w29 = Math.min(Math.round(zielGesamt / 2), maxW);
                            
                                // Senden
                                sendManual(IP_28, w28);
                                sendManual(IP_29, w29);
                            
                                setState(DP + 'status.gesendet_28_w', w28);
                                setState(DP + 'status.gesendet_29_w', w29);
                            
                                const ts = new Date().toLocaleTimeString();
                                const info = ts + ' | Tibber: ' + Math.round(tibber) + 'W' +
                                             ' | Plug: ' + Math.round(plugGes) + 'W' +
                                             ' | Ziel: ' + Math.round(zielGesamt) + 'W' +
                                             ' | 3528: ' + w28 + 'W | 3529: ' + w29 + 'W';
                            
                                setState(DP + 'status.letzte_regelung', info);
                                log('📤 ' + info);
                            }
                            
                            // ------------------------------------------------------------
                            // Start / Stop
                            // ------------------------------------------------------------
                            function start() {
                                log('🚀 MARSTEK_3 Hauptskript v1.0.0 gestartet');
                                initDP();
                                initUDP();
                            
                                setTimeout(function() {
                                    regeln(); // sofort einmal
                                    ivMain = setInterval(regeln, INTERVALL_MS);
                                    log('✅ Regelintervall: 60s');
                                }, 2000);
                            }
                            
                            start();
                            
                            onStop(function() {
                                if (ivMain) { clearInterval(ivMain); }
                                if (udpClient) {
                                    sendManual(IP_28, 0);
                                    sendManual(IP_29, 0);
                                    setTimeout(function() {
                                        try { udpClient.close(); } catch(e) {}
                                    }, 500);
                                }
                                log('🛑 MARSTEK_3 gestoppt - 0W gesendet');
                            }, 1500);
                            
                            H Nicht stören
                            H Nicht stören
                            Hansi1234
                            schrieb zuletzt editiert von
                            #24

                            @Gismoh heißt du lädst immer manuell auf, wenn du Überschuss hast

                            G 1 Antwort Letzte Antwort
                            0
                            • H Hansi1234

                              @Gismoh heißt du lädst immer manuell auf, wenn du Überschuss hast

                              G Offline
                              G Offline
                              Gismoh
                              schrieb zuletzt editiert von Gismoh
                              #25

                              @Hansi1234 Nein, natürlich nicht.
                              Hatte doch geschrieben, das es nur ein sehr kurzes Testskript war (um Fehlerquellen- auszuschließen). Mein vorherigen Code war x mal so lange und hatte sehr viel mehr features drin.

                              Aber gestern Abend ging es für mich "back to the roots" und nach 21 Uhr gab es eben keine Sonne ;)

                              Hatte es noch ein wenig erweitert, so das ich es habe laufen lassen, und nun bin ich gerade aufgewacht, und es hat bereits geladen, bis Pmax. je Speicher.
                              Und es hat unseren, obwohl sehr einfach geschrieben, Zukauf von Strom, heute bislang auf 60 Watt begrenzt.

                              ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                              1 Antwort Letzte Antwort
                              0
                              Antworten
                              • In einem neuen Thema antworten
                              Anmelden zum Antworten
                              • Älteste zuerst
                              • Neuste zuerst
                              • Meiste Stimmen


                              Support us

                              ioBroker
                              Community Adapters
                              Donate
                              FAQ Cloud / IOT
                              HowTo: Node.js-Update
                              HowTo: Backup/Restore
                              Downloads
                              BLOG

                              571

                              Online

                              32.7k

                              Benutzer

                              82.5k

                              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