diff --git a/fhem/CHANGED b/fhem/CHANGED
index ba747b08a..142791668 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it
+ - feature: 76_SolarForecast: new Attr ctrlNextHoursSoCForecastReadings
- feature: 76_SolarForecast: version 1.42.0 with some new features & fixes
- change: 76_SolarForecast: Attr ctrlStatisticReadings to ctrlSpecialReadings
old 'statistics_.*' readings to 'special_.*',
diff --git a/fhem/FHEM/76_SolarForecast.pm b/fhem/FHEM/76_SolarForecast.pm
index dc1c61572..ac969cc66 100644
--- a/fhem/FHEM/76_SolarForecast.pm
+++ b/fhem/FHEM/76_SolarForecast.pm
@@ -157,6 +157,8 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
+ "1.43.0" => "10.01.2025 graphicShowNight: add possible Time Sync of chart bar level 1 and the other ".
+ "_addDynAttr: minor fix for graphicBeamXContent, new attr ctrlNextHoursSoCForecastReadings ",
"1.42.0" => "07.01.2025 change socslidereg to batsocslidereg, _batChargeRecmd: add value to nexthours ".
"entryGraphic: enrich hfcg hash, __normDecPlaces: use it from/to battery, ".
"setupBatteryDevXX : new icon & show key, colour of icon can be changed separately, maxbatteries set to 3 ".
@@ -527,7 +529,7 @@ my @aconfigs = qw( affectBatteryPreferredCharge affectConsForecastIdentWeekdays
consumerLegend consumerAdviceIcon consumerLink
ctrlAIdataStorageDuration ctrlBackupFilesKeep
ctrlConsRecommendReadings ctrlGenPVdeviation ctrlInterval
- ctrlLanguage ctrlNextDayForecastReadings ctrlShowLink ctrlSolCastAPImaxReq
+ ctrlLanguage ctrlNextDayForecastReadings ctrlNextHoursSoCForecastReadings ctrlShowLink ctrlSolCastAPImaxReq
ctrlSolCastAPIoptimizeReq ctrlSpecialReadings ctrlUserExitFn
setupWeatherDev1 setupWeatherDev2 setupWeatherDev3
disable
@@ -1335,6 +1337,7 @@ sub Initialize {
"ctrlInterval ".
"ctrlLanguage:DE,EN ".
"ctrlNextDayForecastReadings:multiple-strict,$hod ".
+ "ctrlNextHoursSoCForecastReadings ".
"ctrlShowLink:1,0 ".
"ctrlSolCastAPImaxReq:selectnumbers,5,5,60,0,lin ".
"ctrlSolCastAPIoptimizeReq:1,0 ".
@@ -1345,10 +1348,10 @@ sub Initialize {
"graphicBeamHeightLevel1 ".
"graphicBeamHeightLevel2 ".
"graphicBeamWidth:slider,20,5,100 ".
- "graphicBeam1Content: ".
- "graphicBeam2Content: ".
- "graphicBeam3Content: ".
- "graphicBeam4Content: ".
+ "graphicBeam1Content ".
+ "graphicBeam2Content ".
+ "graphicBeam3Content ".
+ "graphicBeam4Content ".
"graphicBeam1Color:colorpicker,RGB ".
"graphicBeam2Color:colorpicker,RGB ".
"graphicBeam3Color:colorpicker,RGB ".
@@ -1369,7 +1372,7 @@ sub Initialize {
"graphicLayoutType:single,double,diff ".
"graphicSelect:both,flow,forecast,none ".
"graphicShowDiff:no,top,bottom ".
- "graphicShowNight:1,0 ".
+ "graphicShowNight:1,0,01 ".
"graphicShowWeather:1,0 ".
"graphicSpaceSize ".
"graphicWeatherColor:colorpicker,RGB ".
@@ -5422,6 +5425,10 @@ sub Attr {
if ($aName eq 'ctrlNextDayForecastReadings') {
deleteReadingspec ($hash, "Tomorrow_Hour.*");
}
+
+ if ($aName eq 'ctrlNextHoursSoCForecastReadings') {
+ deleteReadingspec ($hash, "Battery_NextHour.._SoCforecast_..");
+ }
if ($aName =~ /ctrlBatSocManagement/xs && $init_done) {
my $bn = (split 'ctrlBatSocManagement', $aName)[1];
@@ -6146,6 +6153,7 @@ sub _attrBatteryDev { ## no critic "not used"
readingsDelete ($hash, 'Battery_ChargeRecommended_'.$bn);
readingsDelete ($hash, 'Battery_ChargeRequest_'.$bn);
readingsDelete ($hash, 'Battery_OptimumTargetSoC_'.$bn);
+ deleteReadingspec ($hash, "NextHour.._Bat_${bn}_SoCforecast");
undef @{$data{$name}{current}{batsocslidereg}};
@@ -7293,7 +7301,7 @@ sub _addDynAttr {
## Attributhüllen entfernen
#############################
my @deva = split " ", $modules{$type}{AttrList};
- my $atd = 'setupWeatherDev|setupRadiationAPI|graphicBeam*Content';
+ my $atd = 'setupWeatherDev|setupRadiationAPI|graphicBeam*Content|ctrlNextHoursSoCForecastReadings';
@deva = grep {!/$atd/} @deva;
## Attr setupWeatherDevX / setupRadiationAPI zur Laufzeit hinzufügen
@@ -7310,24 +7318,27 @@ sub _addDynAttr {
push @deva, "setupRadiationAPI:$rdd ";
- ## Attr graphicBeamXContent zur Laufzeit hinzufügen
- #####################################################
- my $gbc = '';
+ ## Attr graphicBeamXContent, ctrlNextDayForecastReadings zur Laufzeit hinzufügen
+ ##################################################################################
+ my $gbc;
+
if (isBatteryUsed ($name)) {
for my $bn (1..$maxbatteries) {
$bn = sprintf "%02d", $bn;
$gbc .= 'batsocforecast_'.$bn.',';
}
+
+ my $hod = join ",", (map { sprintf "%02d", $_} (0..23));
+ push @deva, "ctrlNextHoursSoCForecastReadings:multiple-strict,$hod";
}
- $gbc .= ',' if(!$gbc);
+
$gbc .= 'consumption,consumptionForecast,energycosts,feedincome,gridconsumption,gridfeedin,pvForecast,pvReal';
-
+
push @deva, "graphicBeam1Content:$gbc";
push @deva, "graphicBeam2Content:$gbc";
push @deva, "graphicBeam3Content:$gbc";
push @deva, "graphicBeam4Content:$gbc";
-
$hash->{".AttrList"} = join " ", @deva;
return;
@@ -9861,7 +9872,7 @@ sub _batChargeRecmd {
next if($err);
my $batinstcap = BatteryVal ($hash, $bn, 'binstcap', 0); # installierte Batteriekapazität Wh
- my $soc = BatteryVal ($hash, $bn, 'bcharge', 0); # aktuelle Ladung in %
+ my $csoc = BatteryVal ($hash, $bn, 'bcharge', 0); # aktuelle Ladung in %
my $batoptsoc = ReadingsNum ($name, 'Battery_OptimumTargetSoC_'.$bn, 0); # aktueller optimierter SoC
if (!$inplim || !$batinstcap) {
@@ -9878,8 +9889,7 @@ sub _batChargeRecmd {
debugLog ($paref, 'batteryManagement', "Bat $bn Charge Rcmd - Installed Battery capacity: $batinstcap Wh");
- my $whneed = sprintf "%.0f", ($batinstcap - ($batinstcap * $soc / 100)); # benötigte Energie bis 100% Batteriekapazität Wh
- my $sfmargin = $whneed * 0.25; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
+ my $socwh = sprintf "%.0f", ($batinstcap * $csoc / 100); # aktueller SoC in Wh
## Auswertung für jede kommende Stunde
########################################
@@ -9906,20 +9916,38 @@ sub _batChargeRecmd {
$spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang
- ## SOC-Prognose und Ladeempfehlung
- ####################################
- my $progsoc = sprintf "%.0f", (100 / $batinstcap * ($batinstcap - $whneed)); # Prognose SoC
- $progsoc = $progsoc < $batoptsoc ? $batoptsoc :
- $progsoc < $lowSoc ? $lowSoc :
- $progsoc;
+ ## Ladeempfehlung
+ ###################
+ my $whneed = $batinstcap - $socwh;
+ my $sfmargin = $whneed * 0.25; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
if ( $whneed + $sfmargin >= $spday ) {$rcmd = 1} # Ladeempfehlung wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
if ( !$num && $pvCu - $curcon >= $inplim ) {$rcmd = 1} # Ladeempfehlung wenn akt. PV Leistung >= WR-Leistungsbegrenzung
+
+ ## SOC-Prognose
+ #################
+ $socwh += $rcmd ? $pvfc - $confc : -$confc; # PV Prognose nur einbeziehen wenn Ladeempfehlung
+ $socwh = sprintf "%.0f", $socwh;
+ $socwh = $socwh < 0 ? 0 :
+ $socwh > $batinstcap ? $batinstcap :
+ $socwh;
- my $msg = "(SoC forecast: $progsoc, need: $whneed Wh -> Surplus Day: $spday Wh, Curr PV: $pvCu W, Curr Consumption: $curcon W, Limit: $inplim W)";
+ my $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC
+ $progsoc = $progsoc < $batoptsoc ? $batoptsoc :
+ $progsoc < $lowSoc ? $lowSoc :
+ $progsoc;
+
+ __calcReadingsNextHoursSoCFc ( {name => $name,
+ nhr => $nhr,
+ bn => $bn,
+ progsoc => $progsoc
+ }
+ ); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
+
+ my $msg = "(currsoc: $csoc %, SoCfc: $progsoc %, soc: $socwh Wh, pvfc: $pvfc, confc: $confc, Surp Day: $spday Wh, Curr PV: $pvCu W, Curr Consumption: $curcon W, Limit: $inplim W)";
if ($num) {
- $msg = "(SoC forecast: $progsoc, need: $whneed Wh -> Surplus Day: $spday Wh)";
+ $msg = "(SoCfc: $progsoc %, soc: $socwh Wh, pvfc: $pvfc, confc: $confc, Surp Day: $spday Wh)";
}
else {
storeReading ('Battery_ChargeRecommended_'.$bn, $rcmd); # Reading nur für aktuelle Stunde
@@ -9928,31 +9956,35 @@ sub _batChargeRecmd {
$data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $rcmd;
$data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
- debugLog ($paref, 'batteryManagement', "Bat $bn Charge activation $stt -> $rcmd $msg");
-
- ## Fortschreibung der Prognose als Grundlage für die kommende Stunde
- ######################################################################
- if ($pvfc) {
- if ($today) { # (Rest) heutiger Tag
- $confcss -= $confc;
- $confcss = 0 if($confcss < 0);
- $rodpvfc -= $pvfc;
- }
- else { # nächster Tag
- $tomconfc -= $confc;
- $tomconfc = 0 if($tomconfc < 0);
- $tompvfc -= $pvfc;
- }
- }
-
- $whneed -= sprintf "%.0f", ($rcmd ? $pvfc - $confc : 0); # PV Prognose nur einbeziehen wenn Ladeempfehlung
- $whneed = $whneed < 0 ? 0 : $whneed;
+ debugLog ($paref, 'batteryManagement', "Bat $bn doCharge $stt -> $rcmd $msg");
}
}
return;
}
+################################################################
+# zusätzliche Readings NextHourXX_Bat_XX_ChargeForecast
+# erstellen
+################################################################
+sub __calcReadingsNextHoursSoCFc {
+ my $paref = shift;
+ my $name = $paref->{name};
+ my $nhr = $paref->{nhr}; # nächste Stunde
+ my $bn = $paref->{bn}; # Batterienummer
+ my $progsoc = $paref->{progsoc}; # prognostizierter SoC
+
+ my $hods = AttrVal ($name, 'ctrlNextHoursSoCForecastReadings', '');
+
+ return if(!$hods);
+
+ if (grep { /$nhr/x } split ',', $hods) {
+ storeReading ('Battery_NextHour'.$nhr.'_SoCforecast_'.$bn, $progsoc.' %');
+ }
+
+return;
+}
+
################################################################
# Zusammenfassungen erstellen
################################################################
@@ -12000,16 +12032,15 @@ return;
################################################################
# zusätzliche Readings Tomorrow_HourXX_PVforecast
-# berechnen
+# erstellen
################################################################
sub _calcReadingsTomorrowPVFc {
my $paref = shift;
my $name = $paref->{name};
- my $type = $paref->{type};
my $hash = $defs{$name};
my $h = $data{$name}{nexthours};
- my $hods = AttrVal($name, 'ctrlNextDayForecastReadings', '');
+ my $hods = AttrVal ($name, 'ctrlNextDayForecastReadings', '');
return if(!keys %{$h} || !$hods);
@@ -12755,12 +12786,17 @@ sub entryGraphic {
# Parameter f. Anzeige extrahieren
###################################
- my $width = AttrNum ($name, 'graphicBeamWidth', 20); # zu klein ist nicht problematisch
- my $maxhours = AttrNum ($name, 'graphicHourCount', 24);
- my $alias = AttrVal ($name, 'alias', $name); # Linktext als Aliasname oder Devicename setzen
- my $w = $width * $maxhours; # gesammte Breite der Ausgabe , WetterIcon braucht ca. 34px
- my $offset = -1 * AttrNum ($name, 'graphicHistoryHour', $histhourdef);
- my $dlink = qq{$alias};
+ my $width = AttrNum ($name, 'graphicBeamWidth', 20); # zu klein ist nicht problematisch
+ my $maxhours = AttrNum ($name, 'graphicHourCount', 24);
+ my $alias = AttrVal ($name, 'alias', $name); # Linktext als Aliasname oder Devicename setzen
+
+ AttrVal ($name, 'graphicShowNight', 0) =~ /(.)(.)?/xs;
+ my $show_night = $1 // 0;
+ my $layersync = $2 // 0;
+
+ my $w = $width * $maxhours; # gesammte Breite der Ausgabe , WetterIcon braucht ca. 34px
+ my $offset = -1 * AttrNum ($name, 'graphicHistoryHour', $histhourdef);
+ my $dlink = qq{$alias};
if (!$gsel) {
$gsel = AttrVal ($name, 'graphicSelect', 'both'); # Auswahl der anzuzeigenden Grafiken
@@ -12795,7 +12831,8 @@ sub entryGraphic {
width => $width,
fsize => AttrNum ($name, 'graphicSpaceSize', 24),
maxVal => AttrNum ($name, 'graphicBeam1MaxVal', 0), # dyn. Anpassung der Balkenhöhe oder statisch ?
- show_night => AttrNum ($name, 'graphicShowNight', 0), # alle Balken (Spalten) anzeigen ?
+ layersync => $layersync, # Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
+ show_night => $show_night, # alle Balken (Spalten) anzeigen ?
show_diff => AttrVal ($name, 'graphicShowDiff', 'no'), # zusätzliche Anzeige $di{} in allen Typen
weather => AttrNum ($name, 'graphicShowWeather', 1), # Wetter Icons anzeigen
colorw => AttrVal ($name, 'graphicWeatherColor', $wthcolddef), # Wetter Icon Farbe Tag
@@ -14551,14 +14588,7 @@ sub _beamGraphic {
my $ii = 0;
for my $i (0..($maxhours * 2) - 1) { # gleiche Bedingung wie oben
- if (!$show_night && $hfcg->{$i}{weather} > 99 &&
- !$hfcg->{$i}{beam1} && !$hfcg->{$i}{beam2}) {
- next;
- }
-
- if (!$show_night && $hfcg->{$i}{weather} > 99) {
- $paref->{barsync}{$i} = 1;
- }
+ next if(__dontNightshowSkipSync ($name, $paref, $i));
$ii++; # wieviele Stunden haben wir bisher angezeigt ?
last if($ii > $maxhours || $ii > $barcount); # vorzeitiger Abbruch
@@ -14566,9 +14596,9 @@ sub _beamGraphic {
$val = normBeamWidth ($hfcg->{$i}{diff}, $kw, $hfcg->{$i}{weather});
if ($val ne ' ') { # Forum: https://forum.fhem.de/index.php/topic,117864.msg1166215.html#msg1166215
- $val = $hfcg->{$i}{diff} < 0 ? ''.$val.'' :
- $val > 0 ? '+'.$val :
- $val; # negative Zahlen in Fettschrift, 0 aber ohne +
+ $val = $hfcg->{$i}{diff} < 0 ? ''.$val.'' :
+ $val > 0 ? '+' .$val :
+ $val; # negative Zahlen in Fettschrift, 0 aber ohne +
}
$ret .= "
$val | ";
@@ -14582,14 +14612,7 @@ sub _beamGraphic {
my $ii = 0;
for my $i (0..($maxhours * 2) - 1) { # gleiche Bedingung wie oben
- if (!$show_night && $hfcg->{$i}{weather} > 99 &&
- !$hfcg->{$i}{beam1} && !$hfcg->{$i}{beam2}) {
- next;
- }
-
- if (!$show_night && $hfcg->{$i}{weather} > 99) {
- $paref->{barsync}{$i} = 1;
- }
+ next if(__dontNightshowSkipSync ($name, $paref, $i));
$ii++;
last if($ii > $maxhours || $ii > $barcount);
@@ -14849,6 +14872,42 @@ sub _beamGraphic {
return $ret;
}
+############################################################################################
+# liefert Signal ob Werte angezeigt werden sollen obwohl
+# die Nachtstunden nicht angezeigt werden sowie die
+# bei Synchronisation der nachfolgenden Balkendiagramm-Ebenen
+# mit Balkendiagramm-Ebene 1
+#
+# skip = 0 - Wert soll angezeigt werden
+# skip = 1 - Wert soll nicht angezeigt werden
+# paref->skip = 1 - Synchronisation Anzeige des Balkens in nächsten Ebenen verhindern
+# paref->noSkip = 1 - Synchronisation Anzeige des Balkens in nächsten Ebenen erzwingen
+#
+############################################################################################
+sub __dontNightshowSkipSync {
+ my $name = shift;
+ my $paref = shift;
+ my $i = shift;
+
+ my $skip = 0;
+
+ if ($paref->{skip}{$i} && !$paref->{noSkip}{$i}) {
+ $skip = 1 if($paref->{layersync}); # Anwendung bei Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
+ }
+ elsif (!$paref->{show_night} && $paref->{hfcg}{$i}{weather} > 99 &&
+ !$paref->{hfcg}{$i}{beam1} && !$paref->{hfcg}{beam2} &&
+ !$paref->{noSkip}{$i}) {
+
+ $paref->{skip}{$i} = 1 if($paref->{layersync}); # Anwendung bei Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
+ $skip = 1;
+ }
+ else {
+ $paref->{noSkip}{$i} = 1 if($paref->{layersync}); # Anwendung bei Zeitsynchronisation zwischen Ebene 1 und den folgenden Balkengrafikebenen
+ }
+
+return $skip;
+}
+
################################################################
# Wetter Icon Zeile
################################################################
@@ -14878,11 +14937,12 @@ sub __weatherOnBeam {
debugLog ($paref, 'graphic', "weather id beam number >$i< (start hour $hfcg->{$i}{time_str}): wid $hfcg->{$i}{weather} / wcc $wcc") if($ii < $maxhours);
- if (!$show_night && $hfcg->{$i}{weather} > 99 &&
- !$hfcg->{$i}{beam1} && !$hfcg->{$i}{beam2}) { # Lässt Nachticons aber noch durch wenn es einen Wert gibt
- debugLog ($paref, 'graphic', "Weather position >$i< is skipped (condition ‘no night display’)") if($ii < $maxhours);
- next;
- };
+ my $skip = __dontNightshowSkipSync ($name, $paref, $i);
+
+ if ($skip) {
+ debugLog ($paref, 'graphic', "Weather position >$i< is skipped due to don't show night condition") if($ii < $maxhours);
+ next;
+ }
$ii++; # wieviele Stunden Icons haben sind beechnet?
last if($ii > $maxhours || $ii > $barcount);
@@ -14904,7 +14964,7 @@ sub __weatherOnBeam {
debugLog ($paref, "graphic", "unknown weather id: ".$hfcg->{$i}{weather}.", please inform the maintainer");
}
- $icon_name .= $hfcg->{$i}{weather} < 100 ? '@'.$colorw : '@'.$colorwn;
+ $icon_name .= $hfcg->{$i}{weather} < 100 ? '@'.$colorw : '@'.$colorwn;
my $val = FW_makeImage ($icon_name) // q{};
if ($val =~ /title="$icon_name"/xs) { # passendes Icon beim User nicht vorhanden ! ( attr web iconPath falsch/prüfen/update ? )
@@ -14984,13 +15044,14 @@ sub __batRcmdOnBeam {
$ret .= " | "; # freier Platz am Anfang
my $ii = 0;
-
+
for my $i (0..($maxhours * 2) - 1) {
- if (!$show_night && $hfcg->{$i}{weather} > 99 &&
- !$hfcg->{$i}{beam1} && !$hfcg->{$i}{beam2}) {
+ my $skip = __dontNightshowSkipSync ($name, $paref, $i);
+
+ if ($skip) {
debugLog ($paref, 'graphic', "Battery $bn recommandation pos >$i< skipped due to don't show night condition") if($ii < $maxhours);
- next;
- };
+ next;
+ }
$ii++; # wieviele Stunden Icons sind bisher beechnet?
last if($ii > $maxhours || $ii > $barcount);
@@ -19325,7 +19386,7 @@ return ConsumerVal ($hash, $c, 'isConsumptionRecommended', 0);
sub isBatteryUsed {
my $name = shift;
- my $valid;
+ my $valid = 0;
for my $bn (1..$maxbatteries) {
$bn = sprintf "%02d", $bn;
@@ -22449,6 +22510,23 @@ to ensure that the system configuration is correct.
# creates readings for hour 09 (08:00-09:00) and 11 (10:00-11:00) of the coming day
+
+
+
+
+ ctrlNextHoursSoCForecastReadings <00,02,..,23>
+ If set, readings of the form Battery_NextHourXX_SoCforecast_BN are created if a battery is registered
+ in the SolarForecast device (see attr <name> setupBatteryDevXX ).
+ These readings contain the predicted SoC values (%) for the selected hours.
+ Where 'XX' is the hour in the future starting from the current hour (00) and 'BN' is the number of the registered battery.
+
+
+
+ Example:
+ attr <name> ctrlNextHoursSoCForecastReadings 00,03,12,18
+ # creates readings for the current hour (00) and the following hours +03, +12 and +18.
+
+
@@ -22922,7 +23000,7 @@ to ensure that the system configuration is correct.
-
+
both | displays the header, consumer legend, energy flow and prediction graph (default) |
flow | displays the header, the consumer legend and energy flow graphic |
forecast | displays the header, the consumer legend and the prediction graphic |
@@ -22942,10 +23020,19 @@ to ensure that the system configuration is correct.
- graphicShowNight
- Show/hide the night hours without values in the bar chart.
- If the selected bar contents contain a value in the night hours, these bars are also displayed if
- graphicShowNight=0.
- (default: 0 (hide))
+ Display or hide the night hours in the bar chart.
+
+
+
+
+
+ 0 | no display of night hours if no value is to be displayed (default) |
+ | If the selected content contains a value, these bars are still displayed. |
+ 01 | Like ‘0’, but time synchronisation takes place between the level 1 |
+ | and the subsequent bar chart level. |
+ 1 | the night hours are always displayed |
+
+
@@ -24924,6 +25011,23 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
# erstellt Readings für die Stunde 09 (08:00-09:00) und 11 (10:00-11:00) des kommenden Tages
+
+
+
+
+ - ctrlNextHoursSoCForecastReadings <00,02,..,23>
+ Wenn gesetzt, werden Readings der Form Battery_NextHourXX_SoCforecast_BN erstellt sofern eine Batterie im
+ SolarForecast-Device registriert ist (siehe attr <name> setupBatteryDevXX ).
+ Diese Readings enthalten die prognostizierten SoC-Werte (%) der ausgewählten Stunden.
+ Dabei ist 'XX' die Stunde in der Zukunft ausgehend von der aktuellen Stunde (00) und 'BN' die Nummer der registrierten Batterie.
+
+
+
+ Beispiel:
+ attr <name> ctrlNextHoursSoCForecastReadings 00,03,12,18
+ # erstellt Readings für die aktuelle Stunde (00) sowie die nachfolgenden Stunden +03, +12 und +18.
+
+
@@ -25395,7 +25499,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
-
+
both | zeigt den Header, die Verbraucherlegende, Energiefluß- und Vorhersagegrafik an (default) |
flow | zeigt den Header, die Verbraucherlegende und Energieflußgrafik an |
forecast | zeigt den Header, die Verbraucherlegende und die Vorhersagegrafik an |
@@ -25415,10 +25519,19 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
- graphicShowNight
- Anzeigen/Verbergen der Nachtstunden ohne Werte in der Balkengrafik.
- Sofern die ausgewählten Balkeninhalte in den Nachtstunden einen Wert enthalten, werden diese Balken
- auch im Fall graphicShowNight=0 dargestellt.
- (default: 0 (verbergen))
+ Anzeigen oder Verbergen der Nachtstunden in der Balkengrafik.
+
+
+
+
+
+ 0 | keine Anzeige der Nachtstunden sofern kein Wert anzuzeigen ist (default) |
+ | Sofern die ausgewählten Inhalte einen Wert enthalten, werden diese Balken dennoch dargestellt. |
+ 01 | Wie '0', es findet jedoch eine Zeitsynchronisation zwischen der Ebene 1 |
+ | und der nachfolgenden Balkengrafikebene statt. |
+ 1 | Nachtstunden werden immer angezeigt |
+
+
diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm
index c132b145d..ac969cc66 100644
--- a/fhem/contrib/DS_Starter/76_SolarForecast.pm
+++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm
@@ -157,7 +157,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
- "1.43.0" => "09.01.2025 graphicShowNight: add possible Time Sync of chart bar level 1 and the other ".
+ "1.43.0" => "10.01.2025 graphicShowNight: add possible Time Sync of chart bar level 1 and the other ".
"_addDynAttr: minor fix for graphicBeamXContent, new attr ctrlNextHoursSoCForecastReadings ",
"1.42.0" => "07.01.2025 change socslidereg to batsocslidereg, _batChargeRecmd: add value to nexthours ".
"entryGraphic: enrich hfcg hash, __normDecPlaces: use it from/to battery, ".
@@ -9889,7 +9889,7 @@ sub _batChargeRecmd {
debugLog ($paref, 'batteryManagement', "Bat $bn Charge Rcmd - Installed Battery capacity: $batinstcap Wh");
- my $whneed = sprintf "%.0f", ($batinstcap - ($batinstcap * $csoc / 100)); # benötigte Energie bis 100% Batteriekapazität Wh
+ my $socwh = sprintf "%.0f", ($batinstcap * $csoc / 100); # aktueller SoC in Wh
## Auswertung für jede kommende Stunde
########################################
@@ -9916,11 +9916,24 @@ sub _batChargeRecmd {
$spday = 0 if($spday < 0); # PV Überschuß Prognose bis Sonnenuntergang
- ## SOC-Prognose und Ladeempfehlung
- ####################################
- my $progsoc = sprintf "%.0f", (100 / $batinstcap * ($batinstcap - $whneed)); # Prognose SoC
- $progsoc = !$num ? $csoc : # Stunde 00 (aktuelle) -> $progsoc = $csoc
- $progsoc < $batoptsoc ? $batoptsoc :
+ ## Ladeempfehlung
+ ###################
+ my $whneed = $batinstcap - $socwh;
+ my $sfmargin = $whneed * 0.25; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
+
+ if ( $whneed + $sfmargin >= $spday ) {$rcmd = 1} # Ladeempfehlung wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
+ if ( !$num && $pvCu - $curcon >= $inplim ) {$rcmd = 1} # Ladeempfehlung wenn akt. PV Leistung >= WR-Leistungsbegrenzung
+
+ ## SOC-Prognose
+ #################
+ $socwh += $rcmd ? $pvfc - $confc : -$confc; # PV Prognose nur einbeziehen wenn Ladeempfehlung
+ $socwh = sprintf "%.0f", $socwh;
+ $socwh = $socwh < 0 ? 0 :
+ $socwh > $batinstcap ? $batinstcap :
+ $socwh;
+
+ my $progsoc = sprintf "%.1f", (100 * $socwh / $batinstcap); # Prognose SoC
+ $progsoc = $progsoc < $batoptsoc ? $batoptsoc :
$progsoc < $lowSoc ? $lowSoc :
$progsoc;
@@ -9931,15 +9944,10 @@ sub _batChargeRecmd {
}
); # Readings NextHourXX_Bat_XX_ChargeForecast erstellen
- my $sfmargin = $whneed * 0.25; # Sicherheitszuschlag: X% der benötigten Ladeenergie (Wh)
-
- if ( $whneed + $sfmargin >= $spday ) {$rcmd = 1} # Ladeempfehlung wenn benötigte Ladeenergie >= Restüberschuß des Tages zzgl. Sicherheitsaufschlag
- if ( !$num && $pvCu - $curcon >= $inplim ) {$rcmd = 1} # Ladeempfehlung wenn akt. PV Leistung >= WR-Leistungsbegrenzung
-
- my $msg = "(SoC forecast: $progsoc, need: $whneed Wh -> Surplus Day: $spday Wh, Curr PV: $pvCu W, Curr Consumption: $curcon W, Limit: $inplim W)";
+ my $msg = "(currsoc: $csoc %, SoCfc: $progsoc %, soc: $socwh Wh, pvfc: $pvfc, confc: $confc, Surp Day: $spday Wh, Curr PV: $pvCu W, Curr Consumption: $curcon W, Limit: $inplim W)";
if ($num) {
- $msg = "(SoC forecast: $progsoc, need: $whneed Wh -> Surplus Day: $spday Wh)";
+ $msg = "(SoCfc: $progsoc %, soc: $socwh Wh, pvfc: $pvfc, confc: $confc, Surp Day: $spday Wh)";
}
else {
storeReading ('Battery_ChargeRecommended_'.$bn, $rcmd); # Reading nur für aktuelle Stunde
@@ -9948,25 +9956,7 @@ sub _batChargeRecmd {
$data{$name}{nexthours}{'NextHour'.$nhr}{'rcdchargebat'.$bn} = $rcmd;
$data{$name}{nexthours}{'NextHour'.$nhr}{'soc'.$bn} = $progsoc;
- debugLog ($paref, 'batteryManagement', "Bat $bn Charge activation $stt -> $rcmd $msg");
-
- ## Fortschreibung der Prognose als Grundlage für die kommende Stunde
- ######################################################################
- if ($pvfc) {
- if ($today) { # (Rest) heutiger Tag
- $confcss -= $confc;
- $confcss = 0 if($confcss < 0);
- $rodpvfc -= $pvfc;
- }
- else { # nächster Tag
- $tomconfc -= $confc;
- $tomconfc = 0 if($tomconfc < 0);
- $tompvfc -= $pvfc;
- }
- }
-
- $whneed -= sprintf "%.0f", ($rcmd ? $pvfc - $confc : 0); # PV Prognose nur einbeziehen wenn Ladeempfehlung
- $whneed = $whneed < 0 ? 0 : $whneed;
+ debugLog ($paref, 'batteryManagement', "Bat $bn doCharge $stt -> $rcmd $msg");
}
}