76_SolarForecast - Informationen/Ideen zu Weiterentwicklung und Support

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

Vorheriges Thema - Nächstes Thema

DS_Starter

#4245
Hallo Hadl,

vielen Dank!  :)

ZitatMittlerweile sehe ich aber auch immer mehr Stunden mit geringen Ertrag, und nur kurzen "Lichtblicken" am Tag. Die würde ich gerne in den Akku bekommen anstatt diese einzuspeisen und dann am Abend den Akku nicht voll zu haben.
In ein paar Wochen kommt sicher wieder die Zeit in der der Akku über Nacht ab und zu leer wird.
...
Deshalb würde ich mich über ein Signal "target likely achievable"=0 des aktuellen Tages sehr freuen. Ich würde auch dann mit hoher Leistung laden lassen und einspeisen damit vermeiden.
Ich kann das vollkommen nachvollziehen und habe diese Idee bei mir heute im Laufe des Tages bereits eingebaut und getestet. Den Trigger "target likely achievable"=0 zu nutzen und die Ladeleistung entsprechend hochzuheben ist m.M. nach in Verbindung mit optPower eine sehr gut funktionierende Variante die Volatilität in dieser Jahreszeit abzufangen und für die Batterie zu nutzen.

Schwierig ist eine Festlegung der Ladeleistung die irgendwo zwischen pinreduced und pinmax liegt, denn diese Optimierung macht ja die optPower-Logik bereits. Die Schwäche, unvorhergesehene "Lichtblicke" mit hohen Erträgen nicht nutzen zu können, liegt dann in der Natur der Sache.

Die Idee den achievable-Status zu nutzen ist in der aktuellen Contrib-Version enthalten wenn du es ausprobieren möchtest. Morgen ist wieder so ein verhangener Tag an dem es vielleicht "Lichtblicke" gibt. Dann lässt es sich gut beobachten.

Im Anhang ist eine schöne gleichmäßge Ladekurve zu sehen die kurz nach 16:00 das gewünschte Max von 100% erreicht.

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

grappa24

wird der achievable-Status automatisch verarbeitet oder ist der selbst umzusetzen?
Gebäudesicherheit/-komfort, PV-Prognose/Verbrauchssteuerung, Heizungssteuerung, Multimedia, ...
KNX, FS20, HM, HUE, Tradfri, Shellies, KLF200, Netatmo, Nuki, SolarForecast, HEOS, Alexa-FHEM, ...
FHEM 6.4, 2 x RasPi 3B+, Debian Bullseye

DS_Starter

Moin,

das wird automatisch gemacht.
Wenn es aus bestimmten Gründen gewünscht ist, kann ich auch ein Reading dafür erstellen. Allerdings ist der Wert pro Batterie zu errechnen. Je nach deren Anzahl würden dann 1-X Readings generiert.
Alternativ könnte ich auch einen Wert in valBattery erstellen, der aus Scripten heraus mit BatteryVal gelesen werden könnte.
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,
ich hab mir die aktuelle version aus dem Contrib geladen und lasse es heute mal damit laufen. Ich werde berichten.

Zitat von: DS_Starter am 13 Oktober 2025, 18:59:44Schwierig ist eine Festlegung der Ladeleistung die irgendwo zwischen pinreduced und pinmax liegt, denn diese Optimierung macht ja die optPower-Logik bereits. Die Schwäche, unvorhergesehene "Lichtblicke" mit hohen Erträgen nicht nutzen zu können, liegt dann in der Natur der Sache.
Ich hab mir das so vorgestellt:
Die optPower Logik versucht ja den Energiebedarf möglichst gleichmäßig auf die Stunden mit Energieüberschuss zu verteilen. Wenn viel Überschuss vorhanden ist, dann wird die Ladeleistung auch mit hoher Wahrscheinlichkeit erfüllt.
Sollte es aber knapp sein, müsste man mehr von den kurzen "Lichtblicken" profitieren, indem man den berechneten optPower Wert anhebt.

Man könnte auf den Quotienten zwischen erwarteten Überschuss und Ladebedarf des Rest-Tages schauen.
Ist dieser > 120% wird OptPower wie berechnet werwendet.
Ist dieser < 100% wird pinmax verwendet.
Ist dieser zwischen 100% und 120% wird linear zwischen OptPower und pinmax interpoliert und diese erhöhte Leistung als neues OptPower verwendet.

Nehmen wir an, OptPower berechnet für den aktuellen Zeitpunkt 1000W und pinmax ist 2000W:
Überschuss/Ladebedarf[%] -> OptPower
100% -> 2000W
105% -> 1750W
110% -> 1500W
115% -> 1250W
120% -> 1000W

Die 120% sollen nur ein Beispiel sein und sollten einstellbar sein.
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

grappa24

Gebäudesicherheit/-komfort, PV-Prognose/Verbrauchssteuerung, Heizungssteuerung, Multimedia, ...
KNX, FS20, HM, HUE, Tradfri, Shellies, KLF200, Netatmo, Nuki, SolarForecast, HEOS, Alexa-FHEM, ...
FHEM 6.4, 2 x RasPi 3B+, Debian Bullseye

