Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Praktische Anwendungen (Showcase)
  4. [Script] PV-Überschuss mit Speicher vorhersagen

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    15
    1
    842

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

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    1.9k

[Script] PV-Überschuss mit Speicher vorhersagen

Geplant Angeheftet Gesperrt Verschoben Praktische Anwendungen (Showcase)
1 Beiträge 1 Kommentatoren 1.2k Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • O Offline
    O Offline
    oxident
    schrieb am zuletzt editiert von oxident
    #1

    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 Antwort Letzte Antwort
    1
    Antworten
    • In einem neuen Thema antworten
    Anmelden zum Antworten
    • Älteste zuerst
    • Neuste zuerst
    • Meiste Stimmen


    Support us

    ioBroker
    Community Adapters
    Donate

    845

    Online

    32.6k

    Benutzer

    82.0k

    Themen

    1.3m

    Beiträge
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
    ioBroker Community 2014-2025
    logo
    • Anmelden

    • Du hast noch kein Konto? Registrieren

    • Anmelden oder registrieren, um zu suchen
    • Erster Beitrag
      Letzter Beitrag
    0
    • Home
    • Aktuell
    • Tags
    • Ungelesen 0
    • Kategorien
    • Unreplied
    • Beliebt
    • GitHub
    • Docu
    • Hilfe