Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Entwicklung
    4. [Neuer Adapter] Senec Home Adapter

    NEWS

    • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?

    • Monatsrückblick – September 2025

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

    [Neuer Adapter] Senec Home Adapter

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

      Hallo,
      ich habe mal eine Frage bezüglich des Projekts an sich. Läuft das noch oder wurde das jetzt auf Eis gelegt?

      Leider hört es sich teils so an, das SENEC vielleicht den API-Zugang sperren könnte. Für mich zumindest kein gutes Zeichen, wenn dieser Zugang beim V4 gänzlich weggelassen wurde.
      Ich habe ebenso jetzt eine manuelle Zählung eingerichtet, welche aber auf die Zuverlässigkeit und Beständigkeit von SENEC aufbaut.

      Hat sich jemand schon einmal darüber Gedanken gemacht, den Enfluri direkt anzuzapfen? Das heißt als read only (sniffer)? Welche Daten werden darüber genau geliefert?

      Mit diesem Gedanken spiele ich schon länger und es würde unabhängiger von SENECs Laune laufen. Ich verstehe den Sicherheitsgedanken seitens SENEC und den damit verbundenen Onlinezwang. Aber bei jedem Update kann Schluss mit der API sein.
      Ich mag die Unabhängigkeit und mein persönliches Hausdashboard. Ebenso läuft meine PV-Überschussbeladung meiner Wallbox mit Daten von SENEC. Ich habe es zwar auf das Nötigste reduziert (Einspeisung und Bezug über Wattwächter). Aber Hausverbrauch an sich wäre noch nett.

      O 1 Reply Last reply Reply Quote 1
      • O
        oxident @ToniTL last edited by

        @tonitl Das wäre schon recht hilfreich und wichtig. Auch für die, die mit den NPU-Abstürzen zu kämpfen haben.

        Ich glaube, der Bus wird sogar am Senec selber durchgeschliffen, oder?

        B 1 Reply Last reply Reply Quote 1
        • B
          Blockmove @oxident last edited by

          @oxident said in [Neuer Adapter] Senec Home Adapter:

          @tonitl Das wäre schon recht hilfreich und wichtig. Auch für die, die mit den NPU-Abstürzen zu kämpfen haben.

          Ich glaube, der Bus wird sogar am Senec selber durchgeschliffen, oder?

          Mit sowas sollte es funktionieren:
          RS485-Sniffer

          Seit dem ich mich vom Senec-Adapter verabschiedet hab und die Abfrage nur noch über curl mache, hab ich keinerlei NPU-Abstürze mehr gehabt.
          Die Kommunikationsfehler sind auch sehr viel weniger geworden. Ich hol mir halt nur noch die Daten, die ich wirklich brauche.

          T 1 Reply Last reply Reply Quote 0
          • T
            ToniTL @Blockmove last edited by

            @blockmove läuft bei dir das Setup schon über den enfluri oder rufst du die Daten über curl vom senec selbst ab?

            Solltest du es schon über den enfluri betreiben, könntest du mitteilen wie du es angestellt hast? Schritt für Schritt Anleitung?

            B 1 Reply Last reply Reply Quote 0
            • B
              Blockmove @ToniTL last edited by

              @tonitl said in [Neuer Adapter] Senec Home Adapter:

              @blockmove läuft bei dir das Setup schon über den enfluri oder rufst du die Daten über curl vom senec selbst ab?

              Solltest du es schon über den enfluri betreiben, könntest du mitteilen wie du es angestellt hast? Schritt für Schritt Anleitung?

              Ich ruf über curl die Daten vom Senec ab.
              Es kommt vereinzelt zu Fehlermeldungen, aber die Kommunikation fängt sich immer wieder.
              Seitdem keinerlei Probleme mehr mit der Steuerung meines Heizstabes und meiner 2 go-e Wallboxen.

              Ich muss allerdings auch sagen, dass ich das nun alles über Node RED mache und nicht mehr über ioBroker.
              Aber das ist ein anderes Thema. Der curl-Aufruf wird in ioBroker genauso funktionieren.

              1 Reply Last reply Reply Quote 0
              • M
                musicnrw last edited by

                Ich habe gerade festgestellt, dass es im Javasript Warnungen gibt, weiß aber nicht, in wieweit die kritisch sind.
                Und zwar im Gridpower-Script:
                javascript.0 20:17:16.511 warn at Object.<anonymous> (script.js.common.Senec.GridPower:123:9)
                javascript.0 20:17:16.512 warn at Object.<anonymous> (script.js.common.Senec.GridPower:124:9)

                im Hausverbrauch Script:
                javascript.0 20:18:16.667 warn at Object.<anonymous> (script.js.common.Senec.Hausverbrauch:111:5)
                javascript.0 20:18:16.668 warn at Object.<anonymous> (script.js.common.Senec.Hausverbrauch:112:5)

                und im Akku Be- und Entladung Script
                javascript.0 20:19:20.174 warn at Object.<anonymous> (script.js.common.Senec.AkkuBeEntladung:114:9)
                javascript.0 20:19:20.175 warn at Object.<anonymous> (script.js.common.Senec.AkkuBeEntladung:115:9)

                Alle Warnungen wiederholen sich alle 10 Sekunden im Debug-Fenster.
                Kann mir da jemand etwas zu sagen? Ich habe die Scripte nach der Anleitung von icebear bei mir im ioBroker angelegt.

                Danke und Gruß
                Thomas

                icebear 1 Reply Last reply Reply Quote 0
                • icebear
                  icebear @musicnrw last edited by

                  @musicnrw

                  Ich benutze diese Scripte nicht mehr, weil ich die in einem Script zusammengefasst habe.

                  Hier das Script welches ich jetzt verwende, du mußt dort halt die Datenpunkte evtl. auf deine Gegebenheiten anpassen. Beim ersten Start sollten vom Script alle erforderlichen Datenpunkte, wenn sie nicht vorhanden sind, erstellt werden.

                  Wichtig!!! Das ist ein TypeScript. Also beim erstellen nicht JS nehmen sondern ganz rechts TS

                  Kannst ja mal schauen.

                  // -----------------------------------------------------------------------------------
                  // 1. KONFIGURATION
                  // -----------------------------------------------------------------------------------
                  
                  // Basis-Pfad für eigene Datenpunkte (muss in ioBroker unter 0_userdata.0.Energie.Senec. konsolidiert werden)
                  const BASE_DP_PATH = '0_userdata.0.Energie.Senec';
                  
                  // Senec Quell-Datenpunkte (Leistung in Watt)
                  // WICHTIG: Prüfen, ob die IDs in Ihrer Installation korrekt sind!
                  const PowerSourceIds = {
                      // Skript 1: Negativ = Einspeisung, Positiv = Netzbezug
                      GRID_POWER: "senec.0.ENERGY.GUI_GRID_POW",
                      // Skript 2: Hausverbrauch (immer positiv)
                      HOUSE_CONSUMPTION_POWER: "senec.0.ENERGY.GUI_HOUSE_POW",
                      // Skript 3: Positiv = Laden (In), Negativ = Entladen (Out)
                      BAT_POWER: "senec.0.ENERGY.GUI_BAT_DATA_POWER",
                      // Skript 4: PV-Produktion (immer positiv)
                      PV_POWER: "senec.0.ENERGY.GUI_INVERTER_POWER",
                  };
                  
                  // Ziel-Datenpunkte (Tagesenergie in Wh und kWh)
                  const TargetStateIds = {
                      // Skript 1
                      DAILY_FEED_IN_WH: `${BASE_DP_PATH}.Tages_Einspeisung_Wh`,
                      DAILY_FEED_IN_KWH: `${BASE_DP_PATH}.Tages_Einspeisung_kWh`,
                      DAILY_GRID_PURCHASE_WH: `${BASE_DP_PATH}.Tages_Netzbezug_Wh`,
                      DAILY_GRID_PURCHASE_KWH: `${BASE_DP_PATH}.Tages_Netzbezug_kWh`,
                  
                      // Skript 2
                      DAILY_HOUSE_CONSUMPTION_WH: `${BASE_DP_PATH}.Tages_Hausverbrauch_Wh`,
                      DAILY_HOUSE_CONSUMPTION_KWH: `${BASE_DP_PATH}.Tages_Hausverbrauch_kWh`,
                  
                      // Skript 3 (Bat_Out = Entladen, Bat_In = Laden)
                      DAILY_BAT_OUT_WH: `${BASE_DP_PATH}.Bat_Out_Wh`,
                      DAILY_BAT_OUT_KWH: `${BASE_DP_PATH}.Bat_Out_kWh`,
                      DAILY_BAT_IN_WH: `${BASE_DP_PATH}.Bat_In_Wh`,
                      DAILY_BAT_IN_KWH: `${BASE_DP_PATH}.Bat_In_kWh`,
                  
                      // Skript 4 (Zusätzliche PV- und Bilanz-Werte)
                      DAILY_PV_WH: `${BASE_DP_PATH}.Tageswerte.pv_wh`,
                      DAILY_PV_KWH: `${BASE_DP_PATH}.Tageswerte.pv_kwh`,
                      DAILY_BILANZ_KWH: `${BASE_DP_PATH}.Tageswerte.bilanz_kwh`,
                      DAILY_GRID_WH_S4: `${BASE_DP_PATH}.Tageswerte.netz_wh`, // Duplikat von DAILY_GRID_PURCHASE_WH
                      DAILY_FEED_IN_WH_S4: `${BASE_DP_PATH}.Tageswerte.einspeisung_wh`, // Duplikat von DAILY_FEED_IN_WH
                  };
                  
                  // -----------------------------------------------------------------------------------
                  // 2. TYPEN, GLOBALE VARIABLEN UND HILFSFUNKTIONEN
                  // -----------------------------------------------------------------------------------
                  
                  // Typsichere Definition der globalen Variablen für die Integration
                  // Der Schlüssel ist die PowerSourceId, der Wert speichert den letzten Zustand.
                  interface LastState {
                      lastPower: number;
                      lastTime: number; // Zeitstempel in Millisekunden
                  }
                  
                  // Speichert den letzten Zustand für jede Quelle separat
                  const lastStates: { [key: string]: LastState } = {};
                  
                  // Typsichere Definition für die Erstellung der States
                  interface CommonStateOptions {
                      name: string;
                      type: "number";
                      read: boolean;
                      write: boolean;
                      role: string;
                      unit: "Wh" | "kWh";
                      desc?: string;
                  }
                  
                  // Definiert alle zu erstellenden Datenpunkte
                  const stateDefinitions: { id: string; initialValue: number; common: CommonStateOptions }[] = [
                      // Skript 1
                      { id: TargetStateIds.DAILY_FEED_IN_WH, initialValue: 0, common: { name: 'Tägliche Einspeisung (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_FEED_IN_KWH, initialValue: 0, common: { name: 'Tägliche Einspeisung (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' } },
                      { id: TargetStateIds.DAILY_GRID_PURCHASE_WH, initialValue: 0, common: { name: 'Täglicher Netzbezug (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_GRID_PURCHASE_KWH, initialValue: 0, common: { name: 'Täglicher Netzbezug (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' } },
                  
                      // Skript 2
                      { id: TargetStateIds.DAILY_HOUSE_CONSUMPTION_WH, initialValue: 0, common: { name: 'Täglicher Hausverbrauch (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh', desc: 'Summierter Hausverbrauch für den aktuellen Tag in Wattstunden' } },
                      { id: TargetStateIds.DAILY_HOUSE_CONSUMPTION_KWH, initialValue: 0, common: { name: 'Täglicher Hausverbrauch (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh', desc: 'Summierter Hausverbrauch für den aktuellen Tag in Kilowattstunden' } },
                  
                      // Skript 3
                      { id: TargetStateIds.DAILY_BAT_OUT_WH, initialValue: 0, common: { name: 'Daily BatOut (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_BAT_OUT_KWH, initialValue: 0, common: { name: 'Daily BatOut (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' } },
                      { id: TargetStateIds.DAILY_BAT_IN_WH, initialValue: 0, common: { name: 'Daily BatIn (Wh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_BAT_IN_KWH, initialValue: 0, common: { name: 'Daily BatIn (kWh)', type: 'number', read: true, write: false, role: 'value.power.consumption', unit: 'kWh' } },
                      
                      // Skript 4
                      { id: TargetStateIds.DAILY_PV_WH, initialValue: 0, common: { name: 'Tageswert PV in Wh', type: 'number', read: true, write: false, role: 'value.power', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_PV_KWH, initialValue: 0, common: { name: 'Tageswert PV in kWh', type: 'number', read: true, write: false, role: 'value.power', unit: 'kWh' } },
                      { id: TargetStateIds.DAILY_BILANZ_KWH, initialValue: 0, common: { name: 'Bilanz kWh (PV - Netzbezug)', type: 'number', read: true, write: false, role: 'value.power', unit: 'kWh' } },
                      // Die folgenden sind Duplikate aus Skript 4, die wir beibehalten, um Skript 4 vollständig abzubilden
                      { id: TargetStateIds.DAILY_GRID_WH_S4, initialValue: 0, common: { name: 'Tages-Wh Netzbezug (S4)', type: 'number', read: true, write: false, role: 'value.power', unit: 'Wh' } },
                      { id: TargetStateIds.DAILY_FEED_IN_WH_S4, initialValue: 0, common: { name: 'Tages-Wh Einspeisung (S4)', type: 'number', read: true, write: false, role: 'value.power', unit: 'Wh' } }
                  ];
                  
                  /**
                   * Erstellt einen Datenpunkt, falls er noch nicht existiert.
                   * @param id ID des zu erstellenden States.
                   * @param initialValue Initialer Wert.
                   * @param common Common-Objekt Definition.
                   */
                  function createStateIfNotExists(id: string, initialValue: number, common: CommonStateOptions): void {
                      if (!existsState(id)) {
                          createState(id, initialValue, common, (err) => {
                              if (err) {
                                  log(`Fehler beim Erstellen des Datenpunkts ${id}: ${err}`, 'error');
                              } else {
                                  log(`Datenpunkt ${id} erfolgreich erstellt.`, 'info');
                              }
                          });
                      }
                  }
                  
                  /**
                   * Liest den Wert eines States sicher und gibt 0 zurück, falls ungültig.
                   * @param id ID des States.
                   * @returns Der Wert als Zahl oder 0.
                   */
                  async function getStateSafeAsync(id: string): Promise<number> {
                      const state = await getStateAsync(id);
                      if (state && typeof state.val === 'number') {
                          return state.val;
                      }
                      // Float-Parsing für den Fall, dass der Wert als String gespeichert wurde (trotz Type 'number')
                      if (state && state.val !== null && state.val !== undefined) {
                          const parsed = parseFloat(state.val.toString());
                          return isNaN(parsed) ? 0 : parsed;
                      }
                      return 0;
                  }
                  
                  /**
                   * Setzt einen Wert in Wh und berechnet und setzt automatisch den zugehörigen kWh-Wert.
                   * @param whId ID des Wh-Datenpunkts.
                   * @param kwhId ID des kWh-Datenpunkts.
                   * @param whValue Wert in Wh.
                   */
                  function setEnergyStates(whId: string, kwhId: string, whValue: number): void {
                      // Wh als echte Zahl speichern (mit 2 Nachkommastellen runden, um Rundungsfehler zu minimieren, aber als NUMBER)
                      // Wir verwenden Math.round, um Rundungsfehler zu kontrollieren, bevor wir die Zahl speichern.
                      const roundedWh = Math.round(whValue * 100) / 100; 
                      setState(whId, roundedWh, true); // **HIER: Übergabe einer Zahl (roundedWh)**
                  
                      // kWh auf 3 Nachkommastellen formatieren (als String)
                      const kwhString = (roundedWh / 1000).toFixed(3);
                      setState(kwhId, +kwhString, true); // **KORREKTUR: Verwende +kwhString**
                  }
                  
                  // -----------------------------------------------------------------------------------
                  // 3. INITIALISIERUNG UND HAUPTLOGIK (INTEGRATION)
                  // -----------------------------------------------------------------------------------
                  
                  /**
                   * Erstellt alle benötigten Datenpunkte und initialisiert die globalen Last-State-Variablen.
                   */
                  async function initializeScript(): Promise<void> {
                      log("Starte Initialisierung des Energie-Bilanz-Skripts.");
                  
                      // Erstellen des Basisordners, falls nicht vorhanden (für Skript 4 relevant)
                      if (!existsObject(`${BASE_DP_PATH}.Tageswerte`)) {
                          createState(`${BASE_DP_PATH}.Tageswerte`, 'Ordner für zusätzliche Energie-Tagesdatenpunkte', (err) => {
                              if (err) log(`Fehler beim Erstellen des Ordners: ${err}`, 'error');
                              else log(`Ordner ${BASE_DP_PATH}.Tageswerte erfolgreich erstellt`, 'info');
                          });
                      }
                  
                      // Erstellen/Prüfen aller Datenpunkte
                      for (const definition of stateDefinitions) {
                          createStateIfNotExists(definition.id, definition.initialValue, definition.common);
                      }
                  
                      // Initialisierung der Last-States für jede Quelle
                      const allSourceIds = Object.values(PowerSourceIds);
                      const currentTime = Date.now();
                  
                      for (const id of allSourceIds) {
                          // Versucht, den aktuellen Wert des Power-States zu lesen
                          const powerState = await getStateSafeAsync(id);
                          
                          lastStates[id] = {
                              lastPower: powerState,
                              lastTime: currentTime
                          };
                          log(`Initialisiere ${id} mit Leistung: ${powerState} W und Zeit: ${currentTime}.`);
                      }
                  
                      log("Initialisierung abgeschlossen.");
                  }
                  
                  /**
                   * Generische Funktion zur Berechnung der Delta-Energie und Aktualisierung der Ziel-States.
                   * @param sourceId Die ID des Power-Quell-States (z.B. GRID_POWER).
                   * @param currentPower Der aktuelle Leistungswert.
                   * @param currentTime Der aktuelle Zeitstempel.
                   */
                  async function processPowerUpdate(sourceId: string, currentPower: number, currentTime: number): Promise<void> {
                      const lastState = lastStates[sourceId];
                  
                      // Sicherstellen der Initialisierung
                      if (!lastState || lastState.lastTime === currentTime) {
                          // Sollte nicht passieren, da initializeScript aufgerufen wird, aber als Fallback
                          lastStates[sourceId] = { lastPower: currentPower, lastTime: currentTime };
                          return;
                      }
                  
                      const timeDiffSeconds = (currentTime - lastState.lastTime) / 1000;
                  
                      if (timeDiffSeconds <= 0) {
                          return; // Keine Zeit vergangen oder ungültige Messung
                      }
                  
                      // Berechnung der Energie: E [Wh] = P [W] * t [s] / 3600
                      // WICHTIG: Hier verwenden wir den aktuellen Power-Wert für eine einfache Trapez-Annäherung
                      // Die meisten Skripte verwenden nur den aktuellen Wert. Um die Komplexität des ursprünglichen Codes beizubehalten, 
                      // verwenden wir den aktuellen Wert * deltaT, obwohl oft (lastPower + currentPower) / 2 * deltaT genauer ist.
                      const energyWs = currentPower * timeDiffSeconds; 
                      const energyWh = energyWs / 3600;
                  
                      // Aktuellen summierten Tageswert lesen (Wh)
                  let currentWhValue = 0;
                      
                      switch (sourceId) {
                          case PowerSourceIds.GRID_POWER:
                              // Einspeisung (Negativ) vs. Netzbezug (Positiv)
                              if (currentPower < 0) { // Einspeisung
                                  const absEnergyWh = Math.abs(energyWh);
                                  currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_FEED_IN_WH)) + absEnergyWh;
                                  setEnergyStates(TargetStateIds.DAILY_FEED_IN_WH, TargetStateIds.DAILY_FEED_IN_KWH, currentWhValue);
                                  
                                  // Skript 4 Duplikat aktualisieren: Verwenden Sie hier auch eine Zahl
                                  const roundedFeedInWhS4 = Math.round(currentWhValue * 100) / 100;
                                  setState(TargetStateIds.DAILY_FEED_IN_WH_S4, roundedFeedInWhS4, true); // **HIER: Übergabe einer Zahl**
                                  
                              } else { // Netzbezug
                                  currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_GRID_PURCHASE_WH)) + energyWh;
                                  setEnergyStates(TargetStateIds.DAILY_GRID_PURCHASE_WH, TargetStateIds.DAILY_GRID_PURCHASE_KWH, currentWhValue);
                                  
                                  // Skript 4 Duplikat aktualisieren: Verwenden Sie hier auch eine Zahl
                                  const roundedGridWhS4 = Math.round(currentWhValue * 100) / 100;
                                  setState(TargetStateIds.DAILY_GRID_WH_S4, roundedGridWhS4, true); // **HIER: Übergabe einer Zahl**
                              }
                              break;
                  
                          case PowerSourceIds.HOUSE_CONSUMPTION_POWER:
                              // Hausverbrauch (immer positiv)
                              currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_HOUSE_CONSUMPTION_WH)) + energyWh;
                              setEnergyStates(TargetStateIds.DAILY_HOUSE_CONSUMPTION_WH, TargetStateIds.DAILY_HOUSE_CONSUMPTION_KWH, currentWhValue);
                              break;
                              
                          case PowerSourceIds.BAT_POWER:
                              // Batterie: Laden (Positiv) vs. Entladen (Negativ)
                              if (currentPower < 0) { // Entladen (Out)
                                  const absEnergyWh = Math.abs(energyWh);
                                  currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_BAT_OUT_WH)) + absEnergyWh;
                                  setEnergyStates(TargetStateIds.DAILY_BAT_OUT_WH, TargetStateIds.DAILY_BAT_OUT_KWH, currentWhValue);
                              } else { // Laden (In)
                                  currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_BAT_IN_WH)) + energyWh;
                                  setEnergyStates(TargetStateIds.DAILY_BAT_IN_WH, TargetStateIds.DAILY_BAT_IN_KWH, currentWhValue);
                              }
                              break;
                  
                          case PowerSourceIds.PV_POWER:
                              // PV-Produktion (immer positiv)
                              currentWhValue = (await getStateSafeAsync(TargetStateIds.DAILY_PV_WH)) + energyWh;
                              setEnergyStates(TargetStateIds.DAILY_PV_WH, TargetStateIds.DAILY_PV_KWH, currentWhValue);
                              break;
                      }
                  
                      // Bilanz-KWh (Skript 4 Logik) nur berechnen, wenn einer der relevanten Werte aktualisiert wird
                      if (sourceId === PowerSourceIds.PV_POWER || sourceId === PowerSourceIds.GRID_POWER) {
                          const pvWh = await getStateSafeAsync(TargetStateIds.DAILY_PV_WH);
                          const gridWh = await getStateSafeAsync(TargetStateIds.DAILY_GRID_PURCHASE_WH);
                          const bilanzKWh = (pvWh - gridWh) / 1000;
                  
                          // Der Unary Plus Operator (+) konvertiert den toFixed()-String zurück in eine Zahl.
                          setState(TargetStateIds.DAILY_BILANZ_KWH, +bilanzKWh.toFixed(3), true); 
                      }
                      
                      // Werte für die nächste Iteration speichern
                      lastState.lastPower = currentPower;
                      lastState.lastTime = currentTime;
                  }
                  
                  // -----------------------------------------------------------------------------------
                  // 4. TRIGGGER UND SCHEDULER
                  // -----------------------------------------------------------------------------------
                  
                  // 1. Initialisierung beim Skriptstart
                  initializeScript();
                  
                  // 2. Trigger bei Änderung eines Leistungsdatenpunkts (Einspeisung/Bezug, Haus, Batterie, PV)
                  on({ id: Object.values(PowerSourceIds), change: 'ne' }, async function (obj) {
                      const sourceId = obj.id as string;
                      const currentPower = parseFloat(obj.state.val);
                      const currentTime = Date.now();
                  
                      if (isNaN(currentPower)) {
                          log(`Ungültiger Leistungswert für ${sourceId}: ${obj.state.val}. Berechnung übersprungen.`, 'warn');
                          return;
                      }
                  
                      await processPowerUpdate(sourceId, currentPower, currentTime);
                  });
                  
                  // 3. Reset der Tagessummen um Mitternacht
                  schedule('0 0 * * *', async function () {
                      log("Mitternacht erreicht, setze Tagessummen zurück.");
                      
                      // Setze alle Ziel-Datenpunkte auf 0
                      for (const id of Object.values(TargetStateIds)) {
                          setState(id, 0, true);
                      }
                  
                      // Reset der Last-States für korrekte Berechnung am neuen Tag
                      const allSourceIds = Object.values(PowerSourceIds);
                      const currentTime = Date.now();
                  
                      for (const id of allSourceIds) {
                          // Aktuellen Power-Wert erneut holen, um als 'lastPower' für den neuen Tag zu dienen
                          const currentPower = await getStateSafeAsync(id);
                          lastStates[id] = { lastPower: currentPower, lastTime: currentTime };
                      }
                  
                      log("Alle Tagessummen und Zähler wurden zurückgesetzt.");
                  });
                  
                  
                  
                  M 1 Reply Last reply Reply Quote 0
                  • M
                    musicnrw @icebear last edited by

                    @icebear, vielen Dank für Deine schnelle Antwort.
                    Ich denke, ich kann das neue Gesamtscript, ohne an den alten was zu ändern oder diese zu deaktivieren, parallel installieren und die damit erzeugten Datenpunkte zumindest erstmal testweise für Visulaisierungen mit Grafana verwenden?

                    icebear 1 Reply Last reply Reply Quote 0
                    • icebear
                      icebear @musicnrw last edited by

                      @musicnrw

                      Das wäre ein guter Plan, und wenn alles läuft, dann einfach die alten deaktivieren.

                      M 1 Reply Last reply Reply Quote 0
                      • M
                        musicnrw @icebear last edited by

                        @icebear, Du schreibst ja "...du mußt dort halt die Datenpunkte evtl. auf deine Gegebenheiten anpassen....". Meinst Du mit diesen Datenpunkten die, deren Werte ich später in Grafana zur Visualisierung heranziehe?
                        Und wie kann ich es erreichen, dass ich für Auswertungen (z.B. PV-Ertrag letzte Woche, letzter Monat, letztes Jahr) sowohl auf die Daten zurückgreifen kann, die mit den alten Scripts generiert und in die InfluxDB geschrieben wurden, wie auch auf die Daten, die ab Tag X mit Deinem neuen Script in die InfluxDB wandern? Reicht dazu die identische Benennung der Datenpunkte bzw. ist es überhaupt möglich, dass Daten vom alten und neuen Script in gleich benannte Datenpunkte geschrieben werden (Konsistenz?)?

                        icebear 1 Reply Last reply Reply Quote 0
                        • icebear
                          icebear @musicnrw last edited by

                          @musicnrw

                          Du kannst doch die Tageswerte in der InfluxDB speichern und dann in der Abfrage mit der 'aggregation' (day, week, month) festlegen wie diese in Grafana dargestellt werden. oder du machst es so wie es @haus-automatisierung in diesem Video mal erklärt hat.

                          M 1 Reply Last reply Reply Quote 0
                          • M
                            musicnrw @icebear last edited by

                            @icebear , die Aggregierung ist schon klar, mache ich ja heute schon. Ich sehe nur die Schwierigkeit, dass die Datenpunkte nach altem Script z.B. in Datenpunkt "AAA" landen in der InfluxDB und die nach neuem Script in Datenpunkt "BBB". Wenn ich jetzt eine Auswertung über zurückliegende Zeiträume mache (z.B. Jahresauswertung), in die sowohl Daten aus "AAA" (z.B. bis Okt. 2025) wie auch welche aus "BBB" (z.B. ab Nov. 25) einfließen müssen, müsste ich ja beide berücksichtigen und aggregieren.

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

                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            1.1k
                            Online

                            32.4k
                            Users

                            81.2k
                            Topics

                            1.3m
                            Posts

                            adapter photovoltaik senec
                            70
                            386
                            88529
                            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