DS_Starter

Hallo Hadl,

wir behalten das im Hinterkopf und schauen uns erstmal an wie die aktuelle Lösung jetzt mit den Situationen umgeht.

ZitatMan könnte auf den Quotienten zwischen erwarteten Überschuss und Ladebedarf des Rest-Tages schauen.
Ist dieser > 120% wird OptPower wie berechnet werwendet.
Ist dieser < 100% wird pinmax verwendet.
Ist dieser zwischen 100% und 120% wird linear zwischen OptPower und pinmax interpoliert und diese erhöhte Leistung als neues OptPower verwendet.
Im Prinzip wird der Fall "Ist dieser < 100% wird pinmax verwendet" jetzt bereits abgebildet. Der Status achievable=0 sagt aus, dass das Ladeziel wegen ungenügenden Überschuß rechnerisch nicht erreicht werden kann.

Dann wäre eine stufenweise Abschwächung von pinmax (bei 100%) bis optpower (bei >= 120%) noch umzusetzen. Im Prinzip gibt es das in abgewandelter Form jetzt auch schon. Über den Parameter ctrlBatSocManagementXX->safetyMargin kannst du einen prozentualen Sicherheitsaufschlag auf den berechneten optPower-Wert aufschlagen lassen. Wenn es sich als günstig erweist, könnte ich eine solche Abstufung aus safetyMargin ableiten. Schauen wir mal...

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

Parallix

#4251
Einige haben sich vielleicht gefragt, warum ich gerne in Battery_ChargeOptTargetPower_XX eine sinnvolle berechnete Ladeleistung und nicht (in einigen Situationen) einen festen Wert wie pinmax hätte. Der Grund liegt zum einen darin, dass auch bei volatilen Wetterlagen keine Leistungssprünge, von 0 auf pinmax haben möchte.

Es gibt aber noch einen weiteren Grund: Wenn man mal von einem "Force"-Modus absieht, startet meine in FHEM realisierte Ladesteuerung für mein EV die Ladung erst dann, wenn der zur Verfügung stehende "Überschuss" eine gewisse Grenze überschreitet. In Abhängigkeit vom aktuellen Ladezustand der Hausspeicher rechne ich in vorgenannten Grenze, also den geforderter Überschuss, die aktuellen Ladeleistungen der Hausspeicher mit deren aktuellem SOC gewichtet ein und verfolge damit das im SF-Wiki unter dem Stichwort "Priorisierung" beschrieben Ziel einer Verschiebung von Ladeprioritäten.

Beispiel: Bei einem Haus-SOC von 90% wird 90% der akt. Hausspeicher-Ladeleistung in den zur Verfügung stehenden Überschuss für die EV-Ladung eingerechnet, bei einem Haus-SOC von 0% halt gar nichts.

Edit: Meine EV-Ladesteuerung basiert auf der Annahme, dass das EV innnerhalb einer Woche (insb. tagsüber) einige Tage durchgehend zur Ladung zur Verfügung steht, also z.B. von Freitag 15:00 Uhr bis Montag 7:00 Uhr und in diesem Zeitfester eine Aufladung möglich ist, um mit dem EV wenigstens über die verbleibenden Zeit pro Woche zu kommen ohne die Hausspeicher so stark zu entladen, das mit diesen das Ziel einer 100% Autarkie nicht mehr erfüllt werden kann. Ist dies (im Beispiel) bis Sonntag 24:00 Uhr nicht möglich, so erfolgt eine (Teil-)Aufladung über das öffentliche Netz.

