Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. Skript läuft plötzlich nicht mehr

    NEWS

    • Monatsrückblick – September 2025

    • Neues Video "KI im Smart Home" - ioBroker plus n8n

    • Neues Video über Aliase, virtuelle Geräte und Kategorien

    Skript läuft plötzlich nicht mehr

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

      @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

      ich habe ein Javascript geschrieben das mir die aktuelle Leistung von zwei BKWs von Shelly Adaptern abruft (1 x pro Sekunde) und dann die Stromerzeugung pro Tag usw. berechnet und auch noch die Summer über die BKWs errechnet.

      • Warum machst du diesen Unsinn mit dem 1s heartbeat, wenn die Shellies ihre Werte wohl eher nicht in dieser frequenz geändert werden ?
      • bist du sicher das sich die Heartbeats nicht 'aufstauen', so das die vielen einzelnen 'write' events in die DB das ganze blockieren ?
      • Warum holst du den 'letzten' wert jedesmal neu, anstelle diesen in einer lokalen Variablen zu speichern, damit du nicht extra zugriffe auf die DB hast ?
      • Warum speicherst du die Werte auf die du triggerst nicht in lokale variablen, und holst die dann im Skript immer wieder neu ?

      Insgesamt glaube ich das die Abläufe sich über die Zeit aufstauen, so das das Skript wegen mangelnder Reentranz von Funktionen nicht mehr stabil läuft.

      Du solltest Deinen Ansatz mal grundsätzlich überdenken. Wozu brauchst du jede Sekunde jeden der berechneten Werte ?

      A.
      p.s. Das Skript mag keine 'syntaktischen' Fehler haben - danach habe ich nicht geschaut. Die verwendete Logik kann aber auf jeden Fall eine Optimierung vertragen - und eine Begrenzung auf 'sinnvolle' Datenmengen.

      Homoran 1 Reply Last reply Reply Quote 1
      • Homoran
        Homoran Global Moderator Administrators @Asgothian last edited by

        @asgothian sagte in Skript läuft plötzlich nicht mehr:

        Warum machst du diesen Unsinn mit dem 1s heartbeat, wenn die Shellies ihre Werte wohl eher nicht in dieser frequenz geändert werden ?

        @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

        Das Skript ist in Zusammenarbeit mit mir und ChatGPT entstanden. Ich denke in der heutigen Zeit eine Herangehensweise die man durchaus machen kann.

        Asgothian 1 Reply Last reply Reply Quote 0
        • Asgothian
          Asgothian Developer @Homoran last edited by

          @homoran sagte in Skript läuft plötzlich nicht mehr:

          @asgothian sagte in Skript läuft plötzlich nicht mehr:

          Warum machst du diesen Unsinn mit dem 1s heartbeat, wenn die Shellies ihre Werte wohl eher nicht in dieser frequenz geändert werden ?

          @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

          Das Skript ist in Zusammenarbeit mit mir und ChatGPT entstanden. Ich denke in der heutigen Zeit eine Herangehensweise die man durchaus machen kann.

          ich denke da ist ChatGPT unschuldig 🙂 Das war fast sicher vorgegeben.

          Homoran 1 Reply Last reply Reply Quote 0
          • Homoran
            Homoran Global Moderator Administrators @Asgothian last edited by Homoran

            @asgothian sagte in Skript läuft plötzlich nicht mehr:

            Das war fast sicher vorgegeben.

            gehe ich auch von aus.
            Aber KI tut nur was man sagt, und das muss ausreichend wohlüberlegt sein.

            Eine Korrektur in "bessere Programmierung" findet eben nicht statt

            Der Aufwand der KI gut strukturierte, sinnvolle Anweisungen zu geben, ist der selbe, den man für die eigene Programmierung benötigt.
            Dann kan man auch den letzten Schritt noch selber machen.

            Wenn man, wie ich, kein js beherrsct, macht man es eben mit Blockly

            Asgothian 1 Reply Last reply Reply Quote 0
            • T
              ticaki Developer last edited by

              Im Skript gibt’s keinen 1 Sekunden schedule, außer ich hab mich gestern verzählt 5 Felder sind Minuten 6 Sekunden… oder?

              Asgothian 1 Reply Last reply Reply Quote 0
              • Asgothian
                Asgothian Developer @ticaki last edited by

                @ticaki sagte in Skript läuft plötzlich nicht mehr:

                Im Skript gibt’s keinen 1 Sekunden schedule, außer ich hab mich gestern verzählt 5 Felder sind Minuten 6 Sekunden… oder?

                Denkbar, ich bin nicht vom Code im Skript ausgegangen, sondern von dieser Aussage :

                @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

                ich habe ein Javascript geschrieben das mir die aktuelle Leistung von zwei BKWs von Shelly Adaptern abruft (1 x pro Sekunde) und dann die Stromerzeugung pro Tag usw. berechnet und auch noch die Summer über die BKWs errechnet.

                1 Reply Last reply Reply Quote 0
                • Asgothian
                  Asgothian Developer @Homoran last edited by

                  @homoran sagte in Skript läuft plötzlich nicht mehr:

                  Aber KI tut nur was man sagt, und das muss ausreichend wohlüberlegt sein.
                  Eine Korrektur in "bessere Programmierung" findet eben nicht statt
                  Der Aufwand der KI gut strukturierte, sinnvolle Anweisungen zu geben, ist der selbe, den man für die eigene Programmierung benötigt.
                  Dann kan man auch den letzten Schritt noch selber machen.
                  Wenn man, wie ich, kein js beherrsct, macht man es eben mit Blockly

                  Dem würde ich so nicht zu 100% zustimmen. Es ist für mich ok wenn man KI dafür benutzt einen Algorithmus in ausführbaren Code zu giessen.

                  Das Problem sehe ich eher im Algorithmus hinter dem Skript, und der Idee hinter dem Algorithmus.

                  1 Reply Last reply Reply Quote 1
                  • Asgothian
                    Asgothian Developer @hotspot_2 last edited by Asgothian

                    @hotspot_2 Hier stand was falsches - ich hatte eine Klammer uebersehen.

                    • Du hast einen heartbeat pro programmiertem Device, an Statt eines Heartbeat welcher beide programmierten Devices behandelt
                    • du hast pro device einen Heartbeat jede Minute, und einen 2. jede 2. Minute, Anstatt einen Heratbeat zu nutzen, der die Funktion des 2 Minuten ablaufs jedes 2. mal ausführt.
                    • Du hast im 2. Watchdog eine re-Init Funktionalität, die letztendlich keinen Sinn macht. Warum ? du versuchst dinge neu zu initialisieren die aber nicht Ursache des ausbleiben eines Events sind. Wenn sich der Ausgangs-DP zu lange nicht ändert (>1 minute) kommt kein Event, und es wird ein re-init angestossen. Dieser dupliziert alle Shedules, ohne zu prüfen ob diese noch existieren.

                    Unterm Strich ist das Skript so eher unbrauchbar. Beschreib doch mal die Basis auf der das ganze beruht - dann kann da ein Vorschlag gemacht werden wie das sauber umgesetzt werden sollte.

                    A.

                    H 1 Reply Last reply Reply Quote 0
                    • H
                      hotspot_2 @Asgothian last edited by

                      @asgothian Alles klar, vielen vielen Dank für eure Hinweise! Ich finde das super wie gut das hier funktioniert das mal ganz am Rande ;-).

                      Ich habe jetzt mal meine Methode etwas abgeändert. Ich erstelle gerade mit ChatGPT ein Skript was mal auf MQTT Push umstellt und testet wie oft werden die Werte denn aktualisiert. Ist das erfolgreich dann würde ich das Skript mal dahingehend umstellen nur noch auf Änderungen der Werte zu reagieren. Auch die anderen und zahlreichen Hinweise von euch werde ich mal einfließen lassen.

                      Ist es mal ok das ich das mal weiter verfolge und euch dann den Entwurf mal präsentiere. In dem Zug würde ich dann auch meine Idee den Ansatz mal aufzeigen.

                      arteck 1 Reply Last reply Reply Quote 0
                      • arteck
                        arteck Developer Most Active @hotspot_2 last edited by arteck

                        @hotspot_2 wie währe es mit einer einfachen LOG ausgabe.. was durchlaufen wurde..

                        H 1 Reply Last reply Reply Quote 0
                        • H
                          hotspot_2 @arteck last edited by

                          @arteck Wie meinst Du das konkret?

                          arteck 1 Reply Last reply Reply Quote 0
                          • arteck
                            arteck Developer Most Active @hotspot_2 last edited by

                            @hotspot_2 siehste das ist der unterschied zwichen einem der Programmiert und programmieren lässt..

                            in jeder function halt eine console.log('ist durchlaufen ') .. so siehst du wo der hängen bleibt.

                            H 1 Reply Last reply Reply Quote 0
                            • H
                              hotspot_2 @arteck last edited by

                              So, ich habe jetzt mal etwas optimiert. Das MQTT Push Thema ist sehr interessant! Das hatte ich bisher so nicht auf dem Schirm. Das eröffnet auch Möglichkeiten mit manchen Dingen ganz anders umzugehen als bisher (Node-Red MQTT abfragen, in Objekte schreiben und dann mit den Objekten arbeiten so bin ich gerade eher unterwegs. Auch mehr mit Blockly und Node Red). Aber Javascript hat mein Interesse geweckt und da ich schon mal Turbo Pascal und Delphi programmiert habe ich etwas Grundwissen Programmierung. Will mich mit ChatGPT Unterstützung da auf jeden Fall weiter einarbeiten.

                              Hier mal das optimierte Script, wer nochmal drüberschauen möchte und kann ist gerne eingeladen.

                              1// ===============================================
                              // BKW_Runtime (no-create version)
                              // - Legt KEINE States an
                              // - Schreibt NUR in bestehende States (IDs konfigurierbar)
                              // - Watchdog/Heartbeat nur per Log (keine Meta-States)
                              // ===============================================
                              
                              // --------------- CONFIG -----------------
                              const CONFIG = {
                                DEVICES: [
                                  {
                                    name: 'bkw1',
                                    // Eingangswerte (müssen existieren)
                                    POWER: '0_userdata.0.shellies.sonstiges.bkw1.apower',        // W (aktuelle Leistung)
                                    TOTAL: '0_userdata.0.shellies.sonstiges.bkw1.aenergy_total', // Wh (kumulativ)
                              
                                    // Basis-Pfad für Ziel-/Interimswerte (müssen existieren!)
                                    BASE:  '0_userdata.0.pvundstrom.bkws.1',
                                  },
                                  {
                                    name: 'bkw2',
                                    POWER: '0_userdata.0.shellies.sonstiges.bkw2.apower',
                                    TOTAL: '0_userdata.0.shellies.sonstiges.bkw2.aenergy_total',
                                    BASE:  '0_userdata.0.pvundstrom.bkws.2',
                                  }
                                ],
                              
                                // Aggregat-Zielpfad (muss existieren!)
                                AGG_BASE: '0_userdata.0.pvundstrom.bkws.all',
                              
                                // Watchdog: Re-Init wenn x Minuten keine Events
                                WATCHDOG_IDLE_MIN: 1,
                              };
                              // ------------- END CONFIG ---------------
                              
                              
                              // ---- State-Builder pro Device (nur IDs, keine Anlage) ----
                              function S(dev){
                                const b = dev.BASE;
                                return {
                                  // Eingänge:
                                  self_w:        `${b}.wr_selfconsumption_w`,
                              
                                  // Outputs:
                                  power_w:       `${b}.power_w`,
                                  power_net_w:   `${b}.power_net_w`,
                                  producing:     `${b}.producing`,
                              
                                  dt_wh:         `${b}.energy_today_net_wh`,
                                  mt_wh:         `${b}.energy_month_net_wh`,
                                  yt_wh:         `${b}.energy_year_net_wh`,
                                  dt_kwh:        `${b}.energy_today_net_kwh`,
                                  mt_kwh:        `${b}.energy_month_net_kwh`,
                                  yt_kwh:        `${b}.energy_year_net_kwh`,
                                  lf_wh:         `${b}.energy_lifetime_net_wh`,
                                  lf_kwh:        `${b}.energy_lifetime_net_kwh`,
                              
                                  // interne Marker (müssen existieren!):
                                  int_last_total:`${b}.int_total_wh_last`,     // letzter TOTAL (Wh)
                                  int_net_eff:   `${b}.int_neteffective_wh`,   // effektiv eingespeiste Wh (nur wenn ap>self)
                                  int_bd:        `${b}.int_baseline_day_net_wh`,
                                  int_bm:        `${b}.int_baseline_month_net_wh`,
                                  int_by:        `${b}.int_baseline_year_net_wh`,
                                };
                              }
                              
                              // ---- Helpers ----
                              const n = (v, fb=0) => Number.isFinite(Number(v)) ? Number(v) : fb;
                              const toKWh = (wh) => Math.round((wh/1000)*1000)/1000;
                              function val(id){ const s = getState(id); return s ? Number(s.val)||0 : 0; }
                              
                              // ---- Logging / Watchdog (OHNE States) ----
                              let ERRCOUNT = 0;
                              let lastEvent = Date.now();
                              const WD_MAX_IDLE_MS = CONFIG.WATCHDOG_IDLE_MIN * 60 * 1000;
                              
                              function iso(ts=Date.now()){ return new Date(ts).toISOString(); }
                              async function safe(label, fn){
                                try { return await fn(); }
                                catch(e){
                                  ERRCOUNT++;
                                  log(`[BKW] ${label} FAILED: ${e && e.message ? e.message : e}`, 'warn');
                                }
                              }
                              async function touchEvent(){ lastEvent = Date.now(); }
                              schedule('*/1 * * * *', () => log(`[BKW] heartbeat ${iso()}`, 'debug'));
                              schedule('*/2 * * * *', async () => {
                                const idle = Date.now() - lastEvent;
                                if (idle > WD_MAX_IDLE_MS) {
                                  log(`[BKW] Watchdog: idle ${Math.round(idle/1000)}s → re-init listeners`, 'warn');
                                  for (const d of CONFIG.DEVICES) await safe(`reinit.${d.name}`, async () => initDevice(d));
                                  await safe('updateAggregates.watchdog', updateAggregates);
                                  lastEvent = Date.now();
                                }
                              });
                              
                              // ---- Kernlogik ----
                              async function updateProducingFlags(dev, apNow){
                                const s = S(dev);
                                const ap = apNow != null ? apNow : n((await getStateAsync(dev.POWER))?.val, 0);
                                const selfW = n((await getStateAsync(s.self_w))?.val, 0);
                                const producing = ap > selfW;
                              
                                await setStateAsync(s.power_w, ap, true);
                                await setStateAsync(s.power_net_w, Math.max(0, ap - selfW), true);
                                await setStateAsync(s.producing, producing, true);
                              }
                              
                              async function writeNet(dev){
                                const s = S(dev);
                                const netEff = n((await getStateAsync(s.int_net_eff))?.val, 0);
                                const bd = n((await getStateAsync(s.int_bd))?.val, 0);
                                const bm = n((await getStateAsync(s.int_bm))?.val, 0);
                                const by = n((await getStateAsync(s.int_by))?.val, 0);
                              
                                const d = Math.max(0, netEff - bd);
                                const m = Math.max(0, netEff - bm);
                                const y = Math.max(0, netEff - by);
                              
                                await setStateAsync(s.dt_wh, d, true);
                                await setStateAsync(s.mt_wh, m, true);
                                await setStateAsync(s.yt_wh, y, true);
                                await setStateAsync(s.dt_kwh, toKWh(d), true);
                                await setStateAsync(s.mt_kwh, toKWh(m), true);
                                await setStateAsync(s.yt_kwh, toKWh(y), true);
                                await setStateAsync(s.lf_wh,  netEff, true);
                                await setStateAsync(s.lf_kwh, toKWh(netEff), true);
                              }
                              
                              async function initDevice(dev){
                                const s = S(dev);
                              
                                // Initiale Flags
                                await safe(`init.updateProducingFlags.${dev.name}`, async () => updateProducingFlags(dev));
                              
                                // Merker laden
                                const totalNow = n((await getStateAsync(dev.TOTAL))?.val, 0);
                                const lastInit = n((await getStateAsync(s.int_last_total))?.val, NaN);
                                if (!Number.isFinite(lastInit)) {
                                  // NICHT anlegen – vorausgesetzt, der State existiert
                                  await setStateAsync(s.int_last_total, totalNow, true);
                                }
                              
                                const netEffInit = n((await getStateAsync(s.int_net_eff))?.val, NaN);
                                if (!Number.isFinite(netEffInit)) {
                                  await setStateAsync(s.int_net_eff, 0, true);
                                }
                              
                                const netEff = n((await getStateAsync(s.int_net_eff))?.val, 0);
                                if (!Number.isFinite(n((await getStateAsync(s.int_bd))?.val, NaN))) await setStateAsync(s.int_bd, netEff, true);
                                if (!Number.isFinite(n((await getStateAsync(s.int_bm))?.val, NaN))) await setStateAsync(s.int_bm, netEff, true);
                                if (!Number.isFinite(n((await getStateAsync(s.int_by))?.val, NaN))) await setStateAsync(s.int_by, netEff, true);
                              
                                await safe(`init.writeNet.${dev.name}`, async () => writeNet(dev));
                              
                                // Listener neu registrieren (auch bei Re-Init)
                                on({ id: dev.POWER, change: 'ne' }, async obj => {
                                  await touchEvent();
                                  await safe(`POWER:${dev.name}`, async () => {
                                    await updateProducingFlags(dev, n(obj.state.val, 0));
                                  });
                                });
                              
                                on({ id: dev.TOTAL, change: 'ne' }, async obj => {
                                  await touchEvent();
                                  await safe(`TOTAL:${dev.name}`, async () => {
                                    const total = n(obj.state.val, 0);
                                    const last  = n((await getStateAsync(s.int_last_total))?.val, 0);
                              
                                    // Robust gegen Reset: wenn TOTAL kleiner als last → Basis neu setzen, KEIN Delta
                                    if (total < last) {
                                      await setStateAsync(s.int_last_total, total, true);
                                    } else {
                                      const delta = total - last;
                                      await setStateAsync(s.int_last_total, total, true);
                              
                                      const ap = n((await getStateAsync(dev.POWER))?.val, 0);
                                      const selfW = n((await getStateAsync(s.self_w))?.val, 0);
                                      if (ap > selfW && delta > 0) {
                                        const netEffNew = n((await getStateAsync(s.int_net_eff))?.val, 0) + delta;
                                        await setStateAsync(s.int_net_eff, netEffNew, true);
                                        await writeNet(dev);
                                      }
                              
                                      await updateProducingFlags(dev, ap);
                                      await updateAggregates();
                                    }
                                  });
                                });
                              
                                on({ id: s.self_w, change: 'ne' }, async () => {
                                  await touchEvent();
                                  await safe(`SELF_W:${dev.name}`, async () => updateProducingFlags(dev));
                                });
                              }
                              
                              // Baselines (Mitternacht/Monat/Jahr) – schreiben nur in bestehende States
                              async function baselineDay(dev){
                                const s=S(dev);
                                const v=n((await getStateAsync(s.int_net_eff))?.val,0);
                                await setStateAsync(s.int_bd, v, true);
                                await writeNet(dev);
                              }
                              async function baselineMonth(dev){
                                const s=S(dev);
                                const v=n((await getStateAsync(s.int_net_eff))?.val,0);
                                await setStateAsync(s.int_bm, v, true);
                                await writeNet(dev);
                              }
                              async function baselineYear(dev){
                                const s=S(dev);
                                const v=n((await getStateAsync(s.int_net_eff))?.val,0);
                                await setStateAsync(s.int_by, v, true);
                                await writeNet(dev);
                              }
                              
                              // Aggregat
                              async function updateAggregates(){
                                const AGG = CONFIG.AGG_BASE;
                                let pRaw=0, pNet=0, d=0, m=0, y=0, lf=0;
                                for (const dev of CONFIG.DEVICES) {
                                  const s = S(dev);
                                  pRaw += val(s.power_w);
                                  pNet += val(s.power_net_w);
                                  d    += val(s.dt_wh);
                                  m    += val(s.mt_wh);
                                  y    += val(s.yt_wh);
                                  lf   += val(s.lf_wh);
                                }
                                await setStateAsync(`${AGG}.power_w`, pRaw, true);
                                await setStateAsync(`${AGG}.power_net_w`, pNet, true);
                                await setStateAsync(`${AGG}.producing`, pNet > 0, true);
                                await setStateAsync(`${AGG}.energy_today_net_wh`, d, true);
                                await setStateAsync(`${AGG}.energy_month_net_wh`, m, true);
                                await setStateAsync(`${AGG}.energy_year_net_wh`,  y, true);
                                await setStateAsync(`${AGG}.energy_today_net_kwh`, toKWh(d), true);
                                await setStateAsync(`${AGG}.energy_month_net_kwh`, toKWh(m), true);
                                await setStateAsync(`${AGG}.energy_year_net_kwh`,  toKWh(y), true);
                                await setStateAsync(`${AGG}.energy_lifetime_net_wh`,  lf, true);
                                await setStateAsync(`${AGG}.energy_lifetime_net_kwh`, toKWh(lf), true);
                              }
                              
                              // ===== Start + Zeitpläne =====
                              (async () => {
                                // Init Geräte & Listener
                                for (const d of CONFIG.DEVICES) await safe(`initDevice.${d.name}`, async () => initDevice(d));
                              
                                // Baselines
                                schedule('0 0 * * *',      async () => { for (const d of CONFIG.DEVICES) await safe(`baselineDay.${d.name}`,   async () => baselineDay(d));   });
                                schedule('0 0 1 * *',      async () => { for (const d of CONFIG.DEVICES) await safe(`baselineMonth.${d.name}`, async () => baselineMonth(d)); });
                                schedule('0 0 1 1 *',      async () => { for (const d of CONFIG.DEVICES) await safe(`baselineYear.${d.name}`,  async () => baselineYear(d));  });
                              
                                // Aggregat zyklisch zusätzlich
                                schedule('*/1 * * * *', async () => safe('updateAggregates.cron', updateAggregates));
                              
                                log('[BKW] Script started (no-create mode).', 'info');
                              })();
                              
                              Asgothian 1 Reply Last reply Reply Quote 0
                              • Asgothian
                                Asgothian Developer @hotspot_2 last edited by

                                @hotspot_2 Was ist da optimiert ? Ich sehe keine Unterschiede zum oben geposteten skript.

                                Hast du das alte Skript gepostet, oder war die Optimierung eher extern vom Skript ?

                                H 1 Reply Last reply Reply Quote 0
                                • H
                                  hotspot_2 @Asgothian last edited by

                                  @asgothian Ok. Ich habe jetzt nochmal von vorne gestartet und reagiere jetzt auf MQTT Push bei Änderungen von den Leistungswerten und schreibe nur das mal in Objekte. Leistung BKW1, Leistung BKW2 und Gesamtleistung.

                                  Jetzt schau ich mir mal an wie stabil das läuft und dann gehe ich weiter um die Tages-, Monats- und Jahresleistung zu berechnen.

                                  // ===============================================
                                  // BKW Live Power (MQTT JSON parse, no-create, sync)
                                  // - Liest MQTT-JSON aus status.switch:0 (Shelly Plus Plug S)
                                  // - Netto-Leistung je BKW = max(0, apower - wr_selfconsumption_w)
                                  // - Gesamtleistung = Summe der Netto-Leistungen
                                  // - Legt KEINE States an (schreibt nur in vorhandene Objekte)
                                  // - Nutzt getState/setState (ressourcenschonend)
                                  // - Schreibt nur bei echter Änderung (mit Toleranz) + bündelt Aggregat
                                  // ===============================================
                                  
                                  // ---------- KONSTANTEN: HIER ANPASSEN ----------
                                  const MQTT_JSON_BKW1 = 'mqtt.0.shellies.sonstiges.bkw1.status.switch:0';
                                  const MQTT_JSON_BKW2 = 'mqtt.0.shellies.sonstiges.bkw2.status.switch:0';
                                  
                                  // Eigenverbrauch (W) je BKW (Objekte existieren bereits; sonst wird nur gewarnt)
                                  const SELF_BKW1      = '0_userdata.0.pvundstrom.bkws.1.wr_selfconsumption_w';
                                  const SELF_BKW2      = '0_userdata.0.pvundstrom.bkws.2.wr_selfconsumption_w';
                                  
                                  // Ziel-States (müssen existieren; number, role=value.power, unit=W)
                                  const OUT_PWR_BKW1   = '0_userdata.0.pvundstrom.bkws.1.power_w';
                                  const OUT_PWR_BKW2   = '0_userdata.0.pvundstrom.bkws.2.power_w';
                                  const OUT_PWR_ALL    = '0_userdata.0.pvundstrom.bkws.all.power_w';
                                  
                                  // Toleranz & Aggregat-Entprellung
                                  const EPS_W = 1;              // nur schreiben, wenn Änderung > 1 W
                                  const AGG_DEBOUNCE_MS = 300;  // bündelt schnelle Mehrfachänderungen
                                  
                                  // ---------- interner Aufbau ----------
                                  const DEVICES = [
                                    { name: 'bkw1', inJsonId: MQTT_JSON_BKW1, selfId: SELF_BKW1, outId: OUT_PWR_BKW1 },
                                    { name: 'bkw2', inJsonId: MQTT_JSON_BKW2, selfId: SELF_BKW2, outId: OUT_PWR_BKW2 },
                                  ];
                                  
                                  // ---------- Helpers ----------
                                  const n = (v, fb=0) => Number.isFinite(Number(v)) ? Number(v) : fb;
                                  
                                  const _existCache = new Map();
                                  function objExists(id) {
                                    if (_existCache.has(id)) return _existCache.get(id);
                                    const ok = !!getObject(id);
                                    _existCache.set(id, ok);
                                    if (!ok) log(`[BKW] Objekt existiert nicht: ${id}`, 'warn');
                                    return ok;
                                  }
                                  
                                  // schreibt nur, wenn Ziel existiert UND sich der Wert (mit EPS) geändert hat
                                  function setChangedNoCreate(id, nextVal, eps = 0, ack = true) {
                                    if (!objExists(id)) return; // KEINE Anlage
                                    const cur = getState(id);
                                    const curVal = cur ? cur.val : undefined;
                                  
                                    let same = false;
                                    if (typeof nextVal === 'number') {
                                      same = Number.isFinite(Number(curVal)) && Math.abs(Number(curVal) - Number(nextVal)) <= eps;
                                    } else {
                                      same = curVal === nextVal;
                                    }
                                    if (same) return;
                                  
                                    setState(id, nextVal, ack);
                                  }
                                  
                                  // robustes JSON-Parsing für status.switch:0 → apower (W)
                                  function parseApowerFromState(stateObj) {
                                    if (!stateObj || typeof stateObj.val !== 'string') return 0;
                                    try {
                                      const json = JSON.parse(stateObj.val);
                                      const ap = Number(json?.apower);
                                      return Number.isFinite(ap) ? ap : 0;
                                    } catch (e) {
                                      const sample = typeof stateObj.val === 'string' ? stateObj.val.slice(0, 120) : '<non-string>';
                                      log(`[BKW] JSON parse failed (${sample}): ${e.message}`, 'warn');
                                      return 0;
                                    }
                                  }
                                  
                                  // Netto-Leistung: max(0, apower - self)
                                  function computeNetPower(dev) {
                                    const sJson = getState(dev.inJsonId);
                                    const sSelf = getState(dev.selfId);
                                    const ap    = parseApowerFromState(sJson);
                                    const self  = n(sSelf?.val, 0);
                                    const net   = Math.max(0, ap - self);
                                    return { ap, self, net };
                                  }
                                  
                                  // ---------- Aggregat ----------
                                  let aggTimer = null;
                                  function scheduleAgg() {
                                    if (aggTimer) return;
                                    aggTimer = setTimeout(() => {
                                      aggTimer = null;
                                      try {
                                        let sum = 0;
                                        for (const d of DEVICES) {
                                          if (!objExists(d.outId)) continue;
                                          const s = getState(d.outId);
                                          sum += s ? n(s.val, 0) : 0;
                                        }
                                        setChangedNoCreate(OUT_PWR_ALL, sum, EPS_W, true);
                                      } catch (e) {
                                        log(`[BKW] update aggregate failed: ${e && e.message ? e.message : e}`, 'warn');
                                      }
                                    }, AGG_DEBOUNCE_MS);
                                  }
                                  
                                  // ---------- Start ----------
                                  (() => {
                                    try {
                                      // Existenz der benutzten IDs einmalig prüfen (ohne Anlegen)
                                      for (const d of DEVICES) {
                                        objExists(d.inJsonId);
                                        objExists(d.selfId);
                                        objExists(d.outId);
                                      }
                                      objExists(OUT_PWR_ALL);
                                  
                                      // Initiale Übernahme (rein aus ioBroker-States, kein Gerät-Poll)
                                      for (const d of DEVICES) {
                                        if (!objExists(d.inJsonId) || !objExists(d.outId)) continue;
                                        if (!objExists(d.selfId)) log(`[BKW] Hinweis: Eigenverbrauchs-Objekt fehlt für ${d.name} → wird als 0 W behandelt`, 'warn');
                                  
                                        const { net } = computeNetPower(d);
                                        setChangedNoCreate(d.outId, net, EPS_W, true);
                                      }
                                      scheduleAgg();
                                  
                                      // Event-Listener: auf Änderungen am JSON ODER am Eigenverbrauch reagieren
                                      for (const d of DEVICES) {
                                        // MQTT JSON (status.switch:0)
                                        if (objExists(d.inJsonId)) {
                                          on({ id: d.inJsonId, change: 'ne' }, (obj) => {
                                            try {
                                              const ap = parseApowerFromState(obj.state);
                                              const selfS = getState(d.selfId);
                                              const self = n(selfS?.val, 0);
                                              const net = Math.max(0, ap - self);
                                              setChangedNoCreate(d.outId, net, EPS_W, true);
                                              scheduleAgg();
                                            } catch (e) {
                                              log(`[BKW] onJSON ${d.name} failed: ${e && e.message ? e.message : e}`, 'warn');
                                            }
                                          });
                                        }
                                        // Eigenverbrauch
                                        if (objExists(d.selfId)) {
                                          on({ id: d.selfId, change: 'ne' }, () => {
                                            try {
                                              const { net } = computeNetPower(d);
                                              setChangedNoCreate(d.outId, net, EPS_W, true);
                                              scheduleAgg();
                                            } catch (e) {
                                              log(`[BKW] onSelf ${d.name} failed: ${e && e.message ? e.message : e}`, 'warn');
                                            }
                                          });
                                        }
                                      }
                                  
                                      log('[BKW] Live-Power Script gestartet (MQTT JSON, no-create, sync).', 'info');
                                    } catch (e) {
                                      log(`[BKW] init failed: ${e && e.message ? e.message : e}`, 'error');
                                    }
                                  })();
                                  
                                  arteck 1 Reply Last reply Reply Quote 0
                                  • arteck
                                    arteck Developer Most Active @hotspot_2 last edited by

                                    @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

                                    (() => {

                                    oder

                                    function S(dev){

                                    jetzt dich mit javascript auseinander und übernimm nicht blind irgendwelche Klamotten..

                                    ich hab zwat kein Plan was du in Delphi geschrieben hast aber es scheint nicht viel gewesen zu sein.. oder hast du etwa so units definiert

                                    uses 
                                      n, 
                                      b,
                                      u;
                                    

                                    versteh es nicht falsch das was du machst funktioniert und ist nutzbar aber nicht wartbar wenn ich das lese..

                                    H OliverIO 2 Replies Last reply Reply Quote 1
                                    • H
                                      hotspot_2 @arteck last edited by

                                      @arteck Ich verstehe Dich nicht falsch. Ich kann das komplett nachvollziehen was Du sagst.

                                      Ich "programmiere" gerade auf eine Art und Weise die zwar zum Ergebnis führt in einigen Fällen aber Wartbarkeit, Lesbarer Code und viele andere Aspekte die zum Programmieren gehören werden da nicht berücksichtigt. Es ist halt wirklich sehr zielorientiert, das ist aber nicht das Einzigste und das wird irgendwann zu Problem führen. Für ein paar Codeschnipsel für iobroker kann man das eventuell noch tolerieren aber wenn's größer wird wird das schwierig.

                                      Und nein, so hätte ich Units nicht definiert und das hat mir auch sofort klar gemacht was Du damit sagen möchtest. Danke dafür.

                                      Ich bleibe da am Ball, lese mich weiter ein und nutze den nicht ganz optimalen Code als Vehikel um weiter zu kommen.

                                      Danke für die Analyse das ich den Code zumindest einsetzen kann. Stabiler als vorher läuft er auf jeden Fall mal.

                                      T 1 Reply Last reply Reply Quote 0
                                      • T
                                        ticaki Developer @hotspot_2 last edited by

                                        @hotspot_2
                                        Du must dem chat bei GPT ein paar Regeln mit geben - vielleicht auch gleich in der Prompt

                                        • Nur Funktionen benutzen die existieren
                                        • von Menschen lesbaren Code erzeugen
                                        • in der Kürze liegt die Würze
                                        • englische JSDocs hinzufügen
                                        • deaktivierbare Logausgaben zum debuggen einfügen
                                        • kommentare nur auf englisch

                                        ok ich weiß nicht allles- ich hab meinen so oft "an gemeckert", das da ne menge regeln irgendwo gespeichert sind.

                                        Wenn ich so einen Code bekommen würde wäre mein Kommentar - Was soll den das sein? Buchstabensalat? Bist du unfähig - Nochmal und dieses mal anständig!

                                        Wenn man einen genervten ärgerlichen Eindruck macht, werden die ergebnisse meist besser - 🤣

                                        H 1 Reply Last reply Reply Quote 0
                                        • H
                                          hotspot_2 @ticaki last edited by

                                          @ticaki Danke für die Tipps. Das werde ich testen und auch hier mal berichten wie dann der Code aussieht.

                                          Das ChatGPT sehr gut in der Lage ist sich Dinge zu merken hab ich auch schon gemerkt. Ich habe beispielsweise mal erklärt wie ich gerne Objekte in iobroker organisiere im Bereich userdata. Also welche Besamung, wann ich ein Unterordner anlege usw. Das brauche ich nun bei weiteren Javascript Programmierprojekten nicht mehr wiederholen. Das sitzt und alle Objekte werden so wie gewünscht benannt.

                                          Ich werde jetzt mal eine rauere Gangart pflegen und mal schauen wie dann die Ergebnisse aussehen ;-).

                                          1 Reply Last reply Reply Quote 0
                                          • OliverIO
                                            OliverIO @arteck last edited by

                                            @arteck sagte in Skript läuft plötzlich nicht mehr:

                                            @hotspot_2 sagte in Skript läuft plötzlich nicht mehr:

                                            (() => {

                                            Für den Browser ist das eigentlich gar nicht schlecht, für Node ist es unnötig.
                                            Primär macht man das um im Browser das window Objekt nicht unnötig voll zu machen, da alles innerhalb der Funktion in einem eigenen scope läuft.

                                            https://developer.mozilla.org/en-US/docs/Glossary/IIFE

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

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate

                                            960
                                            Online

                                            32.2k
                                            Users

                                            80.9k
                                            Topics

                                            1.3m
                                            Posts

                                            6
                                            28
                                            503
                                            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