76_SolarForecast - Informationen/Ideen zu Weiterentwicklung und Support

Begonnen von DS_Starter, 11 Februar 2024, 14:11:00

Vorheriges Thema - Nächstes Thema

roadghost

NUC/Ubuntu 22.04 m. FHEM, div. Tasmota-Steckdosen, HMCFGUSB-2 für 12x HM-CC-RT-DN + 8x HM-TC-IT-WW
Rademacher DuoFern für 12 Jalousien, JeeLink für LaCrosse Temp.Sensor, WLAN-smart-Plugs, 
NUKI smartlock, 2xIP-CAM, Pylontech Speicher + Sungrow WR, Unifi-AP´s + Controller auf weiterem NUC

DS_Starter

#4381
@Gerd, @all,

der Setter "reset" ist nun deutlich aufgewertet. Die KI-Daten lassen sich selektiver löschen:

aiData    
    Mit den nachfolgenden Argumenten können die KI-Daten selektiv oder komplett entfernt werden:
   delDataAll - löscht die KI Instanz inklusive aller Trainings- und Rohdaten sowie Daten auf Fileebene und initialisiert sie neu
   delIndex=<Index>,<Index>,... - löscht einen oder mehrere Datensätze mit dem Index. Der Index kann als Regex angegeben sein.
   Beispiele: 1.) delIndex=2025013023 2.) delIndex=2025013023,2025013024 3.) delIndex=202501.* 4.) delIndex=20250130[0-9]

Weitere Eingrenzungsmöglichkeiten werden bei Bedarf folgen.
Außerdem können die weiteren reset-Optionen mit ihren Argumenten direkt in dem verfügbaren Eingabefeld aufgerufen werden. Dadurch entfällt bei bestimmten Aufrufen mit mehreren Argumenten die Notwendigkeit über die Kommandozeile zu gehen.

Liegt im Contrib.
Es sind nun bereits so viele Weiterentwicklungen eingeflossen, dass ich diese Version demnächst als Minor Release 1.60.0 veröffentlichen werde.

LG,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

DS_Starter

Thema smartPower Batteriesteuerung...

Meine Vermutung von gestern hat sich erhärtet. Das Ratio ist unter 100% und somit wird auf pinmax gegangen.
Alternativ könnte implementiere:

   Ratio < 100% -> OTP Iterationswert übernehmen (+ safety)
         < 50%  -> OTP pinmax

Allerdings wäre dadurch heute einiges mehr eingespeist worden. So wurden nur geringe Spitzen abgeschnitten.

...
2025.10.30 12:44:01.882 1: SolCast DEBUG> ChargeOTP Bat 01 - current Ratio of surplus / energy requirement to achieve the load target: 40.52 %
2025.10.30 12:44:01.882 1: SolCast DEBUG> ChargeOTP Bat 01 30/12 - hod:13/00, lr/lc:1/1, SocS/E:11082/11811 Wh, SurpH/D:2878/4292 Wh, OTP:5040/2878 W
2025.10.30 12:44:01.883 1: SolCast DEBUG> ChargeOTP Bat 01 30/13 - hod:14/01, lr/lc:1/1, SocS/E:11811/14398 Wh, SurpH/D:2723/1569 Wh, OTP:5040/2723 W
2025.10.30 12:44:01.883 1: SolCast DEBUG> ChargeOTP Bat 01 30/14 - hod:15/02, lr/lc:1/1, SocS/E:14398/16454 Wh, SurpH/D:2164/0 Wh, OTP:5040/2164 W
2025.10.30 12:44:01.884 1: SolCast DEBUG> ChargeOTP Bat 01 30/15 - hod:16/03, lr/lc:1/1, SocS/E:16454/17724 Wh, SurpH/D:1337/0 Wh, OTP:5040/1337 W
..
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Hadl

Zitat von: DS_Starter am 30 Oktober 2025, 14:37:53Meine Vermutung von gestern hat sich erhärtet. Das Ratio ist unter 100% und somit wird auf pinmax gegangen.
Hallo Heiko,
ich hab mich mal selbst an den Code gewagt und folgendes geändert:

