Skip to content
  • Home
  • Recent
  • Tags
  • 0 Unread 0
  • Categories
  • Unreplied
  • Popular
  • 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

  • Default (No Skin)
  • No Skin
Collapse
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. ioBroker Allgemein
  4. PV Überwachung hoymiles

NEWS

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

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

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

PV Überwachung hoymiles

Scheduled Pinned Locked Moved ioBroker Allgemein
13 Posts 3 Posters 1.2k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Ralf 2

    @martinschm sagte in PV Überwachung hoymiles:

    Über eine openDTU ist die Anlage in iobroker eingebunden.

    Ich weiß nicht, was OpenDPU an weiteren Datenpunkten liefert, ggf. kann man hier auch noch irgendwelche Fehlerstatus auslesen und mit berücksichtigen. Aber dein Ansatz ist erst einmal gut und wohl richtig.

    M Offline
    M Offline
    martinschm
    wrote on last edited by
    #3

    @ralf-2 said in PV Überwachung hoymiles:

    @martinschm sagte in PV Überwachung hoymiles:

    Über eine openDTU ist die Anlage in iobroker eingebunden.

    Ich weiß nicht, was OpenDPU an weiteren Datenpunkten liefert, ggf. kann man hier auch noch irgendwelche Fehlerstatus auslesen und mit berücksichtigen. Aber dein Ansatz ist erst einmal gut und wohl richtig.

    Fehlerstatus wird aktuell leider nicht mitgeliefert. Hab ich schon ein Feature requests zu aufgemacht.

    R 1 Reply Last reply
    0
    • M martinschm

      @ralf-2 said in PV Überwachung hoymiles:

      @martinschm sagte in PV Überwachung hoymiles:

      Über eine openDTU ist die Anlage in iobroker eingebunden.

      Ich weiß nicht, was OpenDPU an weiteren Datenpunkten liefert, ggf. kann man hier auch noch irgendwelche Fehlerstatus auslesen und mit berücksichtigen. Aber dein Ansatz ist erst einmal gut und wohl richtig.

      Fehlerstatus wird aktuell leider nicht mitgeliefert. Hab ich schon ein Feature requests zu aufgemacht.

      R Offline
      R Offline
      Ralf 2
      wrote on last edited by
      #4

      @martinschm
      Wäre zwar schön aber bestimmt nicht zwingend nötig.
      Ich würde einfach die Erträge der einzelnen Module Module für einen Tag aufsummieren und dann bei Abweichung von x Prozent eine Meldung geben.
      Bedenke dabei, das vielleicht auch etwas ein Modul mal verschatten kann (Handwerkeraute, oder so etwas). Ich würde das einfach mal eine Woche ohne Alarm laufen lassen und dann den Grenzwert in Prozent daraus ableiten.
      Das bekommen wir schon als Teamarbeit hier im Forum hin. Daten solltest du mal im Vorfeld sammeln.

      Gruß Ralf

      M 1 Reply Last reply
      0
      • B Offline
        B Offline
        Beowolf
        wrote on last edited by
        #5

        Der Opendtu Adapter zeigt doch bei jedem WR die Datenpunkte "producing" und "last_update" aus. Den Datenpunkt "available" gibt es auch noch.

        Da ist doch alles vorhanden was man braucht.

        Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

        M 1 Reply Last reply
        0
        • B Beowolf

          Der Opendtu Adapter zeigt doch bei jedem WR die Datenpunkte "producing" und "last_update" aus. Den Datenpunkt "available" gibt es auch noch.

          Da ist doch alles vorhanden was man braucht.

          M Offline
          M Offline
          martinschm
          wrote on last edited by
          #6

          @beowolf said in PV Überwachung hoymiles:

          Der Opendtu Adapter zeigt doch bei jedem WR die Datenpunkte "producing" und "last_update" aus. Den Datenpunkt "available" gibt es auch noch.

          Da ist doch alles vorhanden was man braucht.

          Leider nicht ganz. producing bezieht sich halt nur auf einen WR, aber wenn mal ein Modul ausfällt bekommst du es so nicht mit.

          B 1 Reply Last reply
          0
          • R Ralf 2

            @martinschm
            Wäre zwar schön aber bestimmt nicht zwingend nötig.
            Ich würde einfach die Erträge der einzelnen Module Module für einen Tag aufsummieren und dann bei Abweichung von x Prozent eine Meldung geben.
            Bedenke dabei, das vielleicht auch etwas ein Modul mal verschatten kann (Handwerkeraute, oder so etwas). Ich würde das einfach mal eine Woche ohne Alarm laufen lassen und dann den Grenzwert in Prozent daraus ableiten.
            Das bekommen wir schon als Teamarbeit hier im Forum hin. Daten solltest du mal im Vorfeld sammeln.

            M Offline
            M Offline
            martinschm
            wrote on last edited by martinschm
            #7

            @ralf-2 said in PV Überwachung hoymiles:

            @martinschm
            Wäre zwar schön aber bestimmt nicht zwingend nötig.
            Ich würde einfach die Erträge der einzelnen Module Module für einen Tag aufsummieren und dann bei Abweichung von x Prozent eine Meldung geben.
            Bedenke dabei, das vielleicht auch etwas ein Modul mal verschatten kann (Handwerkeraute, oder so etwas). Ich würde das einfach mal eine Woche ohne Alarm laufen lassen und dann den Grenzwert in Prozent daraus ableiten.
            Das bekommen wir schon als Teamarbeit hier im Forum hin. Daten solltest du mal im Vorfeld sammeln.

            Ich hab mal mit perplexity.ai ein paar Runden gedreht und nutze aktuell dieses Skript

            const wrThreshold = 0.7;
            const moduleThreshold = 0.7;
            const minProduction = 5;
            const telegramInstance = 'telegram.0';
            const warnDelay = 15 * 60 * 1000; // 15 Minuten in ms
            
            // Gruppen-Konfiguration wie gehabt
            const groups = [
              {
                name: "Zaun",
                wrs: [
                  { id: "xx", name: "WR1", moduleCount: 6 },
                  { id: "xx", name: "WR2", moduleCount: 6 },
                  { id: "xx", name: "WR3", moduleCount: 6 }
                ]
              },
              {
                name: "Gartenhütte",
                wrs: [
                  { id: "xx", name: "WR4", moduleCount: 4 },
                  { id: "xx", name: "WR5", moduleCount: 4 }
                ]
              }
            ];
            
            // Statusspeicher
            if (!globalThis.wrStatus) globalThis.wrStatus = {};
            
            function checkWRs() {
                let now = Date.now();
            
                groups.forEach(group => {
                    let wrPowers = [];
                    let activeWRs = [];
            
                    // 1. Prüfe, welche WR produzieren
                    group.wrs.forEach((wr, i) => {
                        const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                        const isProducing = producingState === true || producingState === 'true';
                        if (isProducing) {
                            let wrPower = getState(`opendtu.0.${wr.id}.power_dc`).val;
                            wrPowers[i] = wrPower;
                            activeWRs.push({ index: i, ...wr, wrPower });
                        } else {
                            wrPowers[i] = 0;
                        }
                    });
            
                    // 2. WR-Vergleich (nur aktive WRs und erst nach 15 Minuten)
                    if (activeWRs.length > 1) {
                        let avgWR = activeWRs.reduce((sum, wr) => sum + wr.wrPower, 0) / activeWRs.length;
                        activeWRs.forEach(wr => {
                            let status = globalThis.wrStatus[wr.name] || { warnSince: null, warned: false };
                            if (wr.wrPower < avgWR * wrThreshold) {
                                if (!status.warnSince) status.warnSince = now;
                                if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `⚠️ *WR-Warnung (${group.name})*: ${wr.name} liefert seit 15 Minuten nur ${wr.wrPower} W (Durchschnitt: ${avgWR.toFixed(1)} W)`
                                    });
                                    status.warned = true;
                                }
                            } else {
                                if (status.warned) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `✅ *Entwarnung (${group.name})*: ${wr.name} liefert wieder ausreichend Leistung.`
                                    });
                                }
                                status.warnSince = null;
                                status.warned = false;
                            }
                            globalThis.wrStatus[wr.name] = status;
                        });
                    }
            
                    // 3. Modulvergleich je WR (nur bei aktiven WRs, erst nach 15 Minuten)
                    activeWRs.forEach(wr => {
                        let modulePowers = [];
                        for (let m = 1; m <= wr.moduleCount; m++) {
                            let modPower = getState(`opendtu.0.${wr.id}.dc.input_${m}.power`).val;
                            modulePowers[m - 1] = modPower;
                        }
                        let avgModule = modulePowers.reduce((a, b) => a + b, 0) / wr.moduleCount;
                        modulePowers.forEach((mp, idx) => {
                            let key = `${wr.name}_modul${idx+1}`;
                            let status = globalThis.wrStatus[key] || { warnSince: null, warned: false };
                            if (mp < avgModule * moduleThreshold) {
                                if (!status.warnSince) status.warnSince = now;
                                if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `⚠️ *Modul-Warnung (${wr.name})*: Modul ${idx + 1} liefert seit 15 Minuten nur ${mp} W (Durchschnitt: ${avgModule.toFixed(1)} W)`
                                    });
                                    status.warned = true;
                                }
                            } else {
                                if (status.warned) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `✅ *Entwarnung (${wr.name})*: Modul ${idx + 1} liefert wieder ausreichend Leistung.`
                                    });
                                }
                                status.warnSince = null;
                                status.warned = false;
                            }
                            globalThis.wrStatus[key] = status;
                        });
                    });
            
                    // 4. Überwachung nicht-produzierender WRs (wie gehabt, ggf. auch mit 15min-Verzögerung anpassen)
                    group.wrs.forEach((wr, i) => {
                        const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                        const isProducing = producingState === true || producingState === 'true';
                        let status = globalThis.wrStatus[wr.name + "_prod"] || { warnSince: null, warned: false };
                        if (!isProducing) {
                            let anyOtherProducing = group.wrs.some((otherWr, otherIdx) => {
                                if (otherIdx !== i) {
                                    const otherProducingState = getState(`opendtu.0.${otherWr.id}.producing`).val;
                                    return otherProducingState === true || otherProducingState === 'true';
                                }
                                return false;
                            });
                            if (anyOtherProducing) {
                                if (!status.warnSince) status.warnSince = now;
                                if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `🔴 *Ausfall (${group.name})*: ${wr.name} produziert seit 15 Minuten nichts, obwohl andere laufen!`
                                    });
                                    status.warned = true;
                                }
                            } else {
                                status.warnSince = null;
                                status.warned = false;
                            }
                        } else {
                            if (status.warned) {
                                sendTo(telegramInstance, 'send', {
                                    text: `✅ *Entwarnung (${group.name})*: ${wr.name} produziert wieder!`
                                });
                            }
                            status.warnSince = null;
                            status.warned = false;
                        }
                        globalThis.wrStatus[wr.name + "_prod"] = status;
                    });
                });
            }
            
            schedule('*/2 * * * *', checkWRs);
            
            

            Das ist die zweite Version, die erste hat zu viele Meldungen in den Morgen- und Abendstunden gebracht wenn einzelne Module kurz verschattet sind.

            Das Skript vergleicht die Module eines WRs miteinander und warnt wenn ein Module nach 15 min immer noch hinter den anderen herhinkt. Außerdem vergleicht es die WRs innerhalb von zwei Gruppen (wo die Module jeweils gleich ausgerichtet sind) miteinander.

            B 2 Replies Last reply
            0
            • M martinschm

              @beowolf said in PV Überwachung hoymiles:

              Der Opendtu Adapter zeigt doch bei jedem WR die Datenpunkte "producing" und "last_update" aus. Den Datenpunkt "available" gibt es auch noch.

              Da ist doch alles vorhanden was man braucht.

              Leider nicht ganz. producing bezieht sich halt nur auf einen WR, aber wenn mal ein Modul ausfällt bekommst du es so nicht mit.

              B Offline
              B Offline
              Beowolf
              wrote on last edited by Beowolf
              #8

              @martinschm

              Na ja, es sind ja auch die Werte von Spannung, Strom und Leistung pro Eingang da. Dann auch noch die Einstrahlung in %.

              Das sind doch genug Werte um daraus etwas zu machen.

              Ich werde dein Skript mal testen. Ist bestimmt interessant.

              Etwas mehr Beschreibung, was wo bei den Einstellung eingegeben werden muß ist bestimmt nicht schlecht.

              Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

              1 Reply Last reply
              0
              • M martinschm

                @ralf-2 said in PV Überwachung hoymiles:

                @martinschm
                Wäre zwar schön aber bestimmt nicht zwingend nötig.
                Ich würde einfach die Erträge der einzelnen Module Module für einen Tag aufsummieren und dann bei Abweichung von x Prozent eine Meldung geben.
                Bedenke dabei, das vielleicht auch etwas ein Modul mal verschatten kann (Handwerkeraute, oder so etwas). Ich würde das einfach mal eine Woche ohne Alarm laufen lassen und dann den Grenzwert in Prozent daraus ableiten.
                Das bekommen wir schon als Teamarbeit hier im Forum hin. Daten solltest du mal im Vorfeld sammeln.

                Ich hab mal mit perplexity.ai ein paar Runden gedreht und nutze aktuell dieses Skript

                const wrThreshold = 0.7;
                const moduleThreshold = 0.7;
                const minProduction = 5;
                const telegramInstance = 'telegram.0';
                const warnDelay = 15 * 60 * 1000; // 15 Minuten in ms
                
                // Gruppen-Konfiguration wie gehabt
                const groups = [
                  {
                    name: "Zaun",
                    wrs: [
                      { id: "xx", name: "WR1", moduleCount: 6 },
                      { id: "xx", name: "WR2", moduleCount: 6 },
                      { id: "xx", name: "WR3", moduleCount: 6 }
                    ]
                  },
                  {
                    name: "Gartenhütte",
                    wrs: [
                      { id: "xx", name: "WR4", moduleCount: 4 },
                      { id: "xx", name: "WR5", moduleCount: 4 }
                    ]
                  }
                ];
                
                // Statusspeicher
                if (!globalThis.wrStatus) globalThis.wrStatus = {};
                
                function checkWRs() {
                    let now = Date.now();
                
                    groups.forEach(group => {
                        let wrPowers = [];
                        let activeWRs = [];
                
                        // 1. Prüfe, welche WR produzieren
                        group.wrs.forEach((wr, i) => {
                            const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                            const isProducing = producingState === true || producingState === 'true';
                            if (isProducing) {
                                let wrPower = getState(`opendtu.0.${wr.id}.power_dc`).val;
                                wrPowers[i] = wrPower;
                                activeWRs.push({ index: i, ...wr, wrPower });
                            } else {
                                wrPowers[i] = 0;
                            }
                        });
                
                        // 2. WR-Vergleich (nur aktive WRs und erst nach 15 Minuten)
                        if (activeWRs.length > 1) {
                            let avgWR = activeWRs.reduce((sum, wr) => sum + wr.wrPower, 0) / activeWRs.length;
                            activeWRs.forEach(wr => {
                                let status = globalThis.wrStatus[wr.name] || { warnSince: null, warned: false };
                                if (wr.wrPower < avgWR * wrThreshold) {
                                    if (!status.warnSince) status.warnSince = now;
                                    if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                        sendTo(telegramInstance, 'send', {
                                            text: `⚠️ *WR-Warnung (${group.name})*: ${wr.name} liefert seit 15 Minuten nur ${wr.wrPower} W (Durchschnitt: ${avgWR.toFixed(1)} W)`
                                        });
                                        status.warned = true;
                                    }
                                } else {
                                    if (status.warned) {
                                        sendTo(telegramInstance, 'send', {
                                            text: `✅ *Entwarnung (${group.name})*: ${wr.name} liefert wieder ausreichend Leistung.`
                                        });
                                    }
                                    status.warnSince = null;
                                    status.warned = false;
                                }
                                globalThis.wrStatus[wr.name] = status;
                            });
                        }
                
                        // 3. Modulvergleich je WR (nur bei aktiven WRs, erst nach 15 Minuten)
                        activeWRs.forEach(wr => {
                            let modulePowers = [];
                            for (let m = 1; m <= wr.moduleCount; m++) {
                                let modPower = getState(`opendtu.0.${wr.id}.dc.input_${m}.power`).val;
                                modulePowers[m - 1] = modPower;
                            }
                            let avgModule = modulePowers.reduce((a, b) => a + b, 0) / wr.moduleCount;
                            modulePowers.forEach((mp, idx) => {
                                let key = `${wr.name}_modul${idx+1}`;
                                let status = globalThis.wrStatus[key] || { warnSince: null, warned: false };
                                if (mp < avgModule * moduleThreshold) {
                                    if (!status.warnSince) status.warnSince = now;
                                    if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                        sendTo(telegramInstance, 'send', {
                                            text: `⚠️ *Modul-Warnung (${wr.name})*: Modul ${idx + 1} liefert seit 15 Minuten nur ${mp} W (Durchschnitt: ${avgModule.toFixed(1)} W)`
                                        });
                                        status.warned = true;
                                    }
                                } else {
                                    if (status.warned) {
                                        sendTo(telegramInstance, 'send', {
                                            text: `✅ *Entwarnung (${wr.name})*: Modul ${idx + 1} liefert wieder ausreichend Leistung.`
                                        });
                                    }
                                    status.warnSince = null;
                                    status.warned = false;
                                }
                                globalThis.wrStatus[key] = status;
                            });
                        });
                
                        // 4. Überwachung nicht-produzierender WRs (wie gehabt, ggf. auch mit 15min-Verzögerung anpassen)
                        group.wrs.forEach((wr, i) => {
                            const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                            const isProducing = producingState === true || producingState === 'true';
                            let status = globalThis.wrStatus[wr.name + "_prod"] || { warnSince: null, warned: false };
                            if (!isProducing) {
                                let anyOtherProducing = group.wrs.some((otherWr, otherIdx) => {
                                    if (otherIdx !== i) {
                                        const otherProducingState = getState(`opendtu.0.${otherWr.id}.producing`).val;
                                        return otherProducingState === true || otherProducingState === 'true';
                                    }
                                    return false;
                                });
                                if (anyOtherProducing) {
                                    if (!status.warnSince) status.warnSince = now;
                                    if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                        sendTo(telegramInstance, 'send', {
                                            text: `🔴 *Ausfall (${group.name})*: ${wr.name} produziert seit 15 Minuten nichts, obwohl andere laufen!`
                                        });
                                        status.warned = true;
                                    }
                                } else {
                                    status.warnSince = null;
                                    status.warned = false;
                                }
                            } else {
                                if (status.warned) {
                                    sendTo(telegramInstance, 'send', {
                                        text: `✅ *Entwarnung (${group.name})*: ${wr.name} produziert wieder!`
                                    });
                                }
                                status.warnSince = null;
                                status.warned = false;
                            }
                            globalThis.wrStatus[wr.name + "_prod"] = status;
                        });
                    });
                }
                
                schedule('*/2 * * * *', checkWRs);
                
                

                Das ist die zweite Version, die erste hat zu viele Meldungen in den Morgen- und Abendstunden gebracht wenn einzelne Module kurz verschattet sind.

                Das Skript vergleicht die Module eines WRs miteinander und warnt wenn ein Module nach 15 min immer noch hinter den anderen herhinkt. Außerdem vergleicht es die WRs innerhalb von zwei Gruppen (wo die Module jeweils gleich ausgerichtet sind) miteinander.

                B Offline
                B Offline
                Beowolf
                wrote on last edited by
                #9

                @martinschm sagte in PV Überwachung hoymiles:

                nutze aktuell dieses Skript

                wr.jpg

                Wo kommen diese 78,2 W her? Wo wird das berechnet?

                Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

                M 1 Reply Last reply
                0
                • M martinschm

                  @ralf-2 said in PV Überwachung hoymiles:

                  @martinschm
                  Wäre zwar schön aber bestimmt nicht zwingend nötig.
                  Ich würde einfach die Erträge der einzelnen Module Module für einen Tag aufsummieren und dann bei Abweichung von x Prozent eine Meldung geben.
                  Bedenke dabei, das vielleicht auch etwas ein Modul mal verschatten kann (Handwerkeraute, oder so etwas). Ich würde das einfach mal eine Woche ohne Alarm laufen lassen und dann den Grenzwert in Prozent daraus ableiten.
                  Das bekommen wir schon als Teamarbeit hier im Forum hin. Daten solltest du mal im Vorfeld sammeln.

                  Ich hab mal mit perplexity.ai ein paar Runden gedreht und nutze aktuell dieses Skript

                  const wrThreshold = 0.7;
                  const moduleThreshold = 0.7;
                  const minProduction = 5;
                  const telegramInstance = 'telegram.0';
                  const warnDelay = 15 * 60 * 1000; // 15 Minuten in ms
                  
                  // Gruppen-Konfiguration wie gehabt
                  const groups = [
                    {
                      name: "Zaun",
                      wrs: [
                        { id: "xx", name: "WR1", moduleCount: 6 },
                        { id: "xx", name: "WR2", moduleCount: 6 },
                        { id: "xx", name: "WR3", moduleCount: 6 }
                      ]
                    },
                    {
                      name: "Gartenhütte",
                      wrs: [
                        { id: "xx", name: "WR4", moduleCount: 4 },
                        { id: "xx", name: "WR5", moduleCount: 4 }
                      ]
                    }
                  ];
                  
                  // Statusspeicher
                  if (!globalThis.wrStatus) globalThis.wrStatus = {};
                  
                  function checkWRs() {
                      let now = Date.now();
                  
                      groups.forEach(group => {
                          let wrPowers = [];
                          let activeWRs = [];
                  
                          // 1. Prüfe, welche WR produzieren
                          group.wrs.forEach((wr, i) => {
                              const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                              const isProducing = producingState === true || producingState === 'true';
                              if (isProducing) {
                                  let wrPower = getState(`opendtu.0.${wr.id}.power_dc`).val;
                                  wrPowers[i] = wrPower;
                                  activeWRs.push({ index: i, ...wr, wrPower });
                              } else {
                                  wrPowers[i] = 0;
                              }
                          });
                  
                          // 2. WR-Vergleich (nur aktive WRs und erst nach 15 Minuten)
                          if (activeWRs.length > 1) {
                              let avgWR = activeWRs.reduce((sum, wr) => sum + wr.wrPower, 0) / activeWRs.length;
                              activeWRs.forEach(wr => {
                                  let status = globalThis.wrStatus[wr.name] || { warnSince: null, warned: false };
                                  if (wr.wrPower < avgWR * wrThreshold) {
                                      if (!status.warnSince) status.warnSince = now;
                                      if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                          sendTo(telegramInstance, 'send', {
                                              text: `⚠️ *WR-Warnung (${group.name})*: ${wr.name} liefert seit 15 Minuten nur ${wr.wrPower} W (Durchschnitt: ${avgWR.toFixed(1)} W)`
                                          });
                                          status.warned = true;
                                      }
                                  } else {
                                      if (status.warned) {
                                          sendTo(telegramInstance, 'send', {
                                              text: `✅ *Entwarnung (${group.name})*: ${wr.name} liefert wieder ausreichend Leistung.`
                                          });
                                      }
                                      status.warnSince = null;
                                      status.warned = false;
                                  }
                                  globalThis.wrStatus[wr.name] = status;
                              });
                          }
                  
                          // 3. Modulvergleich je WR (nur bei aktiven WRs, erst nach 15 Minuten)
                          activeWRs.forEach(wr => {
                              let modulePowers = [];
                              for (let m = 1; m <= wr.moduleCount; m++) {
                                  let modPower = getState(`opendtu.0.${wr.id}.dc.input_${m}.power`).val;
                                  modulePowers[m - 1] = modPower;
                              }
                              let avgModule = modulePowers.reduce((a, b) => a + b, 0) / wr.moduleCount;
                              modulePowers.forEach((mp, idx) => {
                                  let key = `${wr.name}_modul${idx+1}`;
                                  let status = globalThis.wrStatus[key] || { warnSince: null, warned: false };
                                  if (mp < avgModule * moduleThreshold) {
                                      if (!status.warnSince) status.warnSince = now;
                                      if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                          sendTo(telegramInstance, 'send', {
                                              text: `⚠️ *Modul-Warnung (${wr.name})*: Modul ${idx + 1} liefert seit 15 Minuten nur ${mp} W (Durchschnitt: ${avgModule.toFixed(1)} W)`
                                          });
                                          status.warned = true;
                                      }
                                  } else {
                                      if (status.warned) {
                                          sendTo(telegramInstance, 'send', {
                                              text: `✅ *Entwarnung (${wr.name})*: Modul ${idx + 1} liefert wieder ausreichend Leistung.`
                                          });
                                      }
                                      status.warnSince = null;
                                      status.warned = false;
                                  }
                                  globalThis.wrStatus[key] = status;
                              });
                          });
                  
                          // 4. Überwachung nicht-produzierender WRs (wie gehabt, ggf. auch mit 15min-Verzögerung anpassen)
                          group.wrs.forEach((wr, i) => {
                              const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                              const isProducing = producingState === true || producingState === 'true';
                              let status = globalThis.wrStatus[wr.name + "_prod"] || { warnSince: null, warned: false };
                              if (!isProducing) {
                                  let anyOtherProducing = group.wrs.some((otherWr, otherIdx) => {
                                      if (otherIdx !== i) {
                                          const otherProducingState = getState(`opendtu.0.${otherWr.id}.producing`).val;
                                          return otherProducingState === true || otherProducingState === 'true';
                                      }
                                      return false;
                                  });
                                  if (anyOtherProducing) {
                                      if (!status.warnSince) status.warnSince = now;
                                      if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                          sendTo(telegramInstance, 'send', {
                                              text: `🔴 *Ausfall (${group.name})*: ${wr.name} produziert seit 15 Minuten nichts, obwohl andere laufen!`
                                          });
                                          status.warned = true;
                                      }
                                  } else {
                                      status.warnSince = null;
                                      status.warned = false;
                                  }
                              } else {
                                  if (status.warned) {
                                      sendTo(telegramInstance, 'send', {
                                          text: `✅ *Entwarnung (${group.name})*: ${wr.name} produziert wieder!`
                                      });
                                  }
                                  status.warnSince = null;
                                  status.warned = false;
                              }
                              globalThis.wrStatus[wr.name + "_prod"] = status;
                          });
                      });
                  }
                  
                  schedule('*/2 * * * *', checkWRs);
                  
                  

                  Das ist die zweite Version, die erste hat zu viele Meldungen in den Morgen- und Abendstunden gebracht wenn einzelne Module kurz verschattet sind.

                  Das Skript vergleicht die Module eines WRs miteinander und warnt wenn ein Module nach 15 min immer noch hinter den anderen herhinkt. Außerdem vergleicht es die WRs innerhalb von zwei Gruppen (wo die Module jeweils gleich ausgerichtet sind) miteinander.

                  B Offline
                  B Offline
                  Beowolf
                  wrote on last edited by
                  #10

                  @martinschm
                  Noch eine Frage.

                  Warum baust du die Konstante "minProduction = 5" ein, die dann später nicht verwendet wird?

                  Ist da noch etwas geplant?

                  Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

                  M 1 Reply Last reply
                  0
                  • B Beowolf

                    @martinschm
                    Noch eine Frage.

                    Warum baust du die Konstante "minProduction = 5" ein, die dann später nicht verwendet wird?

                    Ist da noch etwas geplant?

                    M Offline
                    M Offline
                    martinschm
                    wrote on last edited by
                    #11

                    @beowolf said in PV Überwachung hoymiles:

                    @martinschm
                    Noch eine Frage.

                    Warum baust du die Konstante "minProduction = 5" ein, die dann später nicht verwendet wird?

                    Ist da noch etwas geplant?

                    Hi, nein das ist ein Überbleibsel aus der ersten Version.

                    1 Reply Last reply
                    0
                    • B Beowolf

                      @martinschm sagte in PV Überwachung hoymiles:

                      nutze aktuell dieses Skript

                      wr.jpg

                      Wo kommen diese 78,2 W her? Wo wird das berechnet?

                      M Offline
                      M Offline
                      martinschm
                      wrote on last edited by
                      #12

                      @beowolf said in PV Überwachung hoymiles:

                      @martinschm sagte in PV Überwachung hoymiles:

                      nutze aktuell dieses Skript

                      wr.jpg

                      Wo kommen diese 78,2 W her? Wo wird das berechnet?

                      Hi, ja wird berechnet aus den Werten der anderen Module.

                      1 Reply Last reply
                      0
                      • B Offline
                        B Offline
                        Beowolf
                        wrote on last edited by Beowolf
                        #13

                        Ich habedas Skript mal etwas "erweitert".

                        Das legt jetzt Datenpunkte unter "userdata" an. Die Daten können dann weiter in einer VIS verwendet werden.

                        const wrThreshold = 0.7;
                        const moduleThreshold = 0.7;
                        const minProduction = 5;
                        const pushoverInstance = 'pushover.0';
                        const warnDelay = 15 * 60 * 1000;
                        
                        const groups = [
                          {
                            name: "Solaranlage",
                            wrs: [
                              { id: "114***********", name: "WR1_HM-1000", moduleCount: 2 },
                              { id: "114***********", name: "WR2_HM-1000", moduleCount: 2 },
                              { id: "114***********", name: "WR3_HM-1000", moduleCount: 2 }
                            ]
                          }
                        ];
                        
                        if (!globalThis.wrStatus) globalThis.wrStatus = {};
                        
                        function sendPushoverMessage(message) {
                          sendTo(pushoverInstance, 'send', {
                            message,
                            title: 'Wechselrichter-Überwachung',
                            priority: 0
                          });
                        }
                        
                        function checkWRs() {
                          let now = Date.now();
                        
                          groups.forEach(group => {
                            let wrPowers = [];
                            let activeWRs = [];
                        
                            group.wrs.forEach((wr, i) => {
                              const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                              const isProducing = producingState === true || producingState === 'true';
                              const wrPower = isProducing ? getState(`opendtu.0.${wr.id}.power_dc`).val : 0;
                              wrPowers[i] = wrPower;
                        
                              if (isProducing) {
                                activeWRs.push({ index: i, ...wr, wrPower });
                              }
                        
                              // Schreibe Status in 0_userdata
                              const statusText = isProducing
                                ? (wrPower >= minProduction ? "✅ OK" : "⚠️ Schwache Produktion")
                                : "❌ Keine Produktion";
                              setState(`0_userdata.0.WR_Status.${wr.name}.Status`, { val: statusText, ack: true });
                            });
                        
                            if (activeWRs.length > 1) {
                              let avgWR = activeWRs.reduce((sum, wr) => sum + wr.wrPower, 0) / activeWRs.length;
                        
                              activeWRs.forEach(wr => {
                                let status = globalThis.wrStatus[wr.name] || { warnSince: null, warned: false };
                        
                                if (wr.wrPower < avgWR * wrThreshold) {
                                  if (!status.warnSince) status.warnSince = now;
                                  if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendPushoverMessage(`⚠️ WR-Warnung (${group.name}): ${wr.name} liefert seit 15 Minuten nur ${wr.wrPower} W (Durchschnitt: ${avgWR.toFixed(1)} W)`);
                                    status.warned = true;
                                  }
                                } else {
                                  if (status.warned) {
                                    sendPushoverMessage(`✅ Entwarnung (${group.name}): ${wr.name} liefert wieder ausreichend Leistung.`);
                                  }
                                  status.warnSince = null;
                                  status.warned = false;
                                }
                        
                                globalThis.wrStatus[wr.name] = status;
                              });
                            }
                        
                            activeWRs.forEach(wr => {
                              let modulePowers = [];
                              for (let m = 1; m <= wr.moduleCount; m++) {
                                let modPower = getState(`opendtu.0.${wr.id}.dc.input_${m}.power`).val;
                                modulePowers[m - 1] = modPower;
                              }
                        
                              let avgModule = modulePowers.reduce((a, b) => a + b, 0) / wr.moduleCount;
                        
                              modulePowers.forEach((mp, idx) => {
                                const modKey = `${wr.name}_modul${idx + 1}`;
                                let status = globalThis.wrStatus[modKey] || { warnSince: null, warned: false };
                        
                                // Modulstatus schreiben
                                const modStatus = mp > 0 ? "✅ OK" : "❌ Kein Ertrag";
                                setState(`0_userdata.0.WR_Status.${wr.name}.Modul${idx + 1}`, { val: modStatus, ack: true });
                        
                                if (mp < avgModule * moduleThreshold) {
                                  if (!status.warnSince) status.warnSince = now;
                                  if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendPushoverMessage(`⚠️ Modul-Warnung (${wr.name}): Modul ${idx + 1} liefert seit 15 Minuten nur ${mp} W (Durchschnitt: ${avgModule.toFixed(1)} W)`);
                                    status.warned = true;
                                  }
                                } else {
                                  if (status.warned) {
                                    sendPushoverMessage(`✅ Entwarnung (${wr.name}): Modul ${idx + 1} liefert wieder ausreichend Leistung.`);
                                  }
                                  status.warnSince = null;
                                  status.warned = false;
                                }
                        
                                globalThis.wrStatus[modKey] = status;
                              });
                            });
                        
                            group.wrs.forEach((wr, i) => {
                              const producingState = getState(`opendtu.0.${wr.id}.producing`).val;
                              const isProducing = producingState === true || producingState === 'true';
                        
                              let status = globalThis.wrStatus[wr.name + "_prod"] || { warnSince: null, warned: false };
                        
                              if (!isProducing) {
                                let anyOtherProducing = group.wrs.some((otherWr, idx) => {
                                  if (idx !== i) {
                                    const otherState = getState(`opendtu.0.${otherWr.id}.producing`).val;
                                    return otherState === true || otherState === 'true';
                                  }
                                  return false;
                                });
                        
                                if (anyOtherProducing) {
                                  if (!status.warnSince) status.warnSince = now;
                                  if (!status.warned && (now - status.warnSince) >= warnDelay) {
                                    sendPushoverMessage(`🔴 Ausfall (${group.name}): ${wr.name} produziert seit 15 Minuten nichts, obwohl andere laufen!`);
                                    status.warned = true;
                                  }
                                } else {
                                  status.warnSince = null;
                                  status.warned = false;
                                }
                              } else {
                                if (status.warned) {
                                  sendPushoverMessage(`✅ Entwarnung (${group.name}): ${wr.name} produziert wieder!`);
                                }
                                status.warnSince = null;
                                status.warned = false;
                              }
                        
                              globalThis.wrStatus[wr.name + "_prod"] = status;
                            });
                          });
                        }
                        
                        schedule('*/2 * * * *', checkWRs);
                        

                        Die Natur braucht nicht unseren Schutz, sie braucht unsere Abwesenheit.

                        1 Reply Last reply
                        0

                        Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                        Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                        With your input, this post could be even better 💗

                        Register Login
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        Support us

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

                        542

                        Online

                        32.7k

                        Users

                        82.6k

                        Topics

                        1.3m

                        Posts
                        Community
                        Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                        ioBroker Community 2014-2025
                        logo
                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Home
                        • Recent
                        • Tags
                        • Unread 0
                        • Categories
                        • Unreplied
                        • Popular
                        • GitHub
                        • Docu
                        • Hilfe