Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Praktische Anwendungen (Showcase)
    4. [Script] PV-Überschuss mit Speicher vorhersagen

    NEWS

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

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    [Script] PV-Überschuss mit Speicher vorhersagen

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

      Hallo!

      Hoffe, ich bin in diesem Bereich richtig. Sonst gerne verschieben 😉

      @PatrickWalther hat unter https://forum.iobroker.net/topic/45315/test-pv-forecast-adapter ja einen Test-Adapter zur Abfrage der PV-Ertragsprognose veröffentlicht.

      Ich habe nun ein Skript "drumherum" geschrieben, welches diese Daten verwendet und zusätzlich noch einen Batteriespeicher und einen geschätzten Grundverbrauch einrechnet. Im Ergebnis erhält man dann einen Graph (für JSON-Chart der Material Design Widgets) und Datenpunkte für die prognostizierte Netzeinspeisung und den Netzbezug. Beides will man ja eigentlich vermeiden...

      3d1e3d83-1656-4b2e-8e72-cfe4e95b0a55-image.png

      Das Skript ist noch ganz frisch und wird auch sicherlich noch erweitert. Wollte es aber schonmal teilen:

      v0.3 20.02.2022

      // PV-Ertragsprognose
      // Ermittelt anhand der PV-Ertragsprognose des "PV Forecast Adapters",
      // der Kapazität des PV-Speichers und des geschätzen Grundverbrauchs
      // den Überschuss (= Strom der eingespeist wird)
      // und den Netzbezug (= Strom der vom Netzbetreiber bezogen wird).
      //
      // Ziel soll es sein, den Eigenverbrauch zu erhöhen indem variable Großverbraucher
      // gezielt eingeschaltet werden können.
      //
      // --- Anleitung ---
      // 1. PV Forecast Adapter von https://forum.iobroker.net/topic/45315/test-pv-forecast-adapter installieren
      //    und richtig konfigurieren
      // 2. Untenstehende Datenpunkte ggf. anpassen (nicht existierende werden automatisch angelegt)
      // 3. Skript starten
      // 4. Für Visualisierung das JSON-Chart Widget der Material Design Widgets zur Visualisierung hinzufügen
      //    (https://github.com/Scrounger/ioBroker.vis-materialdesign)
      // 5. Quelle des JSON-Chart Widgets auf den untenstehenden DP dpPVPrognoseGraph (Default: "0_userdata.0.PV.ErtragsPrognoseGraph") setzen
      //
      //
      //
      // v0.1 19.02.2022 (oxident)
      //      erste Version
      // v0.2 19.02.2022 (oxident)
      //      JSON-Graph Korrekturen
      // v0.3 20.02.2022 (oxident)
      //      bekannter Akkustand geändert (wird ignoriert wenn Wert < 0)
      
      // konfigurierbare Einstellungen:
      
      const dpPVPrognoseStunde = "pvforecast.0.summary.everyhour_kw";             // DP vom PV-Forecast Adapter
      const dpPVPrognoseLastUpdate = "pvforecast.0.summary.lastUpdated_data";     // DP vom PV-Forecast Adapter
      
      const dpPVPrognoseAkkustandJetzt = "0_userdata.0.PV.AkkuLadestandJetzt";    // DP mit aktuellem Ladestand des Speichers
                                                                                  // falls Wert >= 0, dann wird der Wert zu der Stunde
                                                                                  // der Aktualisierung verwendet
                                                                                  // falls Wert < 0, dann wird der Wert ignoriert
                                                                                  
      const dpPVPrognoseAkkustandMax = "0_userdata.0.PV.AkkuLadestandMax";        // DP mit maximalem Ladestand des Speichers
                                                                                  // (beides in kWh)
                                                                                  // die Werte dann unbedingt auf die richtigen Werte
                                                                                  // einstellen bzw. vom Speicher abfragen
      
      const dpPVPrognoseVerbrauch = "0_userdata.0.PV.VerbrauchStunde"             // Verzeichnis mit Datenpunkten des Verbrauchs pro Stunde
      
      const dpPVPrognoseGraph = "0_userdata.0.PV.ErtragsPrognoseGraph";           // hier wird das JSON für das JSON Chart Widget geschrieben
      
      const dpPVPrognoseEinspeisung = "0_userdata.0.PV.PrognoseEinspeisung";      // hier wird die Einspeisung für den gesamten Tag geschrieben
      const dpPVPrognoseBezug = "0_userdata.0.PV.PrognoseBezug";                  // hier wird der Netzbezug für den gesamten Tag geschrieben
      
      const fAkkustandBeginn = 0.0;                                               // angenommener Akkustand (kWh) zu Tagesbeginn
                                                                                  // dies könnte in Zukunft ggf. auf den tatsächlichen
                                                                                  // Wert um Mitternacht gesetzt werden
      
      const fGrundverbrauch = 1.0;                                                // angenommener Grundverbrauch (kWh) pro Stunde
                                                                                  // könnte in Zukunft auch noch feiner eingestellt werden
                                                                                  // wenn z. B. bekannt ist, zu welcher Zeit der Verbrauch
                                                                                  // höher oder niedriger ist
                                                                                  // oder man zieht historische Daten hinzu.
      
      // ENDE Einstellungen
      
      const fErtragPrognose = []; // PV-Ertrag in kWh pro Stunde
      var fGrundverbrauchPrognose = []; // geschätzter Grundverbauch in kWh pro Stunde
      const fAkkustandPrognose = []; // geschätzter Akkustand in kWh pro Stunde
      const fNetzbezugPrognose = []; // geschätzter Netzbezug in kWh pro Stunde
      const fUeberschussPrognose = []; // geschätzer Überschuss in kWh pro Stunde (voller Akku)
      
      
      
      function createDP() {
          if(!existsState(dpPVPrognoseGraph)) {
              createState(dpPVPrognoseGraph,"",{name: "PV Prognose JSON-Graph", type: 'string', role: 'value', write: false}, function() {});
          }
      
          for(var i=0;i<24;i++) {
              if(!existsState(dpPVPrognoseVerbrauch + "." + pad(i,2) + ":00:00")) {
                  createState(dpPVPrognoseVerbrauch + "." + pad(i,2) + ":00:00",0,{name: "PV Prognose Verbrauch " + pad(i,2) + ":00:00", type: 'number', role: 'value', write: true, unit: 'kWh'}, function () {
                      setState(dpPVPrognoseVerbrauch + "." + pad(i,2) + ":00:00", fGrundverbrauch);
                  });
              } 
          }
          
      
          if(!existsState(dpPVPrognoseBezug)) {
              createState(dpPVPrognoseBezug,0,{name: "PV Prognose Netzbezug", type: 'number', role: 'value', write: false, unit: 'kWh'}, function () {});
          } 
          
          if(!existsState(dpPVPrognoseEinspeisung)) {
              createState(dpPVPrognoseEinspeisung,0,{name: "PV Prognose Einspeisung", type: 'number', role: 'value', write: false, unit: 'kWh'}, function () {});
          }
      
          if(!existsState(dpPVPrognoseAkkustandJetzt)) {
              createState(dpPVPrognoseAkkustandJetzt,-1,{name: "Aktueller Akkustand", type: 'number', role: 'value', write: true, unit: 'kWh'}, function () {});
          }
      
          if(!existsState(dpPVPrognoseAkkustandMax)) {
              createState(dpPVPrognoseAkkustandMax,10,{name: "Maximaler Akkustand", type: 'number', role: 'value', write: true, unit: 'kWh'}, function () {});
          }
      }
      
      function updateGraph() {
      
          
      
          var iAkkuUpdateHour = 0;
          if(getState(dpPVPrognoseAkkustandJetzt).val>=0) iAkkuUpdateHour = new Date(getState(dpPVPrognoseAkkustandJetzt).ts).getHours();
      
          const fAkkustandMax = getState(dpPVPrognoseAkkustandMax).val; // maximale Akkuladung in kWh
      
          var iEinspeisungGesamt = 0.0; // Netzeinspeisung Tageswert in kWh
          var iNetzbezugGesamt = 0.0; // Netzbezug Tageswert in kWh
      
          
          fGrundverbrauchPrognose = [];
      
          for(var i=0;i<24;i++) {
              fGrundverbrauchPrognose[i] = getState(dpPVPrognoseVerbrauch + "." + pad(i,2) + ":00:00").val;
          }
      
          
      
      
          for(var i=0;i<24;i++) {
              if(existsState(dpPVPrognoseStunde + "." + pad(i, 2) + ":00:00")) {
                  fErtragPrognose[i] = getState(dpPVPrognoseStunde + "." + pad(i, 2) + ":00:00").val;
              } else {
                  fErtragPrognose[i] = 0.0;
              }
              
              //fErtragPrognose[i] = Math.round((fErtragPrognose[i] + Number.EPSILON) * 100) / 100;
          }
      
          fAkkustandPrognose[0] = 0.0;
          fUeberschussPrognose[0] = 0.0;
          fNetzbezugPrognose[0] = fGrundverbrauchPrognose[0];
      
          for(var i=1;i<24;i++) {
              if(i==iAkkuUpdateHour) {
                  fAkkustandPrognose[i] = getState(dpPVPrognoseAkkustandJetzt).val;
              } else {
                  fAkkustandPrognose[i] = fAkkustandPrognose[i-1];
              }
              
              
              
              if((fAkkustandPrognose[i] + (fErtragPrognose[i] - fGrundverbrauchPrognose[i])) > 0.0) {
                  // Akku wird ausreichen
                  if((fAkkustandPrognose[i] + (fErtragPrognose[i] - fGrundverbrauchPrognose[i])) > fAkkustandMax) {
                      // Akku erreicht maximale Ladung
                      fUeberschussPrognose[i] = (fErtragPrognose[i] - fGrundverbrauchPrognose[i]) - (fAkkustandMax - fAkkustandPrognose[i]);
                      fAkkustandPrognose[i] = fAkkustandMax;
                      fNetzbezugPrognose[i] = 0.0;
                      iEinspeisungGesamt += fUeberschussPrognose[i];
                      
                  } else {
                      // Akku bleibt unterhalb maximaler Ladung
                      fAkkustandPrognose[i] += (fErtragPrognose[i] - fGrundverbrauchPrognose[i]);
                      fNetzbezugPrognose[i] = 0.0;
                      fUeberschussPrognose[i] = 0.0;
                      
                  }
              } else {
                  // Akku wird nicht ausreichen (Netzbezug)
                  fNetzbezugPrognose[i] = (fGrundverbrauchPrognose[i] - fErtragPrognose[i]) - fAkkustandPrognose[i];
                  fAkkustandPrognose[i] = 0.0;
                  fUeberschussPrognose[i] = 0.0;
                  iNetzbezugGesamt += fNetzbezugPrognose[i];
              }
          }
      
          var objJsonGraph = {};
          objJsonGraph.axisLabels = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.axisLabels.push(pad(i, 2) + ":00");
          }
      
          objJsonGraph.graphs = [];
      
          // Ertragsprognose
          objJsonGraph.graphs[0] = {};
          
          objJsonGraph.graphs[0]['type'] = "line";
          objJsonGraph.graphs[0]['legendText'] = "Ertragsprognose";
          objJsonGraph.graphs[0]['datalabel_show'] = false;
          objJsonGraph.graphs[0]['yAxis_show'] = true;
          objJsonGraph.graphs[0]['yAxis_min'] = 0;
          objJsonGraph.graphs[0]['yAxis_max'] = 15;
          objJsonGraph.graphs[0]['yAxis_id'] = 1;
      
          
      
          objJsonGraph.graphs[0]['tooltip_AppendText'] = "kWh";
          objJsonGraph.graphs[0]['color'] = "yellow";
      
          objJsonGraph.graphs[0]['line_pointSize'] = 2;
          objJsonGraph.graphs[0]['line_Tension'] = 0.3;
          objJsonGraph.graphs[0]['line_pointSizeHover'] = 5;
          objJsonGraph.graphs[0]['line_UseFillColor'] = true;
          
          objJsonGraph.graphs[0]['displayOrder'] = 3;
      
          objJsonGraph.graphs[0]['data'] = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.graphs[0]['data'].push(fErtragPrognose[i]);
          }
          
          // Netzbezug (extern)
          objJsonGraph.graphs[1] = {};
          objJsonGraph.graphs[1]['type'] = "line";
      
          objJsonGraph.graphs[1]['data'] = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.graphs[1]['data'].push(fNetzbezugPrognose[i]);
          }
          objJsonGraph.graphs[1]['legendText'] = "Netzbezug " + roundTwoDigits(iNetzbezugGesamt) + "kWh";
          objJsonGraph.graphs[1]['datalabel_show'] = false;
          objJsonGraph.graphs[1]['yAxis_show'] = false;
          objJsonGraph.graphs[1]['yAxis_min'] = 0;
          objJsonGraph.graphs[1]['yAxis_max'] = 15;
          objJsonGraph.graphs[1]['yAxis_id'] = 1;
      
          objJsonGraph.graphs[1]['tooltip_AppendText'] = "kWh";
          objJsonGraph.graphs[1]['color'] = "red";
      
          objJsonGraph.graphs[1]['line_pointSize'] = 2;
          objJsonGraph.graphs[1]['line_Tension'] = 0.3;
          objJsonGraph.graphs[1]['line_pointSizeHover'] = 5;
          objJsonGraph.graphs[1]['line_UseFillColor'] = true;
      
          objJsonGraph.graphs[1]['displayOrder'] = 1;
      
      
          // Akkustand
          objJsonGraph.graphs[2] = {};
          objJsonGraph.graphs[2]['type'] = "line";
          objJsonGraph.graphs[2]['data'] = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.graphs[2]['data'].push(fAkkustandPrognose[i]);
          }
          objJsonGraph.graphs[2]['legendText'] = "Akkustand";
          objJsonGraph.graphs[2]['datalabel_show'] = false;
          objJsonGraph.graphs[2]['yAxis_show'] = false;
          objJsonGraph.graphs[2]['yAxis_min'] = 0;
          objJsonGraph.graphs[2]['yAxis_max'] = 15;
          objJsonGraph.graphs[2]['yAxis_id'] = 1;
      
          objJsonGraph.graphs[2]['tooltip_AppendText'] = "kWh";
          objJsonGraph.graphs[2]['color'] = "green";
      
          objJsonGraph.graphs[2]['line_pointSize'] = 2;
          objJsonGraph.graphs[2]['line_Tension'] = 0.3;
          objJsonGraph.graphs[2]['line_pointSizeHover'] = 5;
          objJsonGraph.graphs[2]['line_UseFillColor'] = true;
      
          objJsonGraph.graphs[2]['displayOrder'] = 2;
      
      
          // Netzeinspeisung (extern)
          objJsonGraph.graphs[3] = {};
          objJsonGraph.graphs[3]['type'] = "line";
          objJsonGraph.graphs[3]['data'] = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.graphs[3]['data'].push(fUeberschussPrognose[i]);
          }
          objJsonGraph.graphs[3]['legendText'] = "Netzeinspeisung " + roundTwoDigits(iEinspeisungGesamt) + "kWh";
          objJsonGraph.graphs[3]['datalabel_show'] = false;
          objJsonGraph.graphs[3]['yAxis_show'] = false;
          objJsonGraph.graphs[3]['yAxis_min'] = 0;
          objJsonGraph.graphs[3]['yAxis_max'] = 15;
          objJsonGraph.graphs[3]['yAxis_id'] = 1;
      
          objJsonGraph.graphs[3]['tooltip_AppendText'] = "kWh";
          objJsonGraph.graphs[3]['color'] = "blue";
      
          objJsonGraph.graphs[3]['line_pointSize'] = 2;
          objJsonGraph.graphs[3]['line_Tension'] = 0.3;
          objJsonGraph.graphs[3]['line_pointSizeHover'] = 5;
          objJsonGraph.graphs[3]['line_UseFillColor'] = true;
      
          objJsonGraph.graphs[3]['displayOrder'] = 0;
      
          // Verbrauch (geplant)
          objJsonGraph.graphs[4] = {};
          objJsonGraph.graphs[4]['type'] = "line";
          objJsonGraph.graphs[4]['data'] = [];
          for(var i=0; i<24; i++) {
              objJsonGraph.graphs[4]['data'].push(fGrundverbrauchPrognose[i]);
          }
          objJsonGraph.graphs[4]['legendText'] = "Verbrauch";
          objJsonGraph.graphs[4]['datalabel_show'] = false;
          objJsonGraph.graphs[4]['yAxis_show'] = false;
          objJsonGraph.graphs[4]['yAxis_min'] = 0;
          objJsonGraph.graphs[4]['yAxis_max'] = 15;
          objJsonGraph.graphs[4]['yAxis_id'] = 1;
      
          objJsonGraph.graphs[4]['tooltip_AppendText'] = "kWh";
          objJsonGraph.graphs[4]['color'] = "gray";
      
          objJsonGraph.graphs[4]['line_pointSize'] = 2;
          objJsonGraph.graphs[4]['line_Tension'] = 0.3;
          objJsonGraph.graphs[4]['line_pointSizeHover'] = 5;
          objJsonGraph.graphs[4]['line_UseFillColor'] = true;
      
          objJsonGraph.graphs[4]['displayOrder'] = 4;
      
          setStateAsync(dpPVPrognoseGraph, JSON.stringify(objJsonGraph), true);
          setStateAsync(dpPVPrognoseBezug, roundTwoDigits(iNetzbezugGesamt), true);
          setStateAsync(dpPVPrognoseEinspeisung, roundTwoDigits(iEinspeisungGesamt), true);
          
          //console.log("Netzbezug: " + roundTwoDigits(iNetzbezugGesamt) + " Einspeisung: " + roundTwoDigits(iEinspeisungGesamt));
          
      }
      
      function pad(num, size) {
          num = num.toString();
          while (num.length < size) num = "0" + num;
          return num;
      }
      
      function roundTwoDigits(num) {
          return Math.round((num + Number.EPSILON) * 100) / 100;
      }
      
      
      
      createDP();
      updateGraph();
      
      on({id: dpPVPrognoseLastUpdate, change: 'ne'}, function(obj) {
          updateGraph();
      });
      
      on({id: dpPVPrognoseAkkustandJetzt, change: 'ne'}, function(obj) {
          updateGraph();
      });
      
      on({id: dpPVPrognoseAkkustandMax, change: 'ne'}, function(obj) {
          updateGraph();
      });
      
      var aVerbrauchsDP = [];
      for(var i=0;i<24;i++) {
              aVerbrauchsDP.push(dpPVPrognoseVerbrauch + "." + pad(i,2) + ":00:00");
      }
      
      on({id: aVerbrauchsDP, change: 'ne'}, function(obj) {
          updateGraph();
      });
      
      1 Reply Last reply Reply Quote 1
      • First post
        Last post

      Support us

      ioBroker
      Community Adapters
      Donate

      941
      Online

      31.7k
      Users

      79.7k
      Topics

      1.3m
      Posts

      1
      1
      1094
      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