- Aktuelle Stunden erhält wieder den Überschuss Anteilig der Rest-Minuten
- Der Überschuss des Rest Tages bis zum letzen Überschuss wird in RemainingSurp gespeichert
- RemainingSurp wird zur SmartPower Margin Berechnung verwendet statt spday
- Wenn der SOC unterhalb lowSoc ist wird die Ladeleistung nichtmehr auf bpinreduced nach oben hin begrenzt, sondern minimal bpinreduced gesetzt.

Damit hab ich schon nen relativ gleichmäßigen Verlauf über den Tag hinbekommen.

Die kleinen Wellen innerhalb einer Stunde möchte ich auch noch wegbekommen, dazu fehlt mir aber gerade der Ansatz. Ich glaube aber ich hab den Grund verstanden.

Wenn ich in einer Stunde 5kWh Überschuss habe, und im Schnitt 1kW brauche, dann passt das zu Beginn der Stunde.
Nach einer halben Stunde rechne ich noch mit 2,5kWh Überschuss in der Stunde. Die Stundenbasierte Suche nach minimaler Ladeleistung sieht also damit immer noch diese Stunde so als könnte man daraus 1kW ziehen. Der Akku ist aber schon voller, dadurch sinkt ungerechtfertigt die Ladeleistung.

Das ganze geht dann bis 10 Minuten vor der vollen Stunde. Dort sind von den 5kW nur noch 1kW übrig, aber auch das wird voll eingerechnet. Wir laden aber diese 1kWh nicht in 10 Minuten rein, sonst müssten wir mit 6kW laden. Hier ist der Fehler am größten.

Anschließend ist weniger als 1kW verfügbar, der Fehler wird kleiner und die Ladeleistung steigt wieder zur notwendigen Leistung hoch.

Hast du eine Idee, wie man die restliche Energiemenge der aktuellen Stunde so einrechnen könnte, das diese nur der minimal notwendigen Ladeleistung mal Rest-Zeit der Stunde entspricht?

Den Verlauf sieht man gut zwischen 13:00 und 15:00
Du darfst diesen Dateianhang nicht ansehen.
schlechtester Punkt wenn OTP ~= SurpH
Zitat2025.10.30 12:51:53 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 30/12 - hod:13/00, lr/lc:1/1, SocS/E:4524/4638 Wh, SurpH/D/R:880/6407/12207 Wh, OTP:877/731 W

Aber der Fehler ist klein genug so das er von den default Margin leicht aufgefangen wird.

VG

Hadl
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

Max_Meyer

Zitat von: DS_Starter am 30 Oktober 2025, 14:05:38der Setter "reset" ist nun deutlich aufgewertet. Die KI-Daten lassen sich selektiver löschen:

Guten Morgen Heiko,
Danke! - der Reset klappt gut.
Ich werde jetzt das Ergebnis beobachten - eigentlich müssten die 'Today_PVdeviation' wesentlich besser werden
Viele Grüße
Gerd
FHEM: PI3...5 FB7590/7530/EnOcean/FS20 /Revolt/FHEM2FHEM/HTTPMOD-->Solmaxx-, Deye-, Bosswerk-Inverter/ModBusTCP -->SMA-Inverter, GoE-Charger, BröntjeWP/Solarforecast/DbLog/DbRep/PostgreSQLDB/Grafana/MQTT-->Shelly,FHEM,HMS/HCCON/Netatmo/KLF etc.

DS_Starter

#4385
Moin Hadl,
ich habe mir die Kodierung mal genau angesehen und wir schauen  ob/wo Unterschiede zu finden sind...

Zitat- Aktuelle Stunden erhält wieder den Überschuss Anteilig der Rest-Minuten
- Der Überschuss des Rest Tages bis zum letzen Überschuss wird in RemainingSurp gespeichert
Vermutlich hast du nicht meine Version gändert in #4377 als Vorlage genommen.
Jedenfalls war die Zeitgewichtichtung nicht raus, sondern steckt in $total (= $RemainingSurp  bei dir).

Du hast es nur etwas umgemodelt. Erst das Replacement direkt ersetzt:

      if ($nh eq '00') {
              ...
              $hsurp->{$k}{surplswh} = $replacement;
              ...
      }

Und später:

      for my $h (@remaining_hods) {                                                                             
          my $val = $hsurp->{$h}{nhr} eq '00'
                    ? $replacement // 0
                    : $hsurp->{$h}{surplswh};
         
          $RemainingSurp += int $val;      (heißt bei mir nur $total += int $val;)
      }

