2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-09 20:57:11 +00:00

76_SolarForecast: graphicHeaderOwnspec: can add set/attr commands, new setter consumerNewPlanning

git-svn-id: https://svn.fhem.de/fhem/trunk@28174 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-11-15 19:36:28 +00:00
parent 1fb994d013
commit 4db23a2307
2 changed files with 279 additions and 111 deletions

View File

@ -1,5 +1,7 @@
# 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: graphicHeaderOwnspec: can add set/attr commands,
new setter consumerNewPlanning
- feature: 72_FB_CALLMONITOR commandRef
- feature: 72_FRITZBOX set <name> lockFilterProfile ...
- feature: 72_FRITZBOX set <name> energyMode ...

View File

@ -94,6 +94,9 @@ BEGIN {
FmtDateTime
FW_makeImage
getKeyValue
getAllAttr
getAllGets
getAllSets
HttpUtils_NonblockingGet
init_done
InternalTimer
@ -119,8 +122,10 @@ BEGIN {
FW_directNotify
FW_ME
FW_subdir
FW_pH
FW_room
FW_detail
FW_widgetFallbackFn
FW_wname
)
);
@ -144,6 +149,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
"1.1.0" => "14.11.2023 graphicHeaderOwnspec: possible add set/attr commands, new setter consumerNewPlanning ",
"1.0.10" => "31.10.2023 fix warnings, edit comref ",
"1.0.9" => "29.10.2023 _aiGetSpread: set spread from 50 to 20 ",
"1.0.8" => "22.10.2023 codechange: add central readings store array, new function storeReading, writeCacheToFile ".
@ -442,6 +448,8 @@ my $kJtokWh = 0.00027778;
my $defmaxvar = 0.5; # max. Varianz pro Tagesberechnung Autokorrekturfaktor
my $definterval = 70; # Standard Abfrageintervall
my $defslidenum = 3; # max. Anzahl der Arrayelemente in Schieberegistern
my $webCmdFn = 'FW_widgetFallbackFn'; # FHEMWEB Widgets Funktion
my @attrreadings = (); # Array der Hilfsreadings als Attributspeicher
my $pvhcache = $attr{global}{modpath}."/FHEM/FhemUtils/PVH_SolarForecast_"; # Filename-Fragment für PV History (wird mit Devicename ergänzt)
my $pvccache = $attr{global}{modpath}."/FHEM/FhemUtils/PVC_SolarForecast_"; # Filename-Fragment für PV Circular (wird mit Devicename ergänzt)
@ -528,12 +536,15 @@ my @dd = qw( none
radiationProcess
saveData2Cache
);
my $allwidgets = 'icon|sortable|uzsu|knob|noArg|time|text|slider|multiple|select|bitfield|widgetList|colorpicker';
# Steuerhashes
###############
my %hset = ( # Hash der Set-Funktion
consumerImmediatePlanning => { fn => \&_setconsumerImmediatePlanning },
consumerNewPlanning => { fn => \&_setconsumerNewPlanning },
currentWeatherDev => { fn => \&_setcurrentWeatherDev },
currentRadiationAPI => { fn => \&_setcurrentRadiationAPI },
modulePeakString => { fn => \&_setmodulePeakString },
@ -1302,6 +1313,7 @@ sub Set {
my $ipai = isPrepared4AI ($hash);
$setlist = "Unknown argument $opt, choose one of ".
"consumerImmediatePlanning:$coms ".
"consumerNewPlanning:$coms ".
"currentWeatherDev:$fcd ".
"currentRadiationAPI:$rdd ".
"currentBatteryDev:textField-long ".
@ -1379,7 +1391,7 @@ sub _setconsumerImmediatePlanning { ## no critic "not used"
my $type = $paref->{type};
my $opt = $paref->{opt};
my $c = $paref->{prop};
my $evt = $paref->{prop1} // 1;
my $evt = $paref->{prop1} // 0; # geändert V 1.1.0 - 1 -> 0
return qq{no consumer number specified} if(!$c);
return qq{no valid consumer id "$c"} if(!ConsumerVal ($hash, $c, "name", ""));
@ -1430,6 +1442,29 @@ sub _setconsumerImmediatePlanning { ## no critic "not used"
return;
}
################################################################
# Setter consumerNewPlanning
################################################################
sub _setconsumerNewPlanning { ## no critic "not used"
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $c = $paref->{prop};
my $evt = $paref->{prop1} // 0; # geändert V 1.1.0 - 1 -> 0
return qq{no consumer number specified} if(!$c);
return qq{no valid consumer id "$c"} if(!ConsumerVal ($hash, $c, 'name', ''));
if ($c) {
deleteConsumerPlanning ($hash, $c);
writeCacheToFile ($hash, 'consumers', $csmcache.$name); # Cache File Consumer schreiben
}
centralTask ($hash, $evt);
return;
}
################################################################
# Setter currentWeatherDev (Wetterdaten)
################################################################
@ -2280,7 +2315,7 @@ sub _setreset { ## no critic "not used"
delete $data{$type}{$name}{current}{powerbatin};
delete $data{$type}{$name}{current}{batcharge};
writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben
writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben
}
if ($prop eq 'currentInverterDev') {
@ -2289,7 +2324,7 @@ sub _setreset { ## no critic "not used"
writeCacheToFile ($hash, "plantconfig", $plantcfg.$name); # Anlagenkonfiguration File schreiben
}
if ($prop eq 'consumerPlanning') { # Verbraucherplanung resetten
if ($prop eq 'consumerPlanning') { # Verbraucherplanung resetten
my $c = $paref->{prop1} // ""; # bestimmten Verbraucher setzen falls angegeben
if ($c) {
@ -2320,7 +2355,7 @@ sub _setreset { ## no critic "not used"
}
}
writeCacheToFile ($hash, "consumers", $csmcache.$name); # Cache File Consumer schreiben
writeCacheToFile ($hash, "consumers", $csmcache.$name); # Cache File Consumer schreiben
}
createAssociatedWith ($hash);
@ -3860,7 +3895,8 @@ sub _getlistPVHistory {
my $ret = listDataPool ($hash, 'pvhist', $arg);
$ret .= lineFromSpaces ($ret, 20);
$ret =~ s/\n/<br>/g;
return $ret;
}
@ -3886,7 +3922,7 @@ sub _getlistNextHours {
my $ret = listDataPool ($hash, 'nexthours');
$ret .= lineFromSpaces ($ret, 10);
return $ret;
}
@ -5031,7 +5067,10 @@ sub _specialActivities {
deleteReadingspec ($hash, "Today_MaxPVforecast.*");
deleteReadingspec ($hash, "Today_PVdeviation");
deleteReadingspec ($hash, "Today_PVreal");
for my $atr (@attrreadings) {
deleteReadingspec ($hash, $atr);
}
for my $n (1..24) {
$n = sprintf "%02d", $n;
@ -9072,6 +9111,9 @@ sub __createOwnSpec {
my $show = $hdrDetail =~ /all|own/xs ? 1 : 0;
return if(!$spec || !$show);
my $allsets = getAllSets ($name);
my $allattrs = getAllAttr ($name);
my @fields = split (/\s+/sx, $spec);
@ -9102,27 +9144,37 @@ sub __createOwnSpec {
next;
}
($v->{$k}, $u->{$k}) = split /\s+/, ReadingsVal ($name, $h->{$k}{rdg}, '');
}
if ($uatr eq 'kWh') {
for (my $r = 0 ; $r < $vinr; $r++) {
next if(!$u->{$r});
if ($u->{$r} =~ /^Wh/xs) {
$v->{$r} = sprintf "%.1f",($v->{$r} / 1000);
$u->{$r} = 'kWh';
my $setcmd = ___getFWwidget ($name, $h->{$k}{rdg}, $allsets, 'set');
if ($setcmd) {
$v->{$k} = $setcmd;
$u->{$k} = q{};
next;
}
my $attrcmd = ___getFWwidget ($name, $h->{$k}{rdg}, $allattrs, 'attr');
if ($attrcmd) {
$v->{$k} = $attrcmd;
$u->{$k} = q{};
next;
}
($v->{$k}, $u->{$k}) = split /\s+/, ReadingsVal ($name, $h->{$k}{rdg}, ' ');
next if(!$u->{$k});
if ($uatr eq 'kWh') {
if ($u->{$k} =~ /^Wh/xs) {
$v->{$k} = sprintf "%.1f",($v->{$k} / 1000);
$u->{$k} = 'kWh';
}
}
}
if ($uatr eq 'Wh') {
for (my $r = 0 ; $r < $vinr; $r++) {
next if(!$u->{$r});
if ($u->{$r} =~ /^kWh/xs) {
$v->{$r} = sprintf "%.0f",($v->{$r} * 1000);
$u->{$r} = 'Wh';
if ($uatr eq 'Wh') {
if ($u->{$k} =~ /^kWh/xs) {
$v->{$k} = sprintf "%.0f",($v->{$k} * 1000);
$u->{$k} = 'Wh';
}
}
}
@ -9143,6 +9195,67 @@ sub __createOwnSpec {
return $ownv;
}
################################################################
# liefert ein FHEMWEB set/attr Widget zurück
################################################################
sub ___getFWwidget {
my $name = shift;
my $elm = shift; # Element
my $allc = shift; # Kommandovorrat -> ist Element enthalten?
my $ctyp = shift // 'set'; # Kommandotyp: set/attr
my $widget = '';
my ($current, $reading);
if ($allc =~ /$elm:?(.*?)\s/xs) {
my $arg = $1;
$arg = 'textFieldNL' if(!$arg);
if ($arg !~ /^\#/xs && $arg !~ /^$allwidgets/xs) {
$arg = '#,'.$arg;
}
if ($ctyp eq 'attr') {
$current = AttrVal ($name, $elm, '');
$reading = '.'.$elm;
push @attrreadings, $reading;
readingsSingleUpdate ($defs{$name}, $reading, $current, 0);
}
no strict "refs"; ## no critic 'NoStrict'
$widget = &{$webCmdFn} ($FW_wname, $name, "", $elm, $arg);
use strict "refs";
if ($widget) {
$widget =~ s,^<td[^>]*>(.*)</td>$,$1,x;
$widget =~ s,></div>, type='$ctyp'></div>,x;
}
else {
$widget = FW_pH ("cmd=$ctyp $name $elm", $elm, 0, "", 1, 1);
}
if ($ctyp eq 'attr') {
my ($sc) = $widget =~ /current='(.*?)'/xs;
my ($sr) = $widget =~ /reading='(.*?)'/xs;
$widget =~ s/$sc/$current/ if(defined $sc);
$widget =~ s/$sr/$reading/ if(defined $sr);
}
if ($arg eq 'textField' || $arg eq 'textField-long') { # Label (Reading) ausblenden -> siehe fhemweb.js function FW_createTextField Zeile 1657
$widget =~ s/arg='textField/arg='textFieldNL/xs;
}
if ($arg =~ 'slider') { # Widget slider in selectnumbers für Kopfgrafik umsetzen
my ($wid, $min, $step, $max, $float) = split ",", $arg;
$widget =~ s/arg='(.*?)'/arg='selectnumbers,$min,$step,$max,0,lin'/xs;
}
}
return $widget;
}
################################################################
# Consumer in forecastGraphic (Balken) anzeigen
# (Hat zur Zeit keine Wirkung !)
@ -9448,8 +9561,8 @@ sub _beamGraphicFirstHour {
my $day;
my $t = NexthoursVal ($hash, "NextHour00", "starttime", '0000-00-00 24');
my ($year,$month,$day_str,$thishour) = $t =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x;
my $stt = NexthoursVal ($hash, "NextHour00", "starttime", '0000-00-00 24');
my ($year,$month,$day_str,$thishour) = $stt =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x;
my ($val1,$val2,$val3,$val4) = (0,0,0,0);
$thishour++;
@ -9489,7 +9602,7 @@ sub _beamGraphicFirstHour {
$val3 = CircularVal ($hash, $hfcg->{0}{time_str}, 'gcons', 0);
$val4 = CircularVal ($hash, $hfcg->{0}{time_str}, 'confc', 0);
$hfcg->{0}{weather} = CircularVal ($hash, $hfcg->{0}{time_str}, "weatherid", 999);
$hfcg->{0}{weather} = CircularVal ($hash, $hfcg->{0}{time_str}, 'weatherid', 999);
#$val4 = (ReadingsVal($name,"ThisHour_IsConsumptionRecommended",'no') eq 'yes' ) ? $icon : 999;
}
@ -9554,14 +9667,14 @@ sub _beamGraphicRemainingHours {
$hfcg->{$i}{wcc} = HistoryVal ($hash, $ds, $hfcg->{$i}{time_str}, 'wcc', '-');
}
else {
$nh = sprintf('%02d', $i+$offset);
$nh = sprintf '%02d', $i + $offset;
}
}
else {
$nh = sprintf('%02d', $i);
$nh = sprintf '%02d', $i;
}
if (defined($nh)) {
if (defined $nh) {
$val1 = NexthoursVal ($hash, 'NextHour'.$nh, 'pvfc', 0);
$val4 = NexthoursVal ($hash, 'NextHour'.$nh, 'confc', 0);
$hfcg->{$i}{weather} = NexthoursVal ($hash, 'NextHour'.$nh, 'weatherid', 999);
@ -9638,15 +9751,15 @@ sub _beamGraphic {
if($show_diff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch
$ret .= "<tr class='$htr{$m}{cl}'><td class='solarfc'></td>";
my $ii;
for my $i (0..($maxhours*2)-1) { # gleiche Bedingung wie oben
next if (!$show_night && ($hfcg->{$i}{weather} > 99)
&& !$hfcg->{$i}{beam1}
&& !$hfcg->{$i}{beam2});
for my $i (0..($maxhours * 2) - 1) { # gleiche Bedingung wie oben
next if(!$show_night && $hfcg->{$i}{weather} > 99
&& !$hfcg->{$i}{beam1}
&& !$hfcg->{$i}{beam2});
$ii++; # wieviele Stunden haben wir bisher angezeigt ?
last if ($ii > $maxhours); # vorzeitiger Abbruch
$val = formatVal6($hfcg->{$i}{diff},$kw,$hfcg->{$i}{weather});
$val = formatVal6 ($hfcg->{$i}{diff}, $kw, $hfcg->{$i}{weather});
if ($val ne '&nbsp;') { # Forum: https://forum.fhem.de/index.php/topic,117864.msg1166215.html#msg1166215
$val = $hfcg->{$i}{diff} < 0 ? '<b>'.$val.'<b/>' :
@ -9663,11 +9776,10 @@ sub _beamGraphic {
my $ii = 0;
for my $i (0..($maxhours*2)-1) { # gleiche Bedingung wie oben
next if (!$show_night && defined($hfcg->{$i}{weather})
&& ($hfcg->{$i}{weather} > 99)
&& !$hfcg->{$i}{beam1}
&& !$hfcg->{$i}{beam2});
for my $i (0..($maxhours * 2) - 1) { # gleiche Bedingung wie oben
next if(!$show_night && $hfcg->{$i}{weather} > 99
&& !$hfcg->{$i}{beam1}
&& !$hfcg->{$i}{beam2});
$ii++;
last if ($ii > $maxhours);
@ -9768,7 +9880,7 @@ sub _beamGraphic {
$ret .="<td style='text-align: center; padding-left:1px; padding-right:1px; margin:0px; vertical-align:bottom; padding-top:0px'>\n";
if ($lotype eq 'single') {
$val = formatVal6($hfcg->{$i}{beam1},$kw,$hfcg->{$i}{weather});
$val = formatVal6 ($hfcg->{$i}{beam1}, $kw, $hfcg->{$i}{weather});
$ret .="<table width='100%' height='100%'>"; # mit width=100% etwas bessere Füllung der Balken
$ret .="<tr class='$htr{$m}{cl}' style='height:".$he."px'>";
@ -9793,32 +9905,32 @@ sub _beamGraphic {
if ($lotype eq 'double') {
my ($color1, $color2, $style1, $style2, $v);
my $style = "style='padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;";
my $style = "style='padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;";
$ret .="<table width='100%' height='100%'>\n"; # mit width=100% etwas bessere Füllung der Balken
# der Freiraum oben kann beim größten Balken ganz entfallen
$ret .="<tr class='$htr{$m}{cl}' style='height:".$he."px'><td class='solarfc'></td></tr>" if ($he);
$ret .="<tr class='$htr{$m}{cl}' style='height:".$he."px'><td class='solarfc'></td></tr>" if($he);
if($hfcg->{$i}{beam1} > $hfcg->{$i}{beam2}) { # wer ist oben, Beam2 oder Beam1 ? Wert und Farbe für Zone 2 & 3 vorbesetzen
$val = formatVal6($hfcg->{$i}{beam1},$kw,$hfcg->{$i}{weather});
if ($hfcg->{$i}{beam1} > $hfcg->{$i}{beam2}) { # wer ist oben, Beam2 oder Beam1 ? Wert und Farbe für Zone 2 & 3 vorbesetzen
$val = formatVal6 ($hfcg->{$i}{beam1}, $kw, $hfcg->{$i}{weather});
$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
$v = formatVal6($hfcg->{$i}{beam2},$kw,$hfcg->{$i}{weather});
$v = formatVal6 ($hfcg->{$i}{beam2}, $kw, $hfcg->{$i}{weather});
$color2 = $colorb2;
$style2 = $style." background-color:#$color2; color:#$fcolor2;'";
}
}
else {
$val = formatVal6($hfcg->{$i}{beam2},$kw,$hfcg->{$i}{weather});
$color1 = $colorb2;
$style1 = $style." background-color:#$color1; color:#$fcolor2;'";
$val = formatVal6 ($hfcg->{$i}{beam2}, $kw, $hfcg->{$i}{weather});
$color1 = $colorb2;
$style1 = $style." background-color:#$color1; color:#$fcolor2;'";
if ($z3) {
$v = formatVal6($hfcg->{$i}{beam1},$kw,$hfcg->{$i}{weather});
$color2 = $colorb1;
$style2 = $style." background-color:#$color2; color:#$fcolor1;'";
$v = formatVal6 ($hfcg->{$i}{beam1}, $kw, $hfcg->{$i}{weather});
$color2 = $colorb1;
$style2 = $style." background-color:#$color2; color:#$fcolor1;'";
}
}
@ -9841,7 +9953,7 @@ sub _beamGraphic {
my $style = "style='padding-bottom:0px; padding-top:1px; vertical-align:top; margin-left:auto; margin-right:auto;";
$ret .= "<table width='100%' border='0'>\n"; # Tipp : das nachfolgende border=0 auf 1 setzen hilft sehr Ausgabefehler zu endecken
$val = ($hfcg->{$i}{diff} > 0) ? formatVal6($hfcg->{$i}{diff},$kw,$hfcg->{$i}{weather}) : '';
$val = ($hfcg->{$i}{diff} > 0) ? formatVal6 ($hfcg->{$i}{diff}, $kw, $hfcg->{$i}{weather}) : '';
$val = '&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;' if ($hfcg->{$i}{diff} == 0); # Sonderfall , hier wird die 0 gebraucht !
if ($val) {
@ -9875,14 +9987,14 @@ sub _beamGraphic {
}
if($z4) { # kann entfallen wenn auch z3 0 ist
$val = ($hfcg->{$i}{diff} < 0) ? formatVal6($hfcg->{$i}{diff},$kw,$hfcg->{$i}{weather}) : '&nbsp;';
$val = ($hfcg->{$i}{diff} < 0) ? formatVal6 ($hfcg->{$i}{diff}, $kw, $hfcg->{$i}{weather}) : '&nbsp;';
$ret .= "<tr class='$htr{$m}{cl}' style='height:".$z4."px'>";
$ret .= "<td class='solarfc' style='vertical-align:top'>".$val."</td></tr>";
}
}
if ($show_diff eq 'bottom') { # zusätzliche diff Anzeige
$val = formatVal6($hfcg->{$i}{diff},$kw,$hfcg->{$i}{weather});
$val = formatVal6 ($hfcg->{$i}{diff}, $kw, $hfcg->{$i}{weather});
$val = ($hfcg->{$i}{diff} < 0) ? '<b>'.$val.'<b/>' : ($val > 0 ) ? '+'.$val : $val if ($val ne '&nbsp;'); # negative Zahlen in Fettschrift, 0 aber ohne +
$ret .= "<tr class='$htr{$m}{cl}'><td class='solarfc' style='vertical-align:middle; text-align:center;'>$val</td></tr>";
}
@ -9926,53 +10038,50 @@ sub __weatherOnBeam {
return $ret if(!$weather);
my $m = $paref->{modulo} % 2;
my $m = $paref->{modulo} % 2;
my $ii = 0;
$ret .= "<tr class='$htr{$m}{cl}'><td class='solarfc'></td>"; # freier Platz am Anfang
my $ii;
for my $i (0..($maxhours*2)-1) {
last if (!exists($hfcg->{$i}{weather}));
next if (!$show_night && defined($hfcg->{$i}{weather})
&& ($hfcg->{$i}{weather} > 99)
&& !$hfcg->{$i}{beam1}
&& !$hfcg->{$i}{beam2});
for my $i (0..($maxhours * 2) - 1) {
last if (!exists ($hfcg->{$i}{weather}));
$hfcg->{$i}{weather} = 999 if(!defined $hfcg->{$i}{weather});
my $wcc = $hfcg->{$i}{wcc} // '-'; # Bewölkungsgrad ergänzen
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}) {
debugLog ($paref, 'graphic', "weather id >$i< don't show night condition ... is skipped") if($ii < $maxhours);
next;
};
# Lässt Nachticons aber noch durch wenn es einen Wert gibt , ToDo : klären ob die Nacht richtig gesetzt wurde
$ii++; # wieviele Stunden Icons haben wir bisher beechnet ?
last if ($ii > $maxhours);
# ToDo : weather_icon sollte im Fehlerfall Title mit der ID besetzen um in FHEMWEB sofort die ID sehen zu können
if (exists($hfcg->{$i}{weather}) && defined($hfcg->{$i}{weather})) {
my ($icon_name, $title) = $hfcg->{$i}{weather} > 100 ?
weather_icon ($name, $lang, $hfcg->{$i}{weather}-100) :
weather_icon ($name, $lang, $hfcg->{$i}{weather});
last if($ii > $maxhours);
# ToDo : weather_icon sollte im Fehlerfall Title mit der ID besetzen um in FHEMWEB sofort die ID sehen zu können
my ($icon_name, $title) = $hfcg->{$i}{weather} > 100 ?
weather_icon ($name, $lang, $hfcg->{$i}{weather}-100) :
weather_icon ($name, $lang, $hfcg->{$i}{weather});
my $wcc = $hfcg->{$i}{wcc} // "-"; # Bewölkungsgrad ergänzen
$wcc += 0 if(isNumeric ($wcc)); # Javascript Fehler vermeiden: https://forum.fhem.de/index.php/topic,117864.msg1233661.html#msg1233661
$title .= ': '.$wcc;
if(isNumeric ($wcc)) { # Javascript Fehler vermeiden: https://forum.fhem.de/index.php/topic,117864.msg1233661.html#msg1233661
$wcc += 0;
}
$title .= ': '.$wcc;
if($icon_name eq 'unknown') {
debugLog ($paref, "graphic", "unknown weather id: ".$hfcg->{$i}{weather}.", please inform the maintainer");
}
$icon_name .= $hfcg->{$i}{weather} < 100 ? '@'.$colorw : '@'.$colorwn;
my $val = FW_makeImage($icon_name) // q{};
if ($val eq $icon_name) { # passendes Icon beim User nicht vorhanden ! ( attr web iconPath falsch/prüfen/update ? )
$val = '<b>???<b/>';
debugLog ($paref, "graphic", qq{the icon "$weather_ids{$hfcg->{$i}{weather}}{icon}" not found. Please check attribute "iconPath" of your FHEMWEB instance and/or update your FHEM software});
}
$ret .= "<td title='$title' class='solarfc' width='$width' style='margin:1px; vertical-align:middle align:center; padding-bottom:1px;'>$val</td>";
if ($icon_name eq 'unknown') {
debugLog ($paref, "graphic", "unknown weather id: ".$hfcg->{$i}{weather}.", please inform the maintainer");
}
else { # mit $hfcg->{$i}{weather} = undef kann man unten leicht feststellen ob für diese Spalte bereits ein Icon ausgegeben wurde oder nicht
$ret .= "<td></td>";
$hfcg->{$i}{weather} = undef; # ToDo : prüfen ob noch nötig
$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 ? )
$val = '<b>???<b/>';
debugLog ($paref, "graphic", qq{ERROR - the icon "$weather_ids{$hfcg->{$i}{weather}}{icon}.svg" not found. Please check attribute "iconPath" of your FHEMWEB instance and/or update your FHEM software});
}
$ret .= "<td title='$title' class='solarfc' width='$width' style='margin:1px; vertical-align:middle align:center; padding-bottom:1px;'>$val</td>";
}
$ret .= "<td class='solarfc'></td></tr>"; # freier Platz am Ende der Icon Zeile
@ -10391,23 +10500,26 @@ return $ret;
#
###############################################################################
sub formatVal6 {
my ($v,$kw,$w) = @_;
my $n = '&nbsp;'; # positive Zahl
my $v = shift;
my $kw = shift;
my $w = shift;
my $n = '&nbsp;'; # positive Zahl
if($v < 0) {
if ($v < 0) {
$n = '-'; # negatives Vorzeichen merken
$v = abs($v);
}
if($kw eq 'kWh') { # bei Anzeige in kWh muss weniger aufgefüllt werden
$v = sprintf "%.1f",($v/1000);
if ($kw eq 'kWh') { # bei Anzeige in kWh muss weniger aufgefüllt werden
$v = sprintf "%.1f",($v / 1000);
$v += 0; # keine 0.0 oder 6.0 etc
return ($n eq '-') ? ($v*-1) : $v if defined($w) ;
return ($n eq '-') ? ($v * -1) : $v if(defined $w);
my $t = $v - int($v); # Nachkommstelle ?
if(!$t) { # glatte Zahl ohne Nachkommastelle
if (!$t) { # glatte Zahl ohne Nachkommastelle
if(!$v) {
return '&nbsp;'; # 0 nicht anzeigen, passt eigentlich immer bis auf einen Fall im Typ diff
}
@ -10428,7 +10540,7 @@ sub formatVal6 {
}
}
return ($n eq '-') ? ($v*-1) : $v if defined($w);
return ($n eq '-') ? ($v * -1) : $v if(defined $w);
# Werte bleiben in Watt
if (!$v) { return '&nbsp;'; } ## no critic "Cascading" # keine Anzeige bei Null
@ -10454,7 +10566,7 @@ sub weather_icon {
return $weather_ids{$id}{icon}, encode("utf8", $weather_ids{$id}{$txt});
}
return 'unknown','';
return ('unknown','');
}
################################################################
@ -10506,7 +10618,7 @@ return ($badev, $a ,$h);
################################################################
# Korrekturen und Qualität berechnen / speichern
# sowie AI Instanzen hinzufügen
# sowie AI Quellen Daten hinzufügen
################################################################
sub calcValueImproves {
my $paref = shift;
@ -10551,7 +10663,7 @@ sub calcValueImproves {
_calcCaQcomplex ($paref); # Korrekturberechnung mit Bewölkung duchführen/speichern
_calcCaQsimple ($paref); # einfache Korrekturberechnung duchführen/speichern
_addHourAiRawdata ($paref); # AI Instanz hinzufügen
_addHourAiRawdata ($paref); # AI Raw Data hinzufügen
delete $paref->{h};
}
@ -10722,7 +10834,7 @@ return;
}
################################################################
# AI Instanz für die abgeschlossene Stunde hinzufügen
# AI Daten für die abgeschlossene Stunde hinzufügen
################################################################
sub _addHourAiRawdata {
my $paref = shift;
@ -10737,7 +10849,7 @@ sub _addHourAiRawdata {
debugLog ($paref, 'aiProcess', "start add AI raw data for hour: $h");
$paref->{ood} = 1;
$paref->{ood} = 1; # Only One Day
$paref->{rho} = $rho;
aiAddRawData ($paref); # Raw Daten für AI hinzufügen und sichern
@ -14429,6 +14541,22 @@ to ensure that the system configuration is correct.
</li>
</ul>
<br>
<ul>
<a id="SolarForecast-set-consumerNewPlanning"></a>
<li><b>consumerNewPlanning &lt;Consumer number&gt; </b> <br><br>
The existing planning of the specified consumer is deleted. <br>
The new planning is carried out immediately, taking into account the parameters set in the consumerXX attribute.
<br><br>
<ul>
<b>Beispiel: </b> <br>
set &lt;name&gt; consumerNewPlanning 01 <br>
</ul>
</li>
</ul>
<br>
<ul>
<a id="SolarForecast-set-consumerImmediatePlanning"></a>
@ -15272,7 +15400,7 @@ to ensure that the system configuration is correct.
<a id="SolarForecast-get-valDecTree"></a>
<li><b>valDecTree </b> <br><br>
If AI support is activated in the SolarForecast Device, various AI-relevant data can be displayed:
If AI support is activated in the SolarForecast Device, various AI-relevant data can be displayed :
<br><br>
<ul>
@ -15962,7 +16090,7 @@ to ensure that the system configuration is correct.
<a id="SolarForecast-attr-graphicHeaderOwnspec"></a>
<li><b>graphicHeaderOwnspec &lt;Label&gt;:&lt;Reading&gt; &lt;Label&gt;:&lt;Reading&gt; ... </b><br>
Display of any reading values of the device. <br>
Display of any readings, set commands and attributes of the device in the graphic header. <br>
The values to be displayed are separated by spaces.
Four values (fields) are displayed per line. <br>
The input can be made in multiple lines. Values with the units "Wh" or "kWh" are converted according to the
@ -15992,6 +16120,17 @@ to ensure that the system configuration is correct.
<tr><td> </td><td>#Battery </td></tr>
<tr><td> </td><td>in&amp;nbsp;today:statistic_todayBatIn </td></tr>
<tr><td> </td><td>out&amp;nbsp;today:statistic_todayBatOut </td></tr>
<tr><td> </td><td>: </td></tr>
<tr><td> </td><td>: </td></tr>
<tr><td> </td><td>#Settings </td></tr>
<tr><td> </td><td>Autocorrection:pvCorrectionFactor_Auto : : : </td></tr>
<tr><td> </td><td>Consumer&lt;br&gt;Replanning:consumerNewPlanning : : : </td></tr>
<tr><td> </td><td>Consumer&lt;br&gt;Quickstart:consumerImmediatePlanning : : : </td></tr>
<tr><td> </td><td>Weather:graphicShowWeather : : : </td></tr>
<tr><td> </td><td>History:graphicHistoryHour : : : </td></tr>
<tr><td> </td><td>GraphicSize:flowGraphicSize : : : </td></tr>
<tr><td> </td><td>ShowNight:graphicShowNight : : : </td></tr>
<tr><td> </td><td>Debug:ctrlDebug : : : </td></tr>
</table>
</ul>
</li>
@ -16274,6 +16413,22 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
</ul>
<br>
<ul>
<a id="SolarForecast-set-consumerNewPlanning"></a>
<li><b>consumerNewPlanning &lt;Verbrauchernummer&gt; </b> <br><br>
Es wird die vorhandene Planung des angegebenen Verbrauchers gelöscht. <br>
Die Neuplanung wird unter Berücksichtigung der im consumerXX Attribut gesetzten Parameter sofort vorgenommen.
<br><br>
<ul>
<b>Beispiel: </b> <br>
set &lt;name&gt; consumerNewPlanning 01 <br>
</ul>
</li>
</ul>
<br>
<ul>
<a id="SolarForecast-set-consumerImmediatePlanning"></a>
<li><b>consumerImmediatePlanning &lt;Verbrauchernummer&gt; </b> <br><br>
@ -17119,7 +17274,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-get-valDecTree"></a>
<li><b>valDecTree </b> <br><br>
Ist der KI Support im SolarForecast Device aktiviert, können verschiedene KI relevante Daten angezeigt werden:
Ist der KI Support im SolarForecast Device aktiviert, können verschiedene KI relevante Daten angezeigt werden :
<br><br>
<ul>
@ -17808,7 +17963,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<a id="SolarForecast-attr-graphicHeaderOwnspec"></a>
<li><b>graphicHeaderOwnspec &lt;Label&gt;:&lt;Reading&gt; &lt;Label&gt;:&lt;Reading&gt; ... </b><br>
Anzeige beliebiger Readingswerte des Devices. <br>
Anzeige beliebiger Readings, Set-Kommandos und Attribute des Devices im Grafikkopf. <br>
Die anzuzeigenden Werte werden durch Leerzeichen getrennt.
Es werden vier Werte (Felder) pro Zeile dargestellt. <br>
Die Eingabe kann mehrzeilig erfolgen. Werte mit den Einheiten "Wh" bzw. "kWh" werden entsprechend der Einstellung
@ -17838,6 +17993,17 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> </td><td>#Batterie </td></tr>
<tr><td> </td><td>in&amp;nbsp;heute:statistic_todayBatIn </td></tr>
<tr><td> </td><td>out&amp;nbsp;heute:statistic_todayBatOut </td></tr>
<tr><td> </td><td>: </td></tr>
<tr><td> </td><td>: </td></tr>
<tr><td> </td><td>#Settings </td></tr>
<tr><td> </td><td>Autokorrektur:pvCorrectionFactor_Auto : : : </td></tr>
<tr><td> </td><td>Consumer&lt;br&gt;Neuplanung:consumerNewPlanning : : : </td></tr>
<tr><td> </td><td>Consumer&lt;br&gt;Sofortstart:consumerImmediatePlanning : : : </td></tr>
<tr><td> </td><td>Wetter:graphicShowWeather : : : </td></tr>
<tr><td> </td><td>History:graphicHistoryHour : : : </td></tr>
<tr><td> </td><td>GraphicSize:flowGraphicSize : : : </td></tr>
<tr><td> </td><td>ShowNight:graphicShowNight : : : </td></tr>
<tr><td> </td><td>Debug:ctrlDebug : : : </td></tr>
</table>
</ul>
</li>