diff --git a/fhem/contrib/DS_Starter/76_SolarForecast.pm b/fhem/contrib/DS_Starter/76_SolarForecast.pm
index e2adb0ecc..5de041512 100644
--- a/fhem/contrib/DS_Starter/76_SolarForecast.pm
+++ b/fhem/contrib/DS_Starter/76_SolarForecast.pm
@@ -160,6 +160,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
+ "1.57.0" => "08.08.2025 new option attr graphicControl->scaleMode=X:staple ",
"1.56.0" => "07.08.2025 set MAXINVERTER to 5 ",
"1.55.0" => "06.08.2025 DWD-Weather and DWD-Radiation device new minimum value of attr 'forecastDays' is 2 ".
"checkPlantConfig: check forecastDays of new minimum value ".
@@ -6500,18 +6501,18 @@ sub _attrgraphicControl { ## no critic "not used"
my $cmd = $paref->{cmd};
my $valid = {
- beamPaddingBottom => { comp => '\d+', act => 0 },
- beamPaddingTop => { comp => '\d+', act => 0 },
- beamWidth => { comp => '([2-9][0-9]|100)', act => 0 },
- energyUnit => { comp => '(Wh|kWh)', act => 0 },
- beamHeightlevel => { comp => '(?:[1-3]:(?:[1-9][0-9]*))(?:,(?:[1-3]:(?:[1-9][0-9]*)))*', act => 0 },
- headerDetail => { comp => '.*', act => 1 },
- hourCount => { comp => '([4-9]|1[0-9]|2[0-4])', act => 0 },
- hourStyle => { comp => ':(0{1,2})', act => 0 },
- layoutType => { comp => '(single|double|diff)', act => 0 },
- scaleMode => { comp => '(?:[1-3]:(?:log|lin))(?:,(?:[1-3]:(?:log|lin)))*', act => 0 },
- showDiff => { comp => '(?:[1-3]:(?:top|bottom))(?:,(?:[1-3]:(?:top|bottom)))*', act => 0 },
- spaceSize => { comp => '\d+', act => 0 },
+ beamPaddingBottom => { comp => '\d+', act => 0 },
+ beamPaddingTop => { comp => '\d+', act => 0 },
+ beamWidth => { comp => '([2-9][0-9]|100)', act => 0 },
+ energyUnit => { comp => '(Wh|kWh)', act => 0 },
+ beamHeightlevel => { comp => '(?:[1-3]:(?:[1-9][0-9]*))(?:,(?:[1-3]:(?:[1-9][0-9]*)))*', act => 0 },
+ headerDetail => { comp => '.*', act => 1 },
+ hourCount => { comp => '([4-9]|1[0-9]|2[0-4])', act => 0 },
+ hourStyle => { comp => ':(0{1,2})', act => 0 },
+ layoutType => { comp => '(single|double|diff)', act => 0 },
+ scaleMode => { comp => '(?:[1-3]:(?:log|lin|staple))(?:,(?:[1-3]:(?:log|lin|staple)))*', act => 0 },
+ showDiff => { comp => '(?:[1-3]:(?:top|bottom))(?:,(?:[1-3]:(?:top|bottom)))*', act => 0 },
+ spaceSize => { comp => '\d+', act => 0 },
};
my ($a, $h) = parseParams ($aVal);
@@ -17228,14 +17229,15 @@ sub _beamGraphic {
# lässt sich durch einbetten in eine zusätzliche Table roomoverview eindämmen
# Die Tabelle ist recht schmal angelegt, aber nur so lassen sich Umbrüche erzwingen
- my ($val, $z2, $z3, $z4, $he, $titz2, $titz3);
+ my ($val, $z2, $z3, $z4, $z1, $titz2, $titz3);
$paref->{beampos} = 'top'; # Lagedefinition "über den Balken"
my $ret = q{};
my $colspan = $maxhours + 2;
my $m = $paref->{modulo} % 2;
- $maxVal = 1.1 if(!int $maxVal); # maxVal devision by zero & log(x) Problem
+ $maxVal = 1.1 if(!int $maxVal); # devision by zero & log(x) Problem
+ $maxStVal = 1.1 if(!int $maxStVal); # devision by zero Problem
## zusätzlicher Abstand vor der ersten Reihe
##############################################
@@ -17283,7 +17285,8 @@ sub _beamGraphic {
$ret .= "
| "; # Neue Zeile mit freiem Platz am Anfang
- my $ii = 0;
+ my $ii = 0;
+ my $mbdf = 0;
for my $i (0..($maxhours * 2) - 1) { # gleiche Bedingung wie oben
next if(__dontNightshowSkipSync ($name, $paref, $i));
@@ -17296,8 +17299,9 @@ sub _beamGraphic {
# Berechnung der Zonen
########################
if ($lotype eq 'single') {
- $he = __normBeamHeight ( { val => $maxVal - $hfcg->{$i}{beam1},
+ $z1 = __normBeamHeight ( { val => $maxVal - $hfcg->{$i}{beam1},
maxVal => $maxVal,
+ maxStVal => $maxStVal,
height => $height,
ground => 0,
scalemode => 'lin'
@@ -17312,25 +17316,36 @@ sub _beamGraphic {
# he - freier der Raum über den Balken. spacesz wird nicht verwendet, da bei diesem Typ keine Zahlen über den Balken stehen
# z2 - primärer Balkenwert ggf. mit Icon
# z3 - sekundärer Balkenwert, bei zu kleinem Wert wird der Platz komplett Zone 2 zugeschlagen und nicht angezeigt
- # z2 und z3 nach Bedarf tauschen, wenn sekundärer Balkenwert > primärer Balkenwert
+ # z2 und z3 nach Bedarf tauschen, wenn sekundärer Balkenwert > primärer Balkenwert (außer bei 'staple')
- if ($hfcg->{$i}{beam1} > $hfcg->{$i}{beam2}) {
+ if ($scm eq 'staple') {
$z2 = $hfcg->{$i}{beam1};
$z3 = $hfcg->{$i}{beam2};
$titz2 = qq/title="$hfcg->{0}{beam1txt}"/;
$titz3 = qq/title="$hfcg->{0}{beam2txt}"/;
+ $mbdf = $maxStVal - ($z2 + $z3); # Wertedifferenz abs. Maxwert und größerem Balkenwert
}
- else { # tauschen, Betrag Beam1 < Betrag Beam2
- $z2 = $hfcg->{$i}{beam2};
- $z3 = $hfcg->{$i}{beam1};
- $titz2 = qq/title="$hfcg->{0}{beam2txt}"/;
- $titz3 = qq/title="$hfcg->{0}{beam1txt}"/;
+ else {
+ if ($hfcg->{$i}{beam1} >= $hfcg->{$i}{beam2}) {
+ $z2 = $hfcg->{$i}{beam1};
+ $z3 = $hfcg->{$i}{beam2};
+ $titz2 = qq/title="$hfcg->{0}{beam1txt}"/;
+ $titz3 = qq/title="$hfcg->{0}{beam2txt}"/;
+ }
+ else { # tauschen, Betrag Beam1 < Betrag Beam2
+ $z2 = $hfcg->{$i}{beam2};
+ $z3 = $hfcg->{$i}{beam1};
+ $titz2 = qq/title="$hfcg->{0}{beam2txt}"/;
+ $titz3 = qq/title="$hfcg->{0}{beam1txt}"/;
+ }
+
+ $mbdf = $maxVal - $z2; # Wertedifferenz abs. Maxwert und größerem Balkenwert
}
- $he = __normBeamHeight ( { val => $maxVal - $z2, maxVal => $maxVal, height => $height, ground => 0, scalemode => 'lin' } );
- $z2 = __normBeamHeight ( { val => $z2, maxVal => $maxVal, height => $height, ground => 0, scalemode => $scm } );
- $z3 = __normBeamHeight ( { val => $z3, maxVal => $maxVal, height => $height, ground => 0, scalemode => $scm } );
- $z2 -= $z3 if($scm eq 'lin'); # effektive Stapelhöhe, da $z2 + $z3 übereinander dargestellt wird
+ $z1 = __normBeamHeight ( { val => $mbdf, maxVal => $maxVal, height => $height, ground => 0, scalemode => 'lin' } );
+ $z2 = __normBeamHeight ( { val => $z2, maxVal => $maxVal, height => $height, ground => 0, scalemode => $scm } );
+ $z3 = __normBeamHeight ( { val => $z3, maxVal => $maxVal, height => $height, ground => 0, scalemode => $scm } );
+ $z2 -= $z3 if($scm eq 'lin'); # effektive Stapelhöhe, da $z2 + $z3 übereinander dargestellt wird
if ($scm eq 'log' && $z2) {
my $z3perc = int (100 / $z2 * $z3);
@@ -17382,13 +17397,13 @@ sub _beamGraphic {
$titz2 = qq/title="$hfcg->{0}{beam1txt}"/;
$titz3 = qq/title="$hfcg->{0}{beam2txt}"/;
# Alle vorbesetzen Werte umrechnen auf echte Ausgabe px
- $he = (!$px_pos || !$maxDif) ? 0 : int(($maxDif-$z2) / $maxDif * $px_pos); # Teilung durch 0 vermeiden
- $z2 = ($px_pos - $he) ;
+ $z1 = (!$px_pos || !$maxDif) ? 0 : int(($maxDif-$z2) / $maxDif * $px_pos); # Teilung durch 0 vermeiden
+ $z2 = ($px_pos - $z1) ;
$z4 = (!$px_neg || !$minDif) ? 0 : int((abs($minDif)-$z3) / abs($minDif) * $px_neg); # Teilung durch 0 unbedingt vermeiden
$z3 = ($px_neg - $z4);
# Beiden Zonen die Werte ausgeben könnten muß spacesz als zusätzlicher Raum zugeschlagen werden !
- $he += $spacesz;
+ $z1 += $spacesz;
$z4 += $spacesz if($z3); # komplette Grafik ohne negativ Balken, keine Ausgabe von z3 & z4
}
@@ -17400,14 +17415,14 @@ sub _beamGraphic {
$ret .="\n";
- $he /= 10; # freier der Raum über den Balken
- $he = $he < 20 ? 20 : $he;
+ $z1 /= 10; # freier der Raum über den Balken
+ $z1 = $z1 < 20 ? 20 : $z1;
if ($lotype eq 'single') {
$val = normBeamWidth ($paref, 'beam1', $i, 'beam1');
$ret .=""; # mit width=100% etwas bessere Füllung der Balken
- $ret .="";
+ $ret .=" ";
$ret .="| ".$val;
$ret .=" | ";
@@ -17431,15 +17446,15 @@ sub _beamGraphic {
my $style = "style='padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;";
- $ret .="\n"; # mit width=100% etwas bessere Füllung der Balken
- $ret .=" | "; # Freiraum über den Balken einfügen
+ $ret .="\n"; # mit width=100% etwas bessere Füllung der Balken
+ $ret .=" | "; # Freiraum über den Balken einfügen
- if ($hfcg->{$i}{beam1} > $hfcg->{$i}{beam2}) { # wer ist oben, Beam2 oder Beam1 ? Wert und Farbe für Zone 2 & 3 vorbesetzen
+ if ($hfcg->{$i}{beam1} > $hfcg->{$i}{beam2} || $scm eq 'staple') { # wer ist oben, Beam2 oder Beam1 ? Wert und Farbe für Zone 2 & 3 vorbesetzen
$val = normBeamWidth ($paref, 'beam1', $i, 'beam1');
$color1 = $colorb1;
$style1 = $style." background-color:#$color1; color:#$fcolor1;'";
- if ($z3) { # die Zuweisung können wir uns sparen wenn Zone 3 nachher eh nicht ausgegeben wird
+ if ($z3) { # die Zuweisung können wir uns sparen wenn Zone 3 nachher eh nicht ausgegeben wird
$v = normBeamWidth ($paref, 'beam2', $i, 'beam2');
$color2 = $colorb2;
$style2 = $style." background-color:#$color2; color:#$fcolor2;'";
@@ -17481,7 +17496,7 @@ sub _beamGraphic {
$val = ' 0 ' if($hfcg->{$i}{diff} == 0); # Sonderfall , hier wird die 0 gebraucht !
if ($val) {
- $ret .= "";
+ $ret .= " ";
$ret .= "| ".$val;
$ret .= " | ";
}
@@ -17622,14 +17637,17 @@ sub __normBeamHeight {
my $maxVal = $paref->{maxVal};
my $height = $paref->{height};
my $ground = $paref->{ground} // 0; # eine minimale Balkenhöhe die immer eingehalten werden soll
- my $scalemode = $paref->{scalemode} // 'lin'; # lin / log
+ my $scalemode = $paref->{scalemode} // 'lin'; # lin / log / staple
my $px = 0;
if ($scalemode eq 'lin') {
$px = $ground + (($val / $maxVal) * ($height - $ground));
}
- elsif ($val * 1 > 0) { # logarithmische Anzeige wenn Mode log, kein Logarithmus für negative Zahlen
+ elsif ($scalemode eq 'staple') {
+ $px = $ground + (($val / $maxVal) * ($height - $ground));
+ }
+ elsif ($scalemode eq 'log' && $val * 1 > 0) { # logarithmische Anzeige wenn Mode log, kein Logarithmus für negative Zahlen
$px = $ground + ((log ($val) / log ($maxVal)) * ($height - $ground));
}
@@ -26943,7 +26961,8 @@ to ensure that the system configuration is correct.
| | The strings for each level are separated by commas (see example). |
| | <Level>:lin - linear scaling (default) |
| | <Level>:log - logarithmic scaling |
- | | |
+ | | <Ebene>:staple - The bars are ‘stacked’, with the secondary bar displayed above the primary bar. |
+ | | |
| showDiff | Additional numerical display of the difference '<primary bar content> - <secondary bar content>'. |
| | The specification for each level consists of the level number (1..X), a ':' followed by the position 'top' or 'bottom'. |
| | The strings for each level are separated by commas (see example). |
@@ -29599,7 +29618,8 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
| | Die Strings für jede Ebene werden durch Komma getrennt (siehe Beispiel). |
| | <Ebene>:lin - lineare Skalierung (default) |
| | <Ebene>:log - logarithmische Skalierung |
- | | |
+ | | <Ebene>:staple - die Balken werden 'gestapelt', der sekundäre Balken wird über dem primären Balken dargestellt |
+ | | |
| showDiff | Zusätzliche numerische Anzeige der Differenz '<primärer Balkeninhalt> - <sekundärer Balkeninhalt>'. |
| | Die Angabe für jede Ebene besteht aus der Ebenen-Nummer (1..X), einem ':' gefolgt von der Position 'top' oder 'bottom'. |
| | Die Strings für jede Ebene werden durch Komma getrennt (siehe Beispiel). |
|