Hier wird wird in der Stunde 00 das Replacement verwendet und sonst der Originalwert. Deswegen hättest du oben nicht das Replacement ersetzen müssen sondern nur extrahieren wie ich es bereits getan hatte.
Also bis zu diesem Punkt sind die Versionen identisch, nur dass $total nun $RemainingSurp heißt.
Das ist allerdings ein besserer Name den ich übernehmen werde.

Zitat- RemainingSurp wird zur SmartPower Margin Berechnung verwendet statt spday
Du verwendest:

          if ($strategy eq 'smartPower') {
              $pneedmin = ___batAdjustPowerByMargin ($name,                                                     
                                                     $limpower,
                                                     $bpinmax,
                                                     $runwhneed,
                                                     $otpMargin,
                                                     $RemainingSurp
                                                    );         
          }

Was wieder zu meinem

          if ($strategy eq 'smartPower') {
              $pneedmin = ___batAdjustPowerByMargin ($name,                                                     
                                                     $limpower,
                                                     $bpinmax,
                                                     $runwhneed,
                                                     $otpMargin,
                                                     $total
                                                    );         
          }

identisch ist wegen $total==$RemainingSurp ($spday ist hier schon in der Vorversion raus wenn ich mich recht erinnere).

Hier ist eine Stelle die den Nutzern von optPower wie Parallix nicht gefallen wird:

          my $fref      = ___batFindMinPhWh ($hsurp, \@remaining_hods, $runwhneed);
          my $limpower  = $fref->{ph};


Es wird die gewählte Strategie bzw. Erreichbarkeit des Ziel keine Beachtung mehr geschenkt. Im Original

          my $limpower  = $achievable || $strategy eq 'optPower'
                          ? min ($fref->{ph}, $spls)                                                           
                          : $fref->{ph};

wird eine Fallentscheidung vorgenommen und bei Erreichbarkeit des Ladeziels oder bei optPower Verwendung der Surplus-Wert als (zunächst) begrenzender Wert herangezogen. Achtung: wichtige Unterscheidung in der Ladeaggressivität was natürlich so bleiben soll.

Weiterhin wird nun durch die direkte Replacement-Ersetzung in der Iteration der Überschuß der aktuellen Stunde tendienziell gegen 0 gehen mit fortschreitender Zeit. Das hatte ich schonmal drin und hat sich als kontraproduktiv gezeigt, weswegen es entfernt wurde. 

Das hast du selbst auch erkannt und in dem Text beschrieben:
Zitat....
Die kleinen Wellen innerhalb einer Stunde möchte ich auch noch wegbekommen, dazu fehlt mir aber gerade der Ansatz. Ich glaube aber ich hab den Grund verstanden.

Wenn ich in einer Stunde 5kWh Überschuss habe, und im Schnitt 1kW brauche, dann passt das zu Beginn der Stunde.
Nach einer halben Stunde rechne ich noch mit 2,5kWh Überschuss in der Stunde. Die Stundenbasierte Suche nach minimaler Ladeleistung sieht also damit immer noch diese Stunde so als könnte man daraus 1kW ziehen. Der Akku ist aber schon voller, dadurch sinkt ungerechtfertigt die Ladeleistung.
....

Deswegen verwenden wir für die Iteration die Surplus-Stunden ohne Replacement und berechnen Zielerreichbarkeit und Steilheit der Margin bei smartPower mit dem Replacement. Dann hast du auch keine Wellen mehr in der Leistungsvorgabe bzw. eigentlich ja Ladeleistungsbeschränkung.


Zitat- Wenn der SOC unterhalb lowSoc ist wird die Ladeleistung nichtmehr auf bpinreduced nach oben hin begrenzt, sondern minimal bpinreduced gesetzt.
Das ist nicht gut. Wenn die Ladung unter lowSoc gefallen ist (was eigentlich nicht vorkommen sollte) wird die Batterie ggf. durch Netzstrom geladen. Das soll nur zaghaft mit pinreduced vorgenommen werden.
Aus welchem Grund bist du der Meinung dies ändern zu wollen?