Übrigens: Unvorhergesehene Lichtblicke bei volatilen Wetterlagen führen selbst bei einer unbegrenztem max. Ladeleistung - zumindest bei mir - selten zu signifikanten Energieeinträgen.
FHEM: Debian/Testing BananaPro - AVM: 7490 (7.60) und 7591 (8.20) - Goodwe: GW25K-ET (DSP V10 / ARM V12) - Trina TSM 405: (#East, #South, #West) = (12,16,12) - BYD: 2 x HVS 7.7 (BMS V3.31-B, BMU V3.26-B) - EnOcean - Z-Wave - FS20/HMS

DS_Starter

ZitatEinige haben sich vielleicht gefragt, warum ich gerne in Battery_ChargeOptTargetPower_XX eine sinnvolle berechnete Ladeleistung und nicht (in einigen Situationen) einen festen Wert wie pinmax hätte.
Diese sinnvoll berechnete Ladeleistung gibt es im Reading Battery_ChargeOptTargetPower_XX und ist ja das Ergebnis der optPower-Logik. Diese Logik stützt sich, wie kann es anders sein, auf die PV- und Verbrauchsprognose. Nur muß man dann damit leben, dass unvorhergesehene plötzliche Aufklarungen bei sonst bedeckten Himmel verbunden mit einer plötzlichen/starken PV-Erzeugung im Form von Einspeisung "verloren" geht. Dem kann man nur mit einem gewissen Sicherheitsaufschlag (safetyMargin) begegnen oder aber wie aktuell im contrib implementiert, die Aktivierung der berechneten optPower von einer generellen Erreichbarkeit abhängig zu gestalten. Dadurch ist die Wahrscheinlichkeit deutlich gesteigert, unvermittelte Sonnenenergie in die Batterie zu laden. 
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

Parallix

#4253
Zitat von: DS_Starter am 13 Oktober 2025, 10:45:31...
Damit ist man auch nicht davor gefeit, dass mal etwas eingespeist wird ... steht alles im Wiki.

Eine Variante wäre eine automatische Umschaltung zur Strategie "loadRelease" wenn/solange das Ladeziel als unerreichbar errechnet wird -> "target likely achievable? no". Das kann der User tun, dazu brauche ich nur ein Reading/Signal dieser Berechnung bereitzustellen.

EDIT: Alternativ dazu könnte ich die aktuelle Ladeleistung auf pinmax stellen, solange "target likely achievable?"== no ist. Das würde eine fallbezogene Mischung aus loadRelease und optPower ergeben. Sobald das Ladeziel überhaupt erreichbar scheint, greift dann eine optimale Ladestrombegrenzung.

Eine explizit gewählte Ladestrategie automatisch umzuschalten, dass fände ich sehr seltsam. Logischer wäre es vermutlich, eine weitere Ladestrategie "Automatik" einzuführen, die dann selber entscheidet, was zu tun ist.

Edit (zu Deinem Edit): Auch wenn das Ziel nicht erreichbar ist, sollte meines Erachtens die "optimale Ladestrombegrenzung" greifen, wenn ein User die Strategie "schonende Ladung" aka "optPower" gewählt hat.

Zitat@all:
Im contrib liegt eine neue Version mit folgenden Umsetzungen:

- mit ctrlBatSocManagementXX->loadTarget kann ein Ladeziel (0..100%) für die Bat eingestellt werden
- bei mehreren Batterien wird deren Anteil vom aktuellen Ladungsdefizit im Verhältnis zum Gesamtdefizit bestimmt. Bisher wurde dafür
  die installierte Kapazität benutzt

Gerade die Auswirkungen des letzten Aspekts kann ich bei mir nur ungenügend testen/simulieren weil ich nur eine Batterie habe. Deswegen bin ich auf euer Feedback angewiesen wie sich das Ladeverhalten verändert.

Gerne teste ich die neuen Features, wobei ich ctrlBatSocManagementXX->loadTarget erst dann auf einen Wert < 100 setzen möchte, wenn es am Tag mal mehr als 0 Sonnenstunden (ein Prognosewert, der in der DWD-App Warnwetter abgegeben wird) prognostiziert werden ;-)

