Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU

    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

    [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU

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

      Hi,

      ich montiere aktuell eine PV mit 3x Hoymiles HMS-1600 Wechselrichtern.
      Um diese zu begrenzen habe ich ein Script zusammengeschustert.
      Ich habe es jetzt nur mal manuell getestet, habe aber keine Erfahrungen, wie es sich mit den WR verhält.

      Der Gedanke: Es wird bei jeder Änderung der Wechselrichterleistung geprüft, ob alle Wechselrichter gemeinsam nicht mehr als die vorgegebene Begrenzung einspeisen. Bei Änderung wird proportional die Begrenzung der WR geändert.

      Vielleicht kann dieses Script schon mal jemand testen und gerne Kritik äußern!

      Des Weiteren werde ich das Script step-by-step erweitern wollen. Gerade mit dem Thema der Nulleinspeisung, um die maximale Auslastung zu erreichen.
      Hierzu wären Tipps und Erfahrungen von Euch wünschenswert.
      z.B.: Erst wenn die Einspeisung größer 600/800W beträgt, werden die Wechselrichter begrenzt und/oder werden weitere Verbraucher hinzugeschalten, usw.

      Die Anzahl der Wechselrichter kann beliebig erweitert oder bis auf einen verkürzt werden.
      Ebenfalls ist eine Berechnung für eine Batterieladung integriert.

      https://github.com/Schmakus/ioBroker-Scripte/blob/main/hoymiles-begrenzung.js

      /*
        * Script zur Begrenzung von Hoymiles Wechselrichter in Verbindung mit openDTU
        * v0.0.3 2023/12/12 by Schmakus
        * http://www.github.com/Schmakus/ioBroker-Scripte/
        *
        * Es werden folgende eigene Datenpunkte erstellt:
        *    BegrenzungSoll:          Vorgabe der Gesamtbegrenzung
        *    BegrenzungIst:           Aktuelle Begrenzung in Watt über alle Wechselrichter
        *    BegrenzungIstInProzent:  Aktuelle Begrenzung in Prozent über alle Wechselrichter
        *
        * Info: Die Objekt-IDs im Wechselrichter Objekt sind nur zum Test und müssen mit den richtigen Datenpunkten der Wechselrichter, usw. ersetzt werden!
       */
      
      //Wo sollen die eigenen Datenpunkte angelegt werden?
      const path = "0_userdata.0.PV";
      
      //** Angaben zu den Wechselrichtern */
      const wechselrichter = {
        1: {
          name: "Wechselrichter 1",
          maxLeistung: 1600,
          objLeistung: "0_userdata.0.PV.LeistungWR1", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
          objBegrenzung: "0_userdata.0.PV.BegrenzungWR1", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
          aktuelleLeistung: 0, // Nichts ändern!
          begrenzteLeistung: 0, // Nichts ändern!
        },
        2: {
          name: "Wechselrichter 2",
          maxLeistung: 1600,
          objLeistung: "0_userdata.0.PV.LeistungWR2", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
          objBegrenzung: "0_userdata.0.PV.BegrenzungWR2", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
          aktuelleLeistung: 0, // Nichts ändern!
          begrenzteLeistung: 0, // Nichts ändern!
        },
        3: {
          name: "Wechselrichter 3",
          maxLeistung: 1600,
          objLeistung: "0_userdata.0.PV.LeistungWR3", // Datenpunkt des Wechselrichters der aktuellen Leistung in Watt
          objBegrenzung: "0_userdata.0.PV.BegrenzungWR3", // Beispiel: opendtu.0.xxxxxx.power_control.limit_persistent_absolute)
          aktuelleLeistung: 0, // Nichts ändern!
          begrenzteLeistung: 0, // Nichts ändern!
        },
      };
      
      //Objekt-ID aktuelle Leistungsaufnahme des Hauses
      const objLeistungHaus = "0_userdata.0.PV.LeistungHaus"; // Hier den Datenpunkt zum Smartmeter angeben (Shelly, IR-Lesekopf, etc...)
      
      //Entscheidung ob Batterie geladen werden soll?
      const batterie = {
          laden: true, // true = laden, false = nicht laden
          maxLadeleistung: 600, //maximale Ladeleistung in Watt,
          unit: "volt", // "volt", "watt" or "percent"
          objLadungWatt: "0_userdata.0.PV.LadeleistungBatterie", // Hier den Datenpunkt zum Ladegerät angeben
          objLadungProzent: "0_userdata.0.PV.LadeleistungBatterieInProzent", // Hier den Datenpunkt zum Ladegerät angeben
          objLadungVolt: "0_userdata.0.PV.LadeleistungBatterieInVolt" // Hier den Datenpunkt zum Ladegerät angeben
      }
      
      //**************************** */
      // AB HIER NICHTS MEHR ÄNDERN! //
      //**************************** */
      
      //Variablen
      let wechselrichterLeistungen = [];
      let maximaleLeistungen = [];
      let entpreller = null;
      let maxGesamtLeistung = 0;
      let objBegrenzung = "";
      let objBegrenzungIst = "";
      let objBegrenzungIstProzent = "";
      
      /**
       * Diese Funktion wird aufgerufen, wenn das System bereit ist.
       */
      async function onReady() {
          await setStates();
          await getWechselrichterLeistungen();
      
          for (const wr of Object.values(wechselrichter)) {
              on({ id: wr.objLeistung, change: "ne" }, async (obj) => {
              wr.aktuelleLeistung = obj.state.val;
              console.log(`Aktuelle Leistung eines Wechselrichters aktualisiert. Wechselrichter: ${wr.name}, aktuelle Leistung: ${wr.aktuelleLeistung}`);
              await setWechselrichterLeistungen();
              });
          }
      
          const updateMaxGesamtLeistung = async (obj) => {
                  maxGesamtLeistung = (await getStateAsync(objBegrenzung)).val || 800;
                  await setStateAsync(objBegrenzung, { val: maxGesamtLeistung, ack: true });
                  console.log(`Aktuelle Begrenzung Soll: ${maxGesamtLeistung}`);
                  await setWechselrichterLeistungen();
           };
          
          on({ id: [objLeistungHaus, objBegrenzung], change: "ne" }, updateMaxGesamtLeistung);
      }
      
      /**
       * Diese Funktion erstellt und initialisiert die eigenen Datenpunkte.
       */
      async function setStates() {
          // Maximal zulässige Gesamtleistung
          await createStateAsync(`${path}.BegrenzungSoll`, 800, { read: true, write: true, name: 'Begrenzung Wechselrichter in Summe', type: "number", role: "state", unit: "W", def: 800 });
          await createStateAsync(`${path}.BegrenzungIst`, 0, { read: true, write: false, name: 'Ist-Begrenzung Wechselrichter in Summe [Watt]', type: "number", role: "value", unit: "W", def: 0 });
          await createStateAsync(`${path}.BegrenzungIstInProzent`, 0, { read: true, write: false, name: 'Ist-Begrenzung Wechselrichter in Summe [Prozent]', type: "number", role: "value", unit: "%", def: 0 });
          objBegrenzung = `${path}.BegrenzungSoll`;
          objBegrenzungIst = `${path}.BegrenzungIst`;
          objBegrenzungIstProzent = `${path}.BegrenzungIstInProzent`;
          maxGesamtLeistung = getState(objBegrenzung).val ?? 800;
      }
      
      /**
       * Diese Funktion ruft die aktuellen Leistungen aller Wechselrichter ab.
       */
      async function getWechselrichterLeistungen() {
          for (const wr of Object.values(wechselrichter)) {
              try {
                  const leistung = await getStateAsync(wr.objLeistung);
                  if (leistung) {
                      wr.aktuelleLeistung = leistung.val;
                  } else {
                      console.error(
                      `Could not retrieve state for ${wr.objLeistung}`
                      );
                      wr.aktuelleLeistung = 0; // Use 0 as a default value
                  }
              } catch (error) {
                  console.error(
                      `Error retrieving state for ${wr.objLeistung}: ${error}`
                  );
                  wr.aktuelleLeistung = 0; // Use 0 as a default value
              }
          }    
      }
      
      /**
       * Diese Funktion gibt ein Array der maximalen Leistungen aller Wechselrichter zurück.
       */
      async function getMaximaleLeistungen() {
        return Object.values(wechselrichter).map(
          (wechselrichter) => wechselrichter.maxLeistung
        );
      }
      
      /**
       * Berechnet die Summe aller aktuellen Leistungen der Wechselrichter.
       */
      async function getAktuelleLeistungSumme() {
        let summe = 0;
        // Iteriere durch jedes Wechselrichter-Objekt
        for (const wr of Object.values(wechselrichter)) {
            summe = summe + wr.aktuelleLeistung;
        }
        return summe;
      };
      
      /**
       * Berechnet die Summe aller maxLeistung-Werte im Wechselrichter-Objekt.
       */
      async function getMaxLeistungSumme() {
        let summe = 0;
        // Iteriere durch jedes Wechselrichter-Objekt
        for (const wr of Object.values(wechselrichter)) {
            summe = summe + wr.maxLeistung;
        }
        return summe;
      };
      
      /**
       * Berechnet die Summe aller begrenzteLeistung-Werte im Wechselrichter-Objekt.
       */
      async function getMaxBegrenzungSumme() {
        let summe = 0;
        // Iteriere durch jedes Wechselrichter-Objekt
        for (const wr of Object.values(wechselrichter)) {
            summe = summe + wr.begrenzteLeistung;
        }
        return summe;
      };
      
      /**
       * Berechnet die maximale Leistung und setzt die Begrenzung der Wechselrichter.
       */
      async function setWechselrichterLeistungen() {
          const aktuelleLeistungen = await getAktuelleLeistungSumme();
          console.log(`Aktuelle Gesamtleistung der Wechselrichter: ${aktuelleLeistungen}`);
      
          const faktor = maxGesamtLeistung / aktuelleLeistungen;
          console.log(`Reduktionsfaktor der Wechselrichter: ${faktor}`);
      
          await Promise.all(
              Object.values(wechselrichter).map(async (wr) => {
                  let begrenzung = Math.floor(wr.aktuelleLeistung * faktor);
                  
                  // Begrenze die einzelnen Wechselrichter auf mindestens 50W
                  begrenzung = Math.max(begrenzung, 50);
                  
                  // Begrenze die einzelnen Wechselrichter auf maxGesamtLeistung
                  begrenzung = Math.min(begrenzung, maxGesamtLeistung);
                  
                  wr.begrenzteLeistung = begrenzung;
                  
                  await setStateAsync(wr.objBegrenzung, { val: wr.begrenzteLeistung, ack: false });
      
                  const prozentualeLeistung = (wr.begrenzteLeistung / wr.maxLeistung) * 100;
                  console.log(`${wr.name}: ${wr.begrenzteLeistung}W (${prozentualeLeistung.toFixed(2)}%)`);
              })
          );
      
          const begrenzteLeistungIst = await getMaxBegrenzungSumme();
          const begrenzteLeistungIstInProzent = Math.round((begrenzteLeistungIst / await getMaxLeistungSumme()) * 10000) / 100; // Runden auf 2 Nachkommastellen
          await Promise.all([
            setStateAsync(objBegrenzungIst, { val: begrenzteLeistungIst, ack: true }),
            setStateAsync(objBegrenzungIstProzent, { val: begrenzteLeistungIstInProzent, ack: true })
          ]);
          console.log(`Gesamtbegrenzung nach Anpassung: ${begrenzteLeistungIst}W, ${begrenzteLeistungIstInProzent}%, maxLeistungWR: ${maxGesamtLeistung}W`);
          
          //Batterieladung
          await loadBattery(aktuelleLeistungen);
      }
      
      async function loadBattery(aktuelleLeistungen) {
         if (batterie.laden) {
            const leistungHaus = (await getStateAsync(objLeistungHaus)).val;
            const ueberschuss = Math.max(aktuelleLeistungen - leistungHaus, 0);
            const ladeLeistung = Math.min(ueberschuss, batterie.maxLadeleistung);
        
            const ladeLeistungProzent = Math.round((ueberschuss / batterie.maxLadeleistung) * 10000) / 100; // Runden auf 2 Nachkommastellen
            const ladeLeistungVolt = Math.round(10 * (ladeLeistungProzent / 100) * 100) / 100; // Runden auf 2 Nachkommastellen
        
            switch (batterie.unit) {
              case "watt":
                await setStateAsync(batterie.objLadungWatt, { val: ladeLeistung, ack: false });
                break;
              case "percent":
                await setStateAsync(batterie.objLadungProzent, { val: ladeLeistungProzent, ack: false });
                break;
              case "volt":
                await setStateAsync(batterie.objLadungVolt, { val: ladeLeistungVolt, ack: false });
                break;
              default:
                console.warn(`Keine Einheit für die Batterieladung angegeben oder Einheit entspricht nicht 'watt', 'volt' oder 'percent'!`);
              
            };
            console.log(`Aktueller Überschuss: ${ueberschuss}, Ladeleistung: ${ladeLeistung}W, ${ladeLeistungProzent}%, ${ladeLeistungVolt}`);
          }
      }
      
      onReady();
      

      Edit 13.12.2023: Code Update

      Codierknecht Ralla66 2 Replies Last reply Reply Quote 0
      • Codierknecht
        Codierknecht Developer Most Active @Schmakus last edited by

        @schmakus
        Was mir sofort auffällt, ohne tief in das Script eingestiegen zu sein:
        Du definierst path, aber die einzelnen DP werden trotzdem absolut definiert.
        Könnte man beispielhaft auch so machen:

        const objLeistungHaus = `$(path).LeistungHaus`;
        

        Dann auch gleich oben definieren und konsequent verwenden.
        Dann muss man nur diese eine Konstante ändern, wenn man die DP woanders ablegen möchte.

        Schmakus 1 Reply Last reply Reply Quote 0
        • Ralla66
          Ralla66 Most Active @Schmakus last edited by

          @schmakus

          würde den Wirkungsgrad der WR mit einfließen lassen.

          Schmakus 1 Reply Last reply Reply Quote 0
          • Schmakus
            Schmakus Developer @Codierknecht last edited by

            @codierknecht sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

            @schmakus
            Was mir sofort auffällt, ohne tief in das Script eingestiegen zu sein:
            Du definierst path, aber die einzelnen DP werden trotzdem absolut definiert.
            Könnte man beispielhaft auch so machen:

            const objLeistungHaus = `$(path).LeistungHaus`;
            

            Dann auch gleich oben definieren und konsequent verwenden.
            Dann muss man nur diese eine Konstante ändern, wenn man die DP woanders ablegen möchte.

            Hi, schon geändert. Hat jedoch nur einen Datenpunkt betroffen. Die anderen DPs sind meine Test-Datenpunkte und müssen durch die richtigen Datenpunkte der Wechselrichter, usw. ersetzt werden.

            1 Reply Last reply Reply Quote 0
            • Schmakus
              Schmakus Developer @Ralla66 last edited by

              @ralla66 sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

              @schmakus

              würde den Wirkungsgrad der WR mit einfließen lassen.

              Kannst du mir das näher erklären?

              Ralla66 1 Reply Last reply Reply Quote 0
              • Ralla66
                Ralla66 Most Active @Schmakus last edited by Ralla66

                @schmakus

                Beispiel: du hast 2 WR a 1600 Watt
                Begrenzung ist 1500 Watt.
                Fahrweise 1 -> 2 WR a 750 Watt betreiben, schlechter Wirkungsgrad
                oder
                Fahrweise 2 -> 1 WR aus, der andere wird mit 1500 Watt betrieben.

                Schmakus 1 Reply Last reply Reply Quote 0
                • Schmakus
                  Schmakus Developer @Ralla66 last edited by

                  @ralla66 Hi, verstehe ich nicht. Liegt aber vermutlich an meinen noch nicht existierenden Knowhow. 🙈
                  Welche Rolle spielt es, wenn in Summe die Leistung kommt, welche benötigt wird, bzw auf die begrenzt wird?

                  Ralla66 1 Reply Last reply Reply Quote 0
                  • Ralla66
                    Ralla66 Most Active @Schmakus last edited by Ralla66

                    @schmakus sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

                    wenn in Summe die Leistung kommt

                    bezogen auf die eingespeiste Strom Menge aber weniger.
                    100 Watt -> 92 % Wirkungsgrad macht 92 Watt zum Verbrauch
                    100 Watt -> 70 % Wirkungsgrad macht 72 Watt zum Verbrauch

                    Schmakus 1 Reply Last reply Reply Quote 0
                    • Schmakus
                      Schmakus Developer @Ralla66 last edited by

                      @ralla66 sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

                      @schmakus sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

                      wenn in Summe die Leistung kommt

                      bezogen auf die eingespeiste Strom Menge aber weniger.
                      100 Watt -> 92 % Wirkungsgrad macht 92 Watt zum Verbrauch
                      100 Watt -> 70 % Wirkungsgrad macht 72 Watt zum Verbrauch

                      Ok, stehe immer noch etwas auf dem Schlauch.
                      Bedeutet das, die Begrenzung der WR bezieht sich nicht auf die AC-Leistung, sondern DC-Leistung?

                      Ralla66 1 Reply Last reply Reply Quote 0
                      • Ralla66
                        Ralla66 Most Active @Schmakus last edited by

                        @schmakus

                        das hat nichts mit der Begrenzung zu tun, sondern mit reingesteckter Energie zu gewandelter nutzbarer Energie.
                        Verluste die der WR beim Wandeln selbst verbraucht.

                        Schmakus 1 Reply Last reply Reply Quote 0
                        • Schmakus
                          Schmakus Developer @Ralla66 last edited by

                          @ralla66 sagte in [Vorlage] Hoymiles Wechselrichter Begrenzung mit openDTU:

                          @schmakus

                          das hat nichts mit der Begrenzung zu tun, sondern mit reingesteckter Energie zu gewandelter nutzbarer Energie.
                          Verluste die der WR beim Wandeln selbst verbraucht.

                          Verstehe. Es wäre jedoch eh besser, auf die tatsächliche Einspeisung zu begrenzen.

                          Ralla66 1 Reply Last reply Reply Quote 0
                          • Ralla66
                            Ralla66 Most Active @Schmakus last edited by

                            @schmakus

                            Genau, begrenzen auf den aktuellen Verbrauch, Rest in den Speicher. 🙂

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

                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            961
                            Online

                            31.9k
                            Users

                            80.2k
                            Topics

                            1.3m
                            Posts

                            3
                            12
                            1402
                            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