ZitatHast du eine Idee, wie man die restliche Energiemenge der aktuellen Stunde so einrechnen könnte, das diese nur der minimal notwendigen Ladeleistung mal Rest-Zeit der Stunde entspricht?
Deswegen wird die Iteration ohne Zeitgewichtung vorgenommen. Dadurch bleibt die Leistungsbegrenzung über die Stunde weitgehend konstant. Nehmen wir an es ist ein Überschuß von 5kWh für die aktuelle Stunde prognostiziert und in der Gesamtkalkulation reicht es aus mit 1kW über diese eine Stunde zu laden, d.h. eine 1kWh in die Bat zu verbringen. Dann ist es völlig in Ordnung wenn zu Beginn der Stunde mit einer Leistung von 1kW geladen wird und am Ende dieser Stunde ebenfalls. Denn dann haben wir genau 1 kWh in der Batterie unter der Voraussetzung, dass über die gesamte Zeit mehr Überschuß als gewünschte/begrenzte Ladeleistung vorliegt.


LG,
Heiko
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Hadl

Hallo Heiko,
vielen Dank für deine Analyse.
Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Du hast es nur etwas umgemodelt. Erst das Replacement direkt ersetzt:
Wunderbar, ja das ist mir auch aufgefallen, das man das vereinfachen könnte. Hab mich aber erstmal auf die Energiedaten fokusiert.
Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Also bis zu diesem Punkt sind die Versionen identisch, nur dass $total nun $RemainingSurp heißt.
Ja, das hat mir etwas beim Denken geholfen das umzubenennen, ist aber ansonsten identisch
Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Es wird die gewählte Strategie bzw. Erreichbarkeit des Ziel keine Beachtung mehr geschenkt. Im Original
Code Auswählen Erweitern
          my $limpower  = $achievable || $strategy eq 'optPower'
                          ? min ($fref->{ph}, $spls)                                                           
                          : $fref->{ph};
wird eine Fallentscheidung vorgenommen und bei Erreichbarkeit des Ladeziels oder bei optPower Verwendung der Surplus-Wert als (zunächst) begrenzender Wert herangezogen. Achtung: wichtige Unterscheidung in der Ladeaggressivität was natürlich so bleiben soll.
Ich hab das absichtlich rausgenommen, weil mir das bei meinen Tests einen deutlich ungleichmäßigeren Verlauf beim stundenwechsel gegeben hat.
Das "$fref->{ph}" ist ja schon ein sehr gleichmäßiges Signal und garnicht aggresiv. Es stellt die niedrigsmögliche konstante Ladeleistungsbegrenzung dar mit der mit dem letzten Überschuss am Tag der Akku gerade noch voll wird. Das sah mir hier für beide Strategien hier am besten geeignet aus. Die Aggressivität kommt dann ja hinterher mit den Aufschlägen.
Evtl hilft hier auch schon das die aktuelle Stunde gewichtet eingerechnet wird, wodurch diesen "min" nichtmehr gebraucht wird. Falls doch müsste man $spls durch etwas besseres ersetzen, den am Ende der Stunde war das immer viel zu hoch, wodurch die Stunden-Sägezähne mit verursacht wurden.

Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Weiterhin wird nun durch die direkte Replacement-Ersetzung in der Iteration der Überschuß der aktuellen Stunde tendienziell gegen 0 gehen mit fortschreitender Zeit. Das hatte ich schonmal drin und hat sich als kontraproduktiv gezeigt, weswegen es entfernt wurde. 
Das zu behalten ist aber physikalisch richtig, ich hab nun auch die Lösung dazu gefunden, warum das Probleme gemacht hatte. Dazu hab ich noch eine Zeile in ___batFindMinPhWh eingefügt. Siehe weiter unten.

Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Das ist nicht gut. Wenn die Ladung unter lowSoc gefallen ist (was eigentlich nicht vorkommen sollte) wird die Batterie ggf. durch Netzstrom geladen. Das soll nur zaghaft mit pinreduced vorgenommen werden.
Aus welchem Grund bist du der Meinung dies ändern zu wollen?
Mit der Variante vor meiner Änderung wurde obwohl Überschuss vorhanden war und ein gleichmäßiges Laden mit mittlerer Leistung zum Ladeziel geführt hätte trotzdem nur mit pinreduced geladen. Dadurch wurde vom Überschuss nur wenig genutzt, sobald aber dann SocMin erreicht war musste um wieder aufzuholen mit etwas höherer Leistung weitergeladen werden. Das wiederspricht dem Ziel einer schonenden Akku-Ladung und der Nutzung von Energie für den Fall von Stromausfällen.
Falls überhaupt Netzstrom geladen werden kann, würde das ja nur im Fall fehlender Überschüsse passieren, dann wird auch in meinem Fall bei Null Überschuss mit pinreduced geladen.
Ich habe bei mir sogar nochmal außerhalb des Moduls in dem Fall das SOC < (lowSoc <) OptimumTargetSoC die Ladeleistungsbegrenzung fast komplett rausgenommen und sperre optionale Verbraucher. Ich erlaube aber auch keine Netzladung. (Außer die, die der Wechselrichter selbstständig macht zum Akkuschutz)
Das sieht man bei mir immer früh, wenn in der Nacht der Akku unter 40% sinkt.

