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.
  • 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

            577

            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