Edit: Im Wiki finde eine textuell inzwischen sehr anspruchsvolle Beschreibung der Ladestrategien. Was ich vermisse ist eine klassische algorithmische Darstellung, die ich gerne beisteuern würde. Da aktuell aber noch einiges nicht konsolidiert ist, werde ich dieses Projekt wahrscheinlich erst kommenden Monat in Angriff nehmen, sofern Interesse an einer entsprechenden Darstellung besteht und würde mich diesbezüglich über ein Feedback freuen.
FHEM: Debian/Testing BananaPro - AVM: 7490 (7.60) und 7591 (8.20) - Goodwe: GW25K-ET (DSP V10 / ARM V12) - Trina TSM 405: (#East, #South, #West) = (12,16,12) - BYD: 2 x HVS 7.7 (BMS V3.31-B, BMU V3.26-B) - EnOcean - Z-Wave - FS20/HMS

DS_Starter

#4254
@all,

im contrib liegt ein weiteres Update.
Es sind nun folgenden Umsetzungen enthalten:

- bei mehreren Batterien wird deren Anteil vom aktuellen Ladungsdefizit im Verhältnis zum Gesamtdefizit bestimmt. Bisher wurde dafür
  die installierte Kapazität benutzt. Diese Aufteilung ist für die SoC- und Ladesteuerung benutzt/relevant.

- ein neues Reading Battery_TargetAchievable_XX
 
- Verfügbarkeit von nun 3 Ladestrategien:
  loadStrategy   
        Abhängig von der gewählten Ladestrategie wird die Prognose der Batterieladung und ggf. die
        Generierung der Steuerreadings beeinflusst. Die Angabe ist optional.
        Weitere Informationen zur Auswahl der Strategie siehe Wiki.
        Wert: loadRelease | optPower | smartPower, default: loadRelease

- die generelle Erreichbarkeit des Ladeziels (achievable) wird bei Aktivierung der Ladestrategie 'smartPower' in die
  Berechnung von optPower einbezogen.

- mit ctrlBatSocManagementXX->stepSoC kann die Schrittweite zur optimalen SoC-Berechnung eingestellt oder das SoC-Management abgeschaltet werden

  stepSoC   
    Optionale Schrittweite zur optimalen SoC-Berechnung (Battery_OptimumTargetSoC_XX) in %.
    Mit der Angabe 'stepSoC=0' wird das SoC-Management deaktiviert und Battery_OptimumTargetSoC_XX
    auf den Wert 'lowSoC' gesetzt.
    Hinweis: Die Beziehung 'careCycle * stepSoC = 100' sollte eingehalten werden!
    Wert: 0..5, default: 5
   
- mit ctrlBatSocManagementXX->loadTarget kann ein Ladeziel (0..100%) für die Bat eingestellt werden

  loadTarget   
    Optionaler Ziel-SoC in % für die Berechnung der Ladefreigabe bzw. der optimalen Ladeleistung.
    Der Zielwert ist eine kalkulatorische Rechengröße. Der reale SoC kann je Situation in Grenzen
    über- oder unterschritten werden. Der höhere Wert aus Reading Battery_OptimumTargetSoC_XX
    und 'loadTarget' hat für die Berechnung Vorrang.
    Wert: 0..100, default: 100


ZitatIm Wiki finde eine textuell inzwischen sehr anspruchsvolle Beschreibung der Ladestrategien. Was ich vermisse ist eine klassische algorithmische Darstellung, die ich gerne beisteuern würde.
Liebend gerne.
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

Parallix

Zitat von: DS_Starter am 14 Oktober 2025, 14:17:56@all,

im contrib liegt ein weiteres Update.
...

Das sind sehr gute Nachrichten, da sich das Modul nun - generischer gestaltet - viele Anwendungsfälle unterstützt!  Toll finde ich die sich aus Deiner Fußnote ergebende Perspektive!
FHEM: Debian/Testing BananaPro - AVM: 7490 (7.60) und 7591 (8.20) - Goodwe: GW25K-ET (DSP V10 / ARM V12) - Trina TSM 405: (#East, #South, #West) = (12,16,12) - BYD: 2 x HVS 7.7 (BMS V3.31-B, BMU V3.26-B) - EnOcean - Z-Wave - FS20/HMS

DS_Starter

Es gibt jetzt die dritte Ladestrategie 'smartPower'. Der Text in #4254 ist ergänzt und das Modul im Contrib upgedated.

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

alkazaa

#4257
Zitat von: ch.eick am 23 Juni 2025, 16:33:59Kurze Zwischenfrage,
hat bereits jemand die Abfrage der EPEX Spot Preise direkt von der Quelle, also ohne Drittanbieter Web Seiten dazwischen für FHEM umgesetzt?
Ich hatte im Wiki ja mal https://wiki.fhem.de/wiki/Stromb%C3%B6rse begonnen, jedoch hat bisher niemand etwas ergänzt :-(
Hallo Christian, (auch wenn deine Frage schon etwas zurück liegt:)
ich habe (ähnlich wie Max_Meyer) ein HTTPMOD geschrieben, das die EPEX Preise von https://energy-charts.info/charts/price_spot_market/chart.htm?l=de&c=DE abholt. Da sie jetzt mit viertelstündlicher Auflösung veröffentlicht werden, habe ich die 96 Werte (in €/MWh) für einen Tag als Liste ausgegeben:
define EPEX_Boersenpreise HTTPMOD https://energy-charts.info/charts/price_spot_market/data/de/week_15min_day_year_week.json 86400
attr EPEX_Boersenpreise alignTime 00:05:00
attr EPEX_Boersenpreise comment This device reads EPEX auction prices (in €/MWh) for 15 min intervals published at https://energy-charts.info/charts/price_spot_market. 96 values for the day and 96 values for dayahead are reported in the respective readings. The dayahead prices are only published at around 14:00, so the reading 'dayhead' says "not yet published" before 14:00. \
A reread is performed twice a day, at 5 min past midnight due to the interval 86400 sec and alignTime 00:05, and at 14:28 due to an 'at' which is created during the reread.\

attr EPEX_Boersenpreise event-on-update-reading day,dayahead
attr EPEX_Boersenpreise get02Name dayahead
attr EPEX_Boersenpreise get02OExpr {$val =~ m/((?:,?[\d\.]*){96})/;; $1}
attr EPEX_Boersenpreise get02RegOpt s
attr EPEX_Boersenpreise get02Regex Auktion \(DE-LU\).*?\[(.*?)\]
attr EPEX_Boersenpreise get02URL https://energy-charts.info/charts/price_spot_market/data/de/week_15min_dayahead_year_week.json
attr EPEX_Boersenpreise reading01Name day
attr EPEX_Boersenpreise reading01OExpr {# The following 'at' definition ensures that a reread occurs at 14:05:\
 fhem("define get_EPEX_afternoon at 14:28 set $name reread");;\
 # Since the webpage data are always reported for a full week (with Monday = day 1),\
 # $a gives the number of data to skip from the data block, before the 96 data for \
 # dayahead or day are extracted\
 my $a = 96 * strftime( "%u", localtime());; \
 fhem("sleep 0.001;;setreading $name dayahead not yet published");;\
 # If number of 'today' is less then 7, both 'day' and 'dayahead' data are in one\
 # block. First the 'dayahead' data are extracted and written into reading 'dayahead'\
 # if they exist (which is only the case after 14:00). Otherwise reading 'dayahead' \
 # remains at 'not yet published'.\
 if ($a/96 < 7) \
  {if ($val =~ m"(?:[\d\.]*,){$a}((?:,?[\d\.]*){96})")\
{fhem("sleep 0.001;;setreading $name dayahead $1");;}}\
 else \
 # If number of 'today' is 7, the dayahead data are not in the same week's data block\
 # but need to be extracted from a separate URL. It is only for this case that the \
 # get02 'get dayhead' command is required, and it is called here.\
 # Note that the definition of 'get02Regex' is especially simple, as it can be assumed that\
 # the data block for the new week contains only the 96 data for dayahead.\
 {fhem("get $name dayahead");;}\
 # After this foreplay, the data for 'day' are eventually extracted.\
 # The data-to-skip count $a is decreased by 96 for this reason:\
 $a -= 96;;\
 $val =~ m"(?:[\d\.]*,){$a}((?:,?[\d\.]*){96})";; $1}
attr EPEX_Boersenpreise reading01RegOpt s
attr EPEX_Boersenpreise reading01Regex Auktion \(DE-LU\).*?\[(.*?)\]
attr EPEX_Boersenpreise replacement01Mode expression
attr EPEX_Boersenpreise replacement01Regex day_year_week
attr EPEX_Boersenpreise replacement01Value {strftime( "%G", localtime())."_".strftime( "%V", localtime())}
attr EPEX_Boersenpreise replacement02Mode expression
attr EPEX_Boersenpreise replacement02Regex dayahead_year_week
attr EPEX_Boersenpreise replacement02Value {strftime("%G", localtime(time + 86400))."_".(strftime( "%V", localtime(time + 86400)))}
attr EPEX_Boersenpreise room Energie
attr EPEX_Boersenpreise userReadings data:d_ata.* {my @a = split(/,/,ReadingsVal($name,"d_ata",""));;"@a[0..30]"}
attr EPEX_Boersenpreise verbose 3
#   BUSY       0
#   DEF        https://energy-charts.info/charts/price_spot_market/data/de/week_15min_day_year_week.json 86400
#   FUUID      68e92bf1-f33f-3e5d-7968-e45ea686cfd749b0
#   Interval   86400
#   MainURL    https://energy-charts.info/charts/price_spot_market/data/de/week_15min_day_year_week.json
#   ModuleVersion 4.2.0 - 11.8.2023
#   NAME       EPEX_Boersenpreise
#   NOTIFYDEV  global
#   NR         187
#   NTFY_ORDER 50-Strompreise2
#   STATE      ???
#   TYPE       HTTPMOD
#   eventCount 356
#   value     
#   CompiledRegexes:
#   HttpUtils:
#     NAME       
#     addr       https://energy-charts.info:443
#     auth       0
#     buf       
#     code       200
#     compress   1
#     conn       
#     data       
#     displayurl https://energy-charts.info/charts/price_spot_market/data/de/week_15min_2025_42.json
#     header     
#     host       energy-charts.info
#     httpheader HTTP/1.1 200 OK
#date: Wed, 15 Oct 2025 11:01:29 GMT
#content-type: application/json
#content-length: 64755
#last-modified: Wed, 15 Oct 2025 10:54:29 GMT
#etag: "68ef7d65-fcf3"
#content-security-policy: default-src 'self';                                  script-src 'self' 'unsafe-inline' 'unsafe-eval'  https://stats.ise.fraunhofer.de  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com  https://cdnjs.cloudflare.com  https://platform.twitter.com  https://cdn.syndication.twimg.com/  http://*.tile.openstreetmap.org  https://api.tiles.mapbox.com  https://api.mapbox.com  https://wisskomm.social/@energy_charts_d ;                                 img-src data: 'self' blob: data:  https://stats.ise.fraunhofer.de  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com  https://cdnjs.cloudflare.com  https://platform.twitter.com  https://cdn.syndication.twimg.com/  http://*.tile.openstreetmap.org  https://api.tiles.mapbox.com  https://api.mapbox.com  https://wisskomm.social/@energy_charts_d ;                                 style-src 'self' 'unsafe-inline'  https://stats.ise.fraunhofer.de  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com  https://cdnjs.cloudflare.com  https://platform.twitter.com  https://cdn.syndication.twimg.com/  http://*.tile.openstreetmap.org  https://api.tiles.mapbox.com  https://api.mapbox.com  https://wisskomm.social/@energy_charts_d ;                                 font-src 'self'  https://stats.ise.fraunhofer.de  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com  https://cdnjs.cloudflare.com  https://platform.twitter.com  https://cdn.syndication.twimg.com/  http://*.tile.openstreetmap.org  https://api.tiles.mapbox.com  https://api.mapbox.com  https://wisskomm.social/@energy_charts_d ;                                 frame-src  https://stats.ise.fraunhofer.de  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com  https://cdnjs.cloudflare.com  https://platform.twitter.com  https://cdn.syndication.twimg.com/  http://*.tile.openstreetmap.org  https://api.tiles.mapbox.com  https://api.mapbox.com  https://wisskomm.social/@energy_charts_d                                 frame-ancestors  leonid.muc.zae-bayern.de  grizzly.rheintal-hosting.ch  kkl.swissscreen.com ;                                 object-src 'none'
#access-control-allow-origin: leonid.muc.zae-bayern.de
#x-frame-options: ALLOW-FROM leonid.muc.zae-bayern.de
#access-control-allow-origin: grizzly.rheintal-hosting.ch
#x-frame-options: ALLOW-FROM grizzly.rheintal-hosting.ch
#access-control-allow-origin: kkl.swissscreen.com
#x-frame-options: ALLOW-FROM kkl.swissscreen.com
#access-control-allow-methods: GET, POST, OPTIONS
#access-control-allow-headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range
#access-control-expose-headers: Content-Length,Content-Range
#accept-ranges: bytes
#server: Nginx
#strict-transport-security: max-age=16000000; includeSubDomains; preload;
#connection: close
#     httpversion 1.0
#     hu_blocking 0
#     hu_filecount 1
#     hu_port    443
#     hu_portSfx
#     ignoreredirects 1
#     loglevel   4
#     path       /charts/price_spot_market/data/de/week_15min_2025_42.json
#     protocol   https
#     redirects  0
#     timeout    2
#     url        https://energy-charts.info/charts/price_spot_market/data/de/week_15min_2025_42.json
#     sslargs:
#   OLDREADINGS:
#   QUEUE:
#   READINGS:
#     2025-10-15 13:01:29   day             120.26,116.09,113.53,111.97,117.16,112.45,110.16,107.69,110.15,108.38,106.29,105.9,105.98,104.94,101.43,102.12,102.06,104.76,107.21,111.89,108.85,112.74,116.6,119.4,117.12,131.33,164.35,195.04,211.75,270.1,319.58,313.53,354.61,304.77,247.13,198.28,252.11,197.67,143.43,131.0,184.44,141.01,131.88,112.1,145.77,130.42,117.22,111.01,127.91,124.04,115.92,109.83,118.01,115.82,111.0,106.68,107.51,109.68,116.98,127.4,103.7,107.64,124.93,154.3,101.51,118.71,147.98,174.57,105.02,130.3,183.17,261.51,156.76,189.62,246.84,294.29,293.57,242.91,182.93,160.59,213.51,158.01,124.95,114.91,153.28,131.41,118.17,94.51,114.72,101.31,95.35,81.46,95.39,87.17,87.1,83.02
#     2025-10-15 13:01:29   dayahead        not yet published
#   REQUEST:
#     context    reading
#     data       
#     header     
#     ignoreredirects 0
#     num        unknown
#     retryCount 0
#     type       update
#     url        https://energy-charts.info/charts/price_spot_market/data/de/week_15min_day_year_week.json
#   defptr:
#     readingBase:
#       dat        reading
#       day        reading
#       dayahead   get
#       werte      get
#     readingNum:
#       dat        01
#       day        01
#       dayahead   02
#       werte      01
#     readingOutdated:
#     requestReadings:
#       get01:
#         werte      get 01
#       get02:
#         dayahead   get 02
#       update:
#         dat        reading 01
#         day        reading 01
#         dayahead   reading 02
#   hmccu:
#   lastpoll:
#     dayahead   1760417110.24968
#     werte      1760287547.19493
#
setstate EPEX_Boersenpreise 2025-10-15 13:01:29 day 120.26,116.09,113.53,111.97,117.16,112.45,110.16,107.69,110.15,108.38,106.29,105.9,105.98,104.94,101.43,102.12,102.06,104.76,107.21,111.89,108.85,112.74,116.6,119.4,117.12,131.33,164.35,195.04,211.75,270.1,319.58,313.53,354.61,304.77,247.13,198.28,252.11,197.67,143.43,131.0,184.44,141.01,131.88,112.1,145.77,130.42,117.22,111.01,127.91,124.04,115.92,109.83,118.01,115.82,111.0,106.68,107.51,109.68,116.98,127.4,103.7,107.64,124.93,154.3,101.51,118.71,147.98,174.57,105.02,130.3,183.17,261.51,156.76,189.62,246.84,294.29,293.57,242.91,182.93,160.59,213.51,158.01,124.95,114.91,153.28,131.41,118.17,94.51,114.72,101.31,95.35,81.46,95.39,87.17,87.1,83.02
setstate EPEX_Boersenpreise 2025-10-15 13:01:29 dayahead not yet published

EDIT: Habe Kommentare im code block ergänzt und Zeiten für das 'reread' definiert.

Hadl

Zitat von: DS_Starter am 13 Oktober 2025, 18:59:44Ich kann das vollkommen nachvollziehen und habe diese Idee bei mir heute im Laufe des Tages bereits eingebaut und getestet. Den Trigger "target likely achievable"=0 zu nutzen und die Ladeleistung entsprechend hochzuheben ist m.M. nach in Verbindung mit optPower eine sehr gut funktionierende Variante die Volatilität in dieser Jahreszeit abzufangen und für die Batterie zu nutzen.

Hallo Heiko, ich habs jetzt mal laufenlassen, aber bisher hatte ich trotz vieler Bewölkung immer deutlich mehr PV Ertrag als ich gebraucht hätte, daher sehe ich den Effekt von achievable=0 noch nicht.

Aber mir ist ein Fall eingefallen, wo ich das auch als Reading brauchen würde.
Ich habe in meinem Warmwasserspeicher einen Heizstab indem ich PV Überschuss zum Heizen verwende. Wenn achievable=0 ist würde ich den Heizstab auf jedem Fall aus lassen wollen, dann wird mit der klasischen Heizung (Öl) das Wasser erwärmt fals nötig. Der Heizstab wird mit fhem und einen shelly gesteuert.
Für andere optionale Verbraucher (E-Auto laden,...) würde ich das warscheinlich auch ähnlich machen.
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

#4259
@Hadl,
ZitatAber mir ist ein Fall eingefallen, wo ich das auch als Reading brauchen würde.
Ok, implementiere ich gern.
Perspektivisch werde ich dann wahrscheinlich, wie von Parallix vorgeschlagen, die True/False-Readings Battery_ChargeAbort_XX, Battery_ChargeRequest_XX, Battery_ChargeUnrestricted_XX und dem noch hinzukommenden Battery_TargetAchievable_XX ein zusammengefasstes Reading Battery_Status_XX erstellen.

Aber das muß ich erst in Ruhe entwickeln wenn ich mal viel Zeit und Lust zu einer solchen Änderung habe. Es muß ja auch gut erkennbar und auswertbar sein -> Zukunftsmusik.
Anwendungsseitig problematisch bei zusammengetzten Readings ist vor allem, dass es keinen Bezug mehr gibt wenn man NUR für einen bestimmten Sachverhalt, z.B. Battery_ChargeAbort_XX, einen Event haben möchte. 

@all,
ich habe die Idee von Hadl aus #4248 aufgenommen und in die Ladestrategie 'smartPower' integriert.
Dadurch ergibt sich ein linear absenkender Sicherheitsaufschlag sofern das Tagesziel erreichbar ist.
Das Funktionsverhalten ist im Anhang erkennbar.

Der folgende Logauszug verdeutlicht die Unterschiede der Strategien optPower und smartPower.

Strategie = optPower (optimierte Ladeleistung), pinreduced = 600 W, safety 5%:
2025.10.15 11:17:46.584 1: SolCast DEBUG> ChargeOTP - The limit for grid feed-in is 4800 W
2025.10.15 11:17:46.585 1: SolCast DEBUG> ChargeOTP Bat 01 - used safety margin: 5 %
2025.10.15 11:17:46.585 1: SolCast DEBUG> ChargeOTP Bat 01 - weighted self-consumption: 0 %
2025.10.15 11:17:46.586 1: SolCast DEBUG> ChargeOTP Bat 01 - charging target: 28416 Wh, remaining: 13924 Wh -> target likely achievable? no
2025.10.15 11:17:46.586 1: SolCast DEBUG> ChargeOTP Bat 01 15/11 - hod: 12 / 00, lr/lc: 1/1, SoC S/E: 14492 / 14584 Wh, Surplus: 135 Wh, OTP: 662 W
2025.10.15 11:17:46.586 1: SolCast DEBUG> ChargeOTP Bat 01 15/12 - hod: 13 / 01, lr/lc: 1/1, SoC S/E: 14584 / 15321 Wh, Surplus: 776 Wh, OTP: 815 W
2025.10.15 11:17:46.587 1: SolCast DEBUG> ChargeOTP Bat 01 15/13 - hod: 14 / 02, lr/lc: 1/1, SoC S/E: 15321 / 16252 Wh, Surplus: 980 Wh, OTP: 1029 W
2025.10.15 11:17:46.587 1: SolCast DEBUG> ChargeOTP Bat 01 15/14 - hod: 15 / 03, lr/lc: 1/1, SoC S/E: 16252 / 18063 Wh, Surplus: 1906 Wh, OTP: 2001 W
2025.10.15 11:17:46.587 1: SolCast DEBUG> ChargeOTP Bat 01 15/15 - hod: 16 / 04, lr/lc: 1/1, SoC S/E: 18063 / 20869 Wh, Surplus: 2954 Wh, OTP: 3102 W
2025.10.15 11:17:46.588 1: SolCast DEBUG> ChargeOTP Bat 01 15/16 - hod: 17 / 05, lr/lc: 1/1, SoC S/E: 20869 / 21408 Wh, Surplus: 567 Wh, OTP: 630 W
2025.10.15 11:17:46.588 1: SolCast DEBUG> ChargeOTP Bat 01 15/17 - hod: 18 / 06, lr/lc: 1/1, SoC S/E: 21408 / 21254 Wh, Surplus: 0 Wh, OTP: 5040 W
2025.10.15 11:17:46.589 1: SolCast DEBUG> ChargeOTP Bat 01 15/18 - hod: 19 / 07, lr/lc: 1/1, SoC S/E: 21254 / 20654 Wh, Surplus: 0 Wh, OTP: 5040 W
2025.10.15 11:17:46.589 1: SolCast DEBUG> ChargeOTP Bat 01 15/19 - hod: 20 / 08, lr/lc: 1/1, SoC S/E: 20654 / 20012 Wh, Surplus: 0 Wh, OTP: 5040 W
2025.10.15 11:17:46.589 1: SolCast DEBUG> ChargeOTP Bat 01 15/20 - hod: 21 / 09, lr/lc: 1/1, SoC S/E: 20012 / 19305 Wh, Surplus: 0 Wh, OTP: 5040 W


Strategie = smartPower (zieloptimierte Ladeleistung), pinreduced = 600 W, safety 5%:


2025.10.15 11:19:22.668 1: SolCast DEBUG> ChargeOTP - The limit for grid feed-in is 4800 W
2025.10.15 11:19:22.669 1: SolCast DEBUG> ChargeOTP Bat 01 - used safety margin: 5 %
2025.10.15 11:19:22.669 1: SolCast DEBUG> ChargeOTP Bat 01 - weighted self-consumption: 0 %
2025.10.15 11:19:22.670 1: SolCast DEBUG> ChargeOTP Bat 01 - charging target: 28416 Wh, remaining: 13924 Wh -> target likely achievable? no
2025.10.15 11:19:22.670 1: SolCast DEBUG> ChargeOTP Bat 01 15/11 - hod: 12 / 00, lr/lc: 1/1, SoC S/E: 14492 / 14578 Wh, Surplus: 132 Wh, OTP: 5040 W
2025.10.15 11:19:22.670 1: SolCast DEBUG> ChargeOTP Bat 01 15/12 - hod: 13 / 01, lr/lc: 1/1, SoC S/E: 14578 / 15331 Wh, Surplus: 793 Wh, OTP: 5040 W
2025.10.15 11:19:22.671 1: SolCast DEBUG> ChargeOTP Bat 01 15/13 - hod: 14 / 02, lr/lc: 1/1, SoC S/E: 15331 / 16234 Wh, Surplus: 950 Wh, OTP: 5040 W
2025.10.15 11:19:22.671 1: SolCast DEBUG> ChargeOTP Bat 01 15/14 - hod: 15 / 03, lr/lc: 1/1, SoC S/E: 16234 / 18237 Wh, Surplus: 2108 Wh, OTP: 5040 W
2025.10.15 11:19:22.671 1: SolCast DEBUG> ChargeOTP Bat 01 15/15 - hod: 16 / 04, lr/lc: 1/1, SoC S/E: 18237 / 20742 Wh, Surplus: 2637 Wh, OTP: 2769 W
2025.10.15 11:19:22.672 1: SolCast DEBUG> ChargeOTP Bat 01 15/16 - hod: 17 / 05, lr/lc: 1/1, SoC S/E: 20742 / 20843 Wh, Surplus: 106 Wh, OTP: 630 W
2025.10.15 11:19:22.672 1: SolCast DEBUG> ChargeOTP Bat 01 15/17 - hod: 18 / 06, lr/lc: 1/1, SoC S/E: 20843 / 20456 Wh, Surplus: 0 Wh, OTP: 5040 W
2025.10.15 11:19:22.672 1: SolCast DEBUG> ChargeOTP Bat 01 15/18 - hod: 19 / 07, lr/lc: 1/1, SoC S/E: 20456 / 19856 Wh, Surplus: 0 Wh, OTP: 5040 W
2025.10.15 11:19:22.673 1: SolCast DEBUG> ChargeOTP Bat 01 15/19 - hod: 20 / 08, lr/lc: 1/1, SoC S/E: 19856 / 19214 Wh, Surplus: 0 Wh, OTP: 5040 W


Der Pseudocode dafür sieht folgendermaßen aus:

Start

├─› ist achievable?
│     ├─› ja
│     │    ├─› target *= 1 + otpMargin/100
│     │    └─› strategy == smartPower?
│     │         ├─› ja → target = "Sicherheitsaufschlag linear absenkend"
│     │         └─› nein → weiter
│     └─› nein
│          ├─› target *= (1 + otpMargin/100)^2
│          └─› strategy == smartPower?
│               ├─› ja → $target = pinmax
│               └─› nein → weiter
└─› Ende


Das Modul im contrib ist upgedated zur Version 1.59.5
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