Zitat von: DS_Starter am 31 Oktober 2025, 08:57:59Nehmen wir an es ist ein Überschuß von 5kWh für die aktuelle Stunde prognostiziert und in der Gesamtkalkulation reicht es aus mit 1kW über diese eine Stunde zu laden, d.h. eine 1kWh in die Bat zu verbringen. Dann ist es völlig in Ordnung wenn zu Beginn der Stunde mit einer Leistung von 1kW geladen wird und am Ende dieser Stunde ebenfalls. Denn dann haben wir genau 1 kWh in der Batterie unter der Voraussetzung, dass über die gesamte Zeit mehr Überschuß als gewünschte/begrenzte Ladeleistung vorliegt.
Perfekt, ich hatte genau die gleiche Vorstellung. Das hab ich erreicht indem ich noch mit einer Zeile die Zeitgewichtung der aktuellen Stunde in ___batFindMinPhWh eingebaut habe. Dadurch wurde am Ende der Stunde nichtmehr erwartet das man in deinem Beispiel 12 Minuten vor Stundenende von den 5kWh noch 1kWh Überschuss übrig hat und man denke man kann das mit 1kW Leistung reinladen. Das klappt auf 12 Minuten nicht, sondern da kriegt man nur 200Wh rein.
Damit sieht die Leistung heute morgen auch über die Stundengrenzen hinweg super gleichmäßig aus!

Ich hab heute wieder genügend Überschuss und erwarte dadurch eine sehr schonende gleichmäßige Ladung trotz des aggressiveren SmartPowers.
Bisher sehe ich garkeine Stunden-Abweichungen!  :D
Die aggressiveren Varianten könnte ich evtl. am Sonntag mit viel Wolken und Regen wieder sehen.


Viele Grüße

Hadl
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

DS_Starter

ZitatIch hab das absichtlich rausgenommen, weil mir das bei meinen Tests einen deutlich ungleichmäßigeren Verlauf beim stundenwechsel gegeben hat.
Das "$fref->{ph}" ist ja schon ein sehr gleichmäßiges Signal und garnicht aggresiv. Es stellt die niedrigsmögliche konstante Ladeleistungsbegrenzung dar mit der mit dem letzten Überschuss am Tag der Akku gerade noch voll wird. Das sah mir hier für beide Strategien hier am besten geeignet aus. Die Aggressivität kommt dann ja hinterher mit den Aufschlägen.
Evtl hilft hier auch schon das die aktuelle Stunde gewichtet eingerechnet wird, wodurch diesen "min" nichtmehr gebraucht wird. Falls doch müsste man $spls durch etwas besseres ersetzen, den am Ende der Stunde war das immer viel zu hoch, wodurch die Stunden-Sägezähne mit verursacht wurden.
Ja, $fref->{ph} ist gleichmäßig und wird deswegen ja auch in der Fallentscheidung für smartPower verwendet. Parallix war dies insbesondere bei volatilen Wetterlagen zu hoch, weswegen nun optPower und smartPower gibt mit der unterschiedlichen Anwendung der Begrenzung auf Surplus. Es wird also gebraucht ... allerdings nicht für smartPower.

