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.
      - + @@ -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. +

      + +
        +
    • 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
      + + + + + + +
      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.
      - + @@ -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. +

      + +
        +
    • 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
      + + + + + + +
      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"); } }