Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. Hoymiles WR mit 1600W regeln

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    Hoymiles WR mit 1600W regeln

    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      NobbyNobs last edited by

      Guten Abend miteinander,

      ich habe folgendes Setup:

      mME --> Einspeisung WR auf L1 --> ShellyEM 3 --> Verbraucher

      Dieser Aufbau ist den Gegebenheiten geschuldet.

      Ich schreibe meine Daten mittels des Shelly-Adapter in iobroker und mqtt mit. Die Daten des WR liefert mir eine OpenDTU - diese soll auch die neue Leistungsgrenze schreiben.

      Ich habe folgenden JavaScript-Code erarbeitet:

      // Datenpunkte
      const wrPowerDP = 'opendtu.0.1164a00f8949.ac.phase_1.power';  // Wechselrichter-Leistung
      const housePowerDP = 'shelly.0.SHEM-3#485519C98888#1.Total.InstantPower';  // Hausverbrauch
      const mqttLimitDP = 'opendtu.0.1164a00f8949.power_control.limit_nonpersistent_absolute';  // MQTT Limit-Datenpunkt
      const producingDP = 'opendtu.0.1164a00f8949.producing';  // Producing Status
      
      // Konfiguration
      const thresholdWR = 800; // Mindestleistung des Wechselrichters in Watt
      const thresholdDifferenceMin = 400; // Mindestdifferenz für das Setzen eines Limits
      const thresholdDifferenceMax = 50;  // Maximale Differenz, um das Limit zu erhöhen
      const maxWRPower = 1600; // Maximale zulässige Leistung des WR
      const changeThreshold = 10; // Schwellenwert für signifikante Limitänderung (in Watt)
      
      // Initialisiere Zähler-Datenpunkte für Prüfungen und Limitänderungen
      if (!existsState('0_userdata.0.solar.check_counter')) {
          createState('0_userdata.0.solar.check_counter', 0, {
              name: 'Anzahl der Prüfungen',
              type: 'number',
              unit: 'Prüfungen',
              read: true,
              write: true
          });
      }
      
      if (!existsState('0_userdata.0.solar.change_counter')) {
          createState('0_userdata.0.solar.change_counter', 0, {
              name: 'Anzahl der Prüfungen mit Limitänderung',
              type: 'number',
              unit: 'Prüfungen',
              read: true,
              write: true
          });
      }
      
      if (!existsState('0_userdata.0.solar.no_change_counter')) {
          createState('0_userdata.0.solar.no_change_counter', 0, {
              name: 'Anzahl der Prüfungen ohne Limitänderung',
              type: 'number',
              unit: 'Prüfungen',
              read: true,
              write: true
          });
      }
      
      // Differenz-Datenpunkt für Grafana
      if (!existsState('0_userdata.0.solar.wr_haus_difference')) {
          createState('0_userdata.0.solar.wr_haus_difference', 0, {
              name: 'WR - Haus Leistung Differenz',
              type: 'number',
              unit: 'Watt',
              read: true,
              write: true
          });
      }
      
      // Zustand für Low Power Mode
      if (!existsState('0_userdata.0.solar.low_power_mode')) {
          createState('0_userdata.0.solar.low_power_mode', false, {
              name: 'Low Power Mode aktiv',
              type: 'boolean',
              read: true,
              write: true
          });
      }
      
      // Funktion zur Berechnung des Limits
      function calculateLimit(wrPower, housePower) {
          let limit = wrPower - thresholdDifferenceMin;
      
          if (wrPower - housePower < thresholdDifferenceMax || wrPower - housePower > thresholdDifferenceMin) {
              limit = housePower + thresholdDifferenceMin;
          }
      
          if (limit < 0) {
              limit = 0;
          } else if (limit > maxWRPower) {
              limit = maxWRPower;
          }
      
          return limit;
      }
      
      // Hauptfunktion zur Leistungsprüfung und Limitsteuerung
      function checkPower() {
          const wrPower = getState(wrPowerDP).val;
          const housePower = getState(housePowerDP).val;
          const powerDifference = parseFloat((wrPower - housePower).toFixed(2));
          const isLowPower = getState('0_userdata.0.solar.low_power_mode').val;
          const currentLimit = getState(mqttLimitDP).val;
      
          // Prüfungszähler erhöhen
          let checkCount = getState('0_userdata.0.solar.check_counter').val + 1;
          setState('0_userdata.0.solar.check_counter', checkCount);
      
          // WR-Leistung unter Schwellwert → Low Power Mode
          if (wrPower < thresholdWR) {
              if (!isLowPower) {
                  console.log('WR-Leistung unter ' + thresholdWR + ' W – Low Power Mode aktiviert');
                  console.log('Limit wird geändert von ' + currentLimit + ' W auf ' + maxWRPower + ' W');
                  setState(mqttLimitDP, maxWRPower);
                  setState('0_userdata.0.solar.low_power_mode', true);
      
                  let changeCount = getState('0_userdata.0.solar.change_counter').val + 1;
                  setState('0_userdata.0.solar.change_counter', changeCount);
              } else {
                  console.log('Low Power Mode aktiv – WR-Leistung weiter unter ' + thresholdWR + ' W');
                  console.log('Limit bleibt unverändert bei ' + currentLimit + ' W');
                  let noChangeCount = getState('0_userdata.0.solar.no_change_counter').val + 1;
                  setState('0_userdata.0.solar.no_change_counter', noChangeCount);
              }
          } else {
              if (isLowPower) {
                  console.log('WR-Leistung über ' + thresholdWR + ' W – Low Power Mode deaktiviert');
                  setState('0_userdata.0.solar.low_power_mode', false);
              }
      
              if (powerDifference >= 0) {
                  const newLimit = calculateLimit(wrPower, housePower);
      
                  if (Math.abs(currentLimit - newLimit) >= changeThreshold) {
                      console.log('Limit wird geändert von ' + currentLimit + ' W auf ' + newLimit + ' W');
                      setState(mqttLimitDP, newLimit);
      
                      let changeCount = getState('0_userdata.0.solar.change_counter').val + 1;
                      setState('0_userdata.0.solar.change_counter', changeCount);
                  } else {
                      console.log('Limit bleibt unverändert bei ' + currentLimit + ' W – Änderung (' + Math.abs(currentLimit - newLimit) + ' W) unterhalb Schwelle (' + changeThreshold + ' W)');
                      let noChangeCount = getState('0_userdata.0.solar.no_change_counter').val + 1;
                      setState('0_userdata.0.solar.no_change_counter', noChangeCount);
                  }
              } else {
                  console.log('Keine Regelung – WR-Haus Differenz negativ (' + powerDifference + ' W)');
              }
          }
      
          setState('0_userdata.0.solar.wr_haus_difference', powerDifference);
      }
      
      // Sofort prüfen bei Produktionsstart
      on({ id: producingDP, val: true }, function () {
          console.log('Produktion gestartet – Starte erste Prüfung der Leistung');
          checkPower();
      });
      
      // Zyklische Prüfung alle 15 Sekunden bei aktiver Produktion
      setInterval(function () {
          if (getState(producingDP).val === true) {
              checkPower();
          }
      }, 60000);
      
      

      Ich möchte die Anzahl der Schreibvorgänge auf den WR so gering wie möglich halten, daher die eingebauten Einschränkungen.

      Allerdings klappt das schreiben des neuen Limit auf den WR nicht - habe ich irgendwo einen Denkfehler?

      Gruß, NobbyNobs

      1 Reply Last reply Reply Quote 0
      • B
        Beowolf last edited by Beowolf

        Die Logik in "calculateLimit()" ist für mich unklar.

        if (wrPower - housePower < thresholdDifferenceMax || wrPower - housePower > thresholdDifferenceMin)
        

        Diese Bedingung ist irgendwie logisch nicht richtig, glaube ich. Sie trifft immer zu, wenn powerDifference außerhalb des Bereichs thresholdDifferenceMax bis thresholdDifferenceMin liegt.

        Versuche das mal.

        // ===========================
        // Konfiguration
        // ===========================
        const wrPowerDP = 'opendtu.0.1164a00f8949.ac.phase_1.power';
        const housePowerDP = 'shelly.0.SHEM-3#485519C98888#1.Total.InstantPower';
        const mqttLimitDP = 'opendtu.0.1164a00f8949.power_control.limit_nonpersistent_absolute';
        const producingDP = 'opendtu.0.1164a00f8949.producing';
        
        const thresholdWR = 800;
        const thresholdDifferenceMin = 400;
        const thresholdDifferenceMax = 50;
        const maxWRPower = 1600;
        const changeThreshold = 10;
        
        const debug = true; // Setze auf false, um Logs zu deaktivieren
        
        // ===========================
        // Datenpunkt-Initialisierung
        // ===========================
        const statesToInit = [
            { id: '0_userdata.0.solar.check_counter', default: 0, name: 'Anzahl der Prüfungen', type: 'number', unit: 'Prüfungen' },
            { id: '0_userdata.0.solar.change_counter', default: 0, name: 'Anzahl der Prüfungen mit Limitänderung', type: 'number', unit: 'Prüfungen' },
            { id: '0_userdata.0.solar.no_change_counter', default: 0, name: 'Anzahl der Prüfungen ohne Limitänderung', type: 'number', unit: 'Prüfungen' },
            { id: '0_userdata.0.solar.wr_haus_difference', default: 0, name: 'WR - Haus Leistung Differenz', type: 'number', unit: 'Watt' },
            { id: '0_userdata.0.solar.low_power_mode', default: false, name: 'Low Power Mode aktiv', type: 'boolean' }
        ];
        
        statesToInit.forEach(dp => {
            if (!existsState(dp.id)) {
                createState(dp.id, dp.default, {
                    name: dp.name,
                    type: dp.type,
                    unit: dp.unit,
                    read: true,
                    write: true
                });
            }
        });
        
        // ===========================
        // Limitberechnung
        // ===========================
        function calculateLimit(wrPower, housePower) {
            let powerDiff = wrPower - housePower;
            let limit;
        
            if (powerDiff >= thresholdDifferenceMax && powerDiff <= thresholdDifferenceMin) {
                limit = housePower + thresholdDifferenceMin;
            } else {
                limit = wrPower - thresholdDifferenceMin;
            }
        
            if (limit < 0) limit = 0;
            else if (limit > maxWRPower) limit = maxWRPower;
        
            return limit;
        }
        
        // ===========================
        // Hauptfunktion
        // ===========================
        function checkPower() {
            const wrPower = getState(wrPowerDP)?.val ?? 0;
            const housePower = getState(housePowerDP)?.val ?? 0;
            const powerDifference = parseFloat((wrPower - housePower).toFixed(2));
            const isLowPower = getState('0_userdata.0.solar.low_power_mode')?.val ?? false;
            const currentLimit = getState(mqttLimitDP)?.val ?? 0;
        
            // Prüfungszähler erhöhen
            let checkCount = getState('0_userdata.0.solar.check_counter')?.val ?? 0;
            setState('0_userdata.0.solar.check_counter', ++checkCount);
        
            if (wrPower < thresholdWR) {
                if (!isLowPower) {
                    if (debug) {
                        console.log(`WR-Leistung unter ${thresholdWR} W – Low Power Mode aktiviert`);
                        console.log(`Limit wird geändert von ${currentLimit} W auf ${maxWRPower} W`);
                    }
                    setState(mqttLimitDP, maxWRPower);
                    setState('0_userdata.0.solar.low_power_mode', true);
        
                    let changeCount = getState('0_userdata.0.solar.change_counter')?.val ?? 0;
                    setState('0_userdata.0.solar.change_counter', ++changeCount);
                } else {
                    if (debug) {
                        console.log(`Low Power Mode aktiv – WR-Leistung weiter unter ${thresholdWR} W`);
                        console.log(`Limit bleibt unverändert bei ${currentLimit} W`);
                    }
        
                    let noChangeCount = getState('0_userdata.0.solar.no_change_counter')?.val ?? 0;
                    setState('0_userdata.0.solar.no_change_counter', ++noChangeCount);
                }
            } else {
                if (isLowPower) {
                    if (debug) console.log(`WR-Leistung über ${thresholdWR} W – Low Power Mode deaktiviert`);
                    setState('0_userdata.0.solar.low_power_mode', false);
                }
        
                if (powerDifference >= 0) {
                    const newLimit = calculateLimit(wrPower, housePower);
                    const diff = Math.abs(currentLimit - newLimit);
        
                    if (diff >= changeThreshold) {
                        if (debug) console.log(`Limit wird geändert von ${currentLimit} W auf ${newLimit} W`);
                        setState(mqttLimitDP, newLimit);
        
                        let changeCount = getState('0_userdata.0.solar.change_counter')?.val ?? 0;
                        setState('0_userdata.0.solar.change_counter', ++changeCount);
                    } else {
                        if (debug) console.log(`Limit bleibt unverändert bei ${currentLimit} W – Änderung (${diff} W) unterhalb Schwelle (${changeThreshold} W)`);
                        let noChangeCount = getState('0_userdata.0.solar.no_change_counter')?.val ?? 0;
                        setState('0_userdata.0.solar.no_change_counter', ++noChangeCount);
                    }
                } else {
                    if (debug) console.log(`Keine Regelung – WR-Haus Differenz negativ (${powerDifference} W)`);
                }
            }
        
            setState('0_userdata.0.solar.wr_haus_difference', powerDifference);
        }
        
        // ===========================
        // Event- und Zeitsteuerung
        // ===========================
        on({ id: producingDP, val: true }, function () {
            if (debug) console.log('Produktion gestartet – Starte erste Prüfung der Leistung');
            checkPower();
        });
        
        // Zyklische Prüfung alle 60 Sekunden
        setInterval(() => {
            if (getState(producingDP)?.val === true) {
                checkPower();
            }
        }, 60000);
        
        1 Reply Last reply Reply Quote 0
        • agreen
          agreen last edited by agreen

          Da du sowieso OPENDTU verwendest, verwende OpenDTU on Battery.
          Damit kannst du den Wechselrichter nach aktuellem Strombedarf steuern.

          https://github.com/hoylabs/OpenDTU-OnBattery

          1 Reply Last reply Reply Quote 0
          • First post
            Last post

          Support us

          ioBroker
          Community Adapters
          Donate

          421
          Online

          31.9k
          Users

          80.1k
          Topics

          1.3m
          Posts

          3
          3
          182
          Loading More Posts
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes
          Reply
          • Reply as topic
          Log in to reply
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
          The ioBroker Community 2014-2023
          logo