ZitatDas zu behalten ist aber physikalisch richtig, ich hab nun auch die Lösung dazu gefunden, warum das Probleme gemacht hatte. Dazu hab ich noch eine Zeile in ___batFindMinPhWh eingefügt.
Physikalisch richtig schon aber nicht zielführend. Wir wollen nicht in Schönheit sterben sondern eine Batterie laden.  ;)

Hier
        for my $hod (@hods) {
            my $cap   = $hsurp->{$hod}{surplswh};
            my $nhr   = $hsurp->{$hod}{nhr};
            if ($nhr eq '00') { $cap = min ($mid, $cap) / 60 * (60 - int $minute); }
            $charged += $mid < $cap ? $mid : $cap;
        }

gibt es die Situation, dass in $hsurp->{$hod}{surplswh} bereits schon die Zeitgewichtung der Stunde 00 drin steckt.
Wenn $mid kleiner als $cap ist, passt das mit Zeitgewichtung weil sie auf $mid angewendet wird. Ist aber $cap kleiner wird der schon zeitgewichtete Wert der Stunde 00 nochmal behandelt.
Wenn man es tun will, dann die generelle Ersetzung in $hsurp->{$hod}{surplswh} nicht verwenden (wie Standard) und dann hier:

        for my $hod (@hods) {
            my $cap   = $hsurp->{$hod}{surplswh};
            my $nhr   = $hsurp->{$hod}{nhr};
            if ($nhr eq '00') { $cap = $cap / 60 * (60 - int $minute); }
            $charged += $mid < $cap ? $mid : $cap;
        }

Das werde ich bei mir mal einbauen und ausprobieren.

ZitatMit der Variante vor meiner Änderung wurde obwohl Überschuss vorhanden war und ein gleichmäßiges Laden mit mittlerer Leistung zum Ladeziel geführt hätte trotzdem nur mit pinreduced geladen.
Das ist unverständlich. War dein SoC < lowSoC? Wenn ja, wieso passiert das bei dir? Auf welchen Wert ist der Parameter eingestellt und wird er auch im Batteriesystem so verwendet?



Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

DS_Starter

Ich habe die kleine Anpassung in ___batFindMinPhWh eingebaut und sieht nun so aus:

        for my $hod (@hods) {
            my $cap   = $hsurp->{$hod}{surplswh};
            my $nhr   = $hsurp->{$hod}{nhr};
            $cap      = $cap / 60 * (60 - int $minute) if($nhr eq '00');
            $charged += $mid < $cap ? $mid : $cap;
        }

Dann habe ich das Ziel auf 75% angepasst. Zielerreichung ist nicht vorhanden und das Ratio bei 82.27 %.
Somit wird der Iterationswert zzgl. Margin genutzt (OTP:2432/2027 W) und bleibt auch die verbleibenden Stunden voraussichtlich konstant.
Fällt Ration < 50% gehe ich auf pinmax hoch.

2025.10.31 11:19:38.507 1: SolCast DEBUG> ChargeMgmt Bat 01 - charging target: 75 % / 21312 Wh
2025.10.31 11:19:38.507 1: SolCast DEBUG> ChargeMgmt Bat 01 - Percentage of the total amount of charging energy required: 100.0 %
2025.10.31 11:19:38.508 1: SolCast DEBUG> ChargeMgmt Bat 01 - The PV generation, consumption and surplus listed below are based on the battery's share of the total amount of charging energy required!
2025.10.31 11:19:38.515 1: SolCast DEBUG> ChargeOTP Bat 01 - used safety margin: 20 %
2025.10.31 11:19:38.515 1: SolCast DEBUG> ChargeOTP Bat 01 - charging target: 21312 Wh, remaining: 7672 Wh -> target likely achievable? no
2025.10.31 11:19:38.515 1: SolCast DEBUG> ChargeOTP Bat 01 - current Ratio of surplus / energy requirement to achieve the load target: 82.27 %
2025.10.31 11:19:38.516 1: SolCast DEBUG> ChargeOTP Bat 01 31/11 - hod:12/00, lr/lc:1/1, SocS/E:13640/14850 Wh, SurpH/D:1864/4135 Wh, OTP:2432/2027 W
2025.10.31 11:19:38.516 1: SolCast DEBUG> ChargeOTP Bat 01 31/12 - hod:13/01, lr/lc:1/1, SocS/E:14850/16044 Wh, SurpH/D:1257/2878 Wh, OTP:2432/2027 W
2025.10.31 11:19:38.516 1: SolCast DEBUG> ChargeOTP Bat 01 31/13 - hod:14/02, lr/lc:1/1, SocS/E:16044/17970 Wh, SurpH/D:2027/851 Wh, OTP:2432/2027 W
2025.10.31 11:19:38.517 1: SolCast DEBUG> ChargeOTP Bat 01 31/14 - hod:15/03, lr/lc:1/1, SocS/E:17970/19500 Wh, SurpH/D:1610/0 Wh, OTP:1932/1610 W
2025.10.31 11:19:38.517 1: SolCast DEBUG> ChargeOTP Bat 01 31/15 - hod:16/04, lr/lc:1/1, SocS/E:19500/19637 Wh, SurpH/D:144/0 Wh, OTP:5040/144 W
2025.10.31 11:19:38.517 1: SolCast DEBUG> ChargeOTP Bat 01 31/16 - hod:17/05, lr/lc:1/1, SocS/E:19637/19178 Wh, SurpH/D:0/0 Wh, OTP:5040/- W

Mal schauen wie es sich entwickelt.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Hadl

Zitat von: DS_Starter am 31 Oktober 2025, 11:29:43Ich habe die kleine Anpassung in ___batFindMinPhWh eingebaut und sieht nun so aus:

Da fehlt noch das minimum aus $cap und $mid.
Sollte unsere OTP Leistung $mid unterhalb der zur Verfügung stehenden $cap sein, würden wir sonst mit zuviel Energie rechnen, die wir in Wirklichkeit nicht bekommen können weil OTP niedriger ist. Dann haben wir wieder die Unterschreitungen am Ende der Stunde.

Ich hab mal unsere beiden Änderungen zusammengemerged, meine zusätzlichen aber drinnen gelassen. Das Ergebniss ist im Anhang

Damit siehts bisher so aus:
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - selected charging strategy: smartPower
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - General load termination condition: 0
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - control time Slot - Slot start: 00:00, Slot end: 23:59
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - Battery efficiency used: 87 %
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - weighted self-consumption: 0 %
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - charging target: 100 % / 7680 Wh
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - Percentage of the total amount of charging energy required: 100.0 %
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeMgmt Bat 01 - The PV generation, consumption and surplus listed below are based on the battery's share of the total amount of charging energy required!
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 - used safety margin: 20 %
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 - charging target: 7680 Wh, remaining: 2243 Wh -> target likely achievable? yes
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 - current Ratio of surplus / energy requirement to achieve the load target: 623.35 %
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 31/12 - hod:13/00, lr/lc:1/1, SocS/E:5437/7680 Wh, SurpH/D/R:4550/8468/13979 Wh, OTP:704/587 W
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 31/13 - hod:14/01, lr/lc:0/1, SocS/E:7680/7680 Wh, SurpH/D/R:4667/3801/9429 Wh, OTP:3000/0 W
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 31/14 - hod:15/02, lr/lc:0/1, SocS/E:7680/7680 Wh, SurpH/D/R:3121/680/4762 Wh, OTP:3000/0 W
2025.10.31 12:11:16 1: PV_SolarForecast DEBUG> ChargeOTP Bat 01 31/15 - hod:16/03, lr/lc:0/1, SocS/E:7680/7680 Wh, SurpH/D/R:1641/0/1641 Wh, OTP:3000/0 W

So gefällt mir das!  ;D
Du darfst diesen Dateianhang nicht ansehen.

Viele Grüße

Hadl
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

DS_Starter

#4390
ZitatDa fehlt noch das minimum aus $cap und $mid.
Sollte unsere OTP Leistung $mid unterhalb der zur Verfügung stehenden $cap sein, würden wir sonst mit zuviel Energie rechnen, die wir in Wirklichkeit nicht bekommen können weil OTP niedriger ist.
Macht $charged += $mid < $cap ? $mid : $cap;
Ist identisch mit $charged += min ($mid, $cap);
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

Hadl

Zitat von: DS_Starter am 31 Oktober 2025, 13:04:18
ZitatDa fehlt noch das minimum aus $cap und $mid.
Sollte unsere OTP Leistung $mid unterhalb der zur Verfügung stehenden $cap sein, würden wir sonst mit zuviel Energie rechnen, die wir in Wirklichkeit nicht bekommen können weil OTP niedriger ist.
Macht $charged += $mid < $cap ? $mid : $cap;
Ist identisch mit $charged += min ($mid, $cap);
Nicht ganz, denn damit würde, falls $mid < $cap ist die Aktuelle Stunde nicht anteilig von $mid gerechnet, sondern voll.
Damit würde wieder zum Ende der Stunde von zuviel Energie ausgegangen werden und die Leistung zu gering eingestellt.
Damit das funktioniert muss die Minimum Bildung vor der Gewichtung mit der Restzeit der aktuellen Stunde stattfinden.
            $cap = min ($mid, $cap) / 60 * (60 - int $minute) if ($nhr eq '00');     # Restkapazität der aktuellen Stunde mit Restzeit gewichten
            $charged += $mid < $cap ? $mid : $cap;
FHEM: Rpi 5 + SSD / WR: Fronius Symo Gen24 10.0 Plus + BYD HVS 7.7, Fronius Symo Gen24 12.0 SC (60%) PV: (Ost=3.5 West=6.6 Nord=9.9 Ost=4.5) / Homematic BidCoS / Shelly / Viessmann

DS_Starter

#4392
Ja, da streiten sich die Gelehrten.  ;)

Deswegen habe ich zur Entscheidungsfindung mal eine schlaue KI befragt. Hier das Ergebnis:

Konkrete Frage, welche Teilvariante ist zutreffender wenn $replacement den zeitgewichteten Anteil des PV Überschusses $hsurp->{$hod}{surplswh} zur aktuellen Stunde enthält:

        for my $hod (@hods) {
            my $nhr   = $hsurp->{$hod}{nhr};
            next if(!defined $nhr);
            my $cap   = $nhr eq '00' ? $replacement : $hsurp->{$hod}{surplswh};
            $charged += min ($mid, $cap);
        }

oder ohne Replacement

        for my $hod (@hods) {
            my $cap   = $hsurp->{$hod}{surplswh};
            my $nhr   = $hsurp->{$hod}{nhr};
            $cap = min ($mid, $cap) / 60 * (60 - int $minute) if ($nhr eq '00');     # Restkapazität der aktuellen Stunde mit Restzeit gewichten
            $charged += $mid < $cap ? $mid : $cap;
        }

Zusammenfassung — kurze Antwort
Die erste Variante ist korrekt, wenn für die aktuelle Stunde vollständig statt der stündlichen surplswh die alternative Kapazität $replacement gelten soll. Die zweite Variante ist korrekt, wenn die aktuelle Stunde nur anteilig (Restminuten) der normalen surplswh zur Verfügung steht.


Wann welche Variante wählen
Variante 1 (dein erstes Snippet) — wähle sie, wenn:

- $replacement den gesamten verfügbaren Überschuss für die aktuelle Stunde repräsentiert (z. B. ein zeitgewichteter, bereits berechneter Wert für die verbleibende Stunde) und
- für Stunden mit nhr eq '00' ausschließlich dieser Ersatzwert gelten soll (nicht anteilig von surplswh).

Variante 2 (dein zweites Snippet) — wähle sie, wenn:

- du nur den Anteil der aktuellen Stunde verwenden willst, also surplswh * (remaining_minutes/60), und
- $replacement nicht verwendet wird bzw. $replacement gar nicht die Rolle eines vollständigen Stundenwerts hat.


Warum die zweite Variante problematisch ist
- Sie bindet min($mid,$cap) an die Skalierung durch Restminuten, also wird $cap zunächst an $mid begrenzt und dann erneut verglichen — das erzeugt unnötige/fehlerhafte Doppelbegrenzung.
- Sie kann zu inkonsistenten Beiträgen führen und ist schwer zu lesen/zu debuggen.

Die letzte Aussage bzgl. Doppelbegrenzung war mir ja bereits in #4387 aufgefallen weswegen ich zur aktuellen Stunde das vorab berechnete und mitgegebene zeitgewichtete Replacement verwende.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

DS_Starter

Die aktualisierte Version 1.60.0 ist ins contrib geladen.
Proxmox+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter