mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-03 16:56:54 +00:00
76_Solarforcast: contrib 0.13.0
git-svn-id: https://svn.fhem.de/fhem/trunk@23984 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
b76384b5af
commit
d12bebc72f
@ -116,6 +116,8 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"0.13.0" => "16.03.2021 changed sub forecastGraphic from Wzut ",
|
||||
"0.12.0" => "16.03.2021 switch etoday to etotal ",
|
||||
"0.11.0" => "14.03.2021 new attr history_hour, beam1Content, beam2Content, implement sub forecastGraphic from Wzut, ".
|
||||
"rename attr beamColor, beamColor2 , more fixes ",
|
||||
"0.10.0" => "13.03.2021 hour shifter in sub _transferMeterValues, lot of fixes ",
|
||||
@ -557,10 +559,11 @@ sub _setinverterDevice { ## no critic "not used"
|
||||
return qq{The device "$indev" doesn't exist!};
|
||||
}
|
||||
|
||||
if(!$h->{pv} || !$h->{etoday}) {
|
||||
if(!$h->{pv} || !$h->{etotal}) {
|
||||
return qq{The syntax of "$opt" isn't right. Please consider the commandref.};
|
||||
}
|
||||
|
||||
delete $hash->{HELPER}{INITETOTAL};
|
||||
readingsSingleUpdate($hash, "currentInverterDev", $arg, 1);
|
||||
createNotifyDev ($hash);
|
||||
|
||||
@ -776,6 +779,7 @@ sub _setreset { ## no critic "not used"
|
||||
if($prop eq "pvHistory") {
|
||||
my $type = $hash->{TYPE};
|
||||
delete $data{$type}{$name}{pvhist};
|
||||
delete $hash->{HELPER}{INITETOTAL};
|
||||
return;
|
||||
}
|
||||
|
||||
@ -793,6 +797,7 @@ sub _setreset { ## no critic "not used"
|
||||
if($prop eq "currentInverterDev") {
|
||||
readingsDelete ($hash, "Current_PV");
|
||||
deleteReadingspec ($hash, ".*_PVreal" );
|
||||
delete $hash->{HELPER}{INITETOTAL};
|
||||
}
|
||||
|
||||
createNotifyDev ($hash);
|
||||
@ -1089,12 +1094,14 @@ sub centralTask {
|
||||
my @da;
|
||||
my $t = time; # aktuelle Unix-Zeit
|
||||
my $chour = strftime "%H", localtime($t); # aktuelle Stunde
|
||||
my $day = strftime "%d", localtime($t); # aktueller Tag
|
||||
|
||||
my $params = {
|
||||
hash => $hash,
|
||||
name => $name,
|
||||
t => $t,
|
||||
chour => $chour,
|
||||
day => $day,
|
||||
daref => \@da
|
||||
};
|
||||
|
||||
@ -1288,11 +1295,8 @@ sub _transferDWDForecastValues {
|
||||
# deleteReadingspec ($hash, "NextHour.*");
|
||||
|
||||
for my $num (0..47) {
|
||||
my $fh = $chour + $num;
|
||||
my $fd = int ($fh / 24) ;
|
||||
$fh = $fh - ($fd * 24);
|
||||
|
||||
next if($fd > 1);
|
||||
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
|
||||
last if($fd > 1);
|
||||
|
||||
my $v = ReadingsVal($fcname, "fc${fd}_${fh}_Rad1h", 0);
|
||||
|
||||
@ -1357,15 +1361,14 @@ sub _transferWeatherValues {
|
||||
push @$daref, "Tomorrow_SunRise:".$fc1_SunRise;
|
||||
push @$daref, "Tomorrow_SunSet:". $fc1_SunSet;
|
||||
|
||||
my $fc0_SunRise_round = (sprintf "%02d", (split ":", $fc0_SunRise)[0]);
|
||||
my $fc0_SunSet_round = (sprintf "%02d", (split ":", $fc0_SunSet)[0]);
|
||||
my $fc0_SunRise_round = sprintf "%02d", (split ":", $fc0_SunRise)[0];
|
||||
my $fc0_SunSet_round = sprintf "%02d", (split ":", $fc0_SunSet)[0];
|
||||
my $fc1_SunRise_round = sprintf "%02d", (split ":", $fc1_SunRise)[0];
|
||||
my $fc1_SunSet_round = sprintf "%02d", (split ":", $fc1_SunSet)[0];
|
||||
|
||||
for my $num (0..47) {
|
||||
my $fh = $chour + $num;
|
||||
my $fd = int ($fh / 24) ;
|
||||
$fh = $fh - ($fd * 24);
|
||||
|
||||
next if($fd > 1);
|
||||
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
|
||||
last if($fd > 1);
|
||||
|
||||
if($num == 0) {
|
||||
$time_str = "ThisHour";
|
||||
@ -1385,7 +1388,7 @@ sub _transferWeatherValues {
|
||||
if($fd == 0 && ($fhstr lt $fc0_SunRise_round || $fhstr gt $fc0_SunSet_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang heute
|
||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||
}
|
||||
elsif ($fd == 1 && ($fhstr lt $fc0_SunRise_round || $fhstr gt $fc0_SunSet_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen
|
||||
elsif ($fd == 1 && ($fhstr lt $fc1_SunRise_round || $fhstr gt $fc1_SunSet_round)) { # Zeit vor Sonnenaufgang oder nach Sonnenuntergang morgen
|
||||
$wid += 100; # "1" der WeatherID voranstellen wenn Nacht
|
||||
}
|
||||
|
||||
@ -1416,6 +1419,7 @@ sub _transferInverterValues {
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Unix-Zeit
|
||||
my $chour = $paref->{chour};
|
||||
my $day = $paref->{day};
|
||||
my $daref = $paref->{daref};
|
||||
|
||||
my $indev = ReadingsVal($name, "currentInverterDev", "");
|
||||
@ -1423,41 +1427,65 @@ sub _transferInverterValues {
|
||||
$indev = $a->[0] // "";
|
||||
return if(!$indev || !$defs{$indev});
|
||||
|
||||
my $tlim = "00|23"; # Stunde 00/23 -> bestimmte Aktionen
|
||||
my $tlim = "23"; # Stunde 23 -> bestimmte Aktionen
|
||||
my $type = $hash->{TYPE};
|
||||
|
||||
if($chour =~ /^($tlim)$/x) {
|
||||
deleteReadingspec ($hash, "Today_Hour.*_PV.*");
|
||||
delete $hash->{HELPER}{INITETOTAL};
|
||||
}
|
||||
|
||||
my ($pvread,$pvunit) = split ":", $h->{pv}; # Readingname/Unit für aktuelle PV Erzeugung
|
||||
my ($edread,$edunit) = split ":", $h->{etoday}; # Readingname/Unit für Tagesenergie
|
||||
my ($edread,$etunit) = split ":", $h->{etotal}; # Readingname/Unit für Energie total
|
||||
|
||||
Log3($name, 5, "$name - collect Inverter data: device=$indev, pv=$pvread ($pvunit), etoday=$edread ($edunit)");
|
||||
Log3($name, 5, "$name - collect Inverter data: device=$indev, pv=$pvread ($pvunit), etotal=$edread ($etunit)");
|
||||
|
||||
my $pvuf = $pvunit =~ /^kW$/xi ? 1000 : 1;
|
||||
my $pv = ReadingsNum ($indev, $pvread, 0) * $pvuf; # aktuelle Erzeugung (W)
|
||||
|
||||
push @$daref, "Current_PV:". $pv." W";
|
||||
$data{$hash->{TYPE}}{$name}{current}{generation} = $pv; # Hilfshash Wert current generation Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
|
||||
$data{$type}{$name}{current}{generation} = $pv; # Hilfshash Wert current generation Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
|
||||
|
||||
my $eduf = $edunit =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etoday = ReadingsNum ($indev, $edread, 0) * $eduf; # aktuelle Erzeugung (W)
|
||||
my $etuf = $etunit =~ /^kWh$/xi ? 1000 : 1;
|
||||
my $etotal = ReadingsNum ($indev, $edread, 0) * $etuf; # Erzeugung total (Wh)
|
||||
|
||||
my $edaypast = 0;
|
||||
deleteReadingspec ($hash, "Today_Hour00_PVreal");
|
||||
# deleteReadingspec ($hash, "Today_Hour00_PVreal");
|
||||
|
||||
for my $hour (0..int $chour) { # alle bisherigen Erzeugungen des Tages summieren
|
||||
$edaypast += ReadingsNum ($name, "Today_Hour".sprintf("%02d",$hour)."_PVreal", 0);
|
||||
}
|
||||
|
||||
my $ethishour = int ($etoday - $edaypast);
|
||||
my $do = 0;
|
||||
if ($edaypast == 0) {
|
||||
if (defined $hash->{HELPER}{INITETOTAL}) {
|
||||
# $edaypast = $hash->{HELPER}{INITETOTAL};
|
||||
# $hash->{HELPER}{INITETOTAL} = $etotal;
|
||||
$do = 1;
|
||||
}
|
||||
else {
|
||||
$hash->{HELPER}{INITETOTAL} = $etotal;
|
||||
}
|
||||
}
|
||||
elsif (!defined $hash->{HELPER}{INITETOTAL}) {
|
||||
$hash->{HELPER}{INITETOTAL} = $etotal-$edaypast-ReadingsNum($name, "Today_Hour".sprintf("%02d",$chour+1)."_PVreal", 0);
|
||||
}
|
||||
else {
|
||||
$do = 1;
|
||||
}
|
||||
|
||||
if ($do) {
|
||||
my $ethishour = int ($etotal - ($edaypast + $hash->{HELPER}{INITETOTAL}));
|
||||
|
||||
# Log3($name, 1, "$name - etotal: $etotal, edaypast: $edaypast, HELPER: $hash->{HELPER}{INITETOTAL}, ethishour: $ethishour ");
|
||||
|
||||
if($chour !~ /^($tlim)$/x) { # nicht setzen wenn Stunde 23 des Tages
|
||||
if($ethishour < 0) {
|
||||
$ethishour = 0;
|
||||
}
|
||||
|
||||
my $nhour = $chour+1;
|
||||
push @$daref, "Today_Hour".sprintf("%02d",$nhour)."_PVreal:".$ethishour." Wh";
|
||||
$data{$hash->{TYPE}}{$name}{pvreal}{sprintf("%02d",$nhour)} = $ethishour; # Hilfshash Wert PV real Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
||||
$data{$type}{$name}{pvreal}{sprintf("%02d",$nhour)} = $ethishour; # Hilfshash Wert PV real Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
|
||||
|
||||
$paref->{ethishour} = $ethishour;
|
||||
$paref->{nhour} = sprintf("%02d",$nhour);
|
||||
@ -1485,8 +1513,6 @@ sub _transferMeterValues {
|
||||
$medev = $a->[0] // "";
|
||||
return if(!$medev || !$defs{$medev});
|
||||
|
||||
## aktuelle Consumption
|
||||
#########################
|
||||
my ($gc,$gcunit) = split ":", $h->{gcon}; # Readingname/Unit für aktuellen Netzbezug
|
||||
|
||||
Log3($name, 5, "$name - collect Meter data: device=$medev, gcon=$gc ($gcunit)");
|
||||
@ -1500,6 +1526,21 @@ sub _transferMeterValues {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Berechnen Forecast Tag / Stunden Verschieber
|
||||
# aus aktueller Stunde + lfd. Nummer
|
||||
################################################################
|
||||
sub _calcDayHourMove {
|
||||
my $chour = shift;
|
||||
my $num = shift;
|
||||
|
||||
my $fh = $chour + $num;
|
||||
my $fd = int ($fh / 24) ;
|
||||
$fh = $fh - ($fd * 24);
|
||||
|
||||
return ($fd,$fh);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# FHEMWEB Fn
|
||||
################################################################
|
||||
@ -1667,8 +1708,8 @@ sub forecastGraphic {
|
||||
}
|
||||
|
||||
my $cclv = "L05";
|
||||
my @pgCDev = split ',', AttrVal($name,"consumerList",""); # definierte Verbraucher ermitteln
|
||||
my ($legend_style, $legend) = split '_', AttrVal($name,'consumerLegend','icon_top');
|
||||
my @pgCDev = split(',',AttrVal($name,"consumerList","")); # definierte Verbraucher ermitteln
|
||||
my ($legend_style, $legend) = split('_',AttrVal($name,'consumerLegend','icon_top'));
|
||||
|
||||
$legend = '' if(($legend_style eq 'none') || (!int(@pgCDev)));
|
||||
|
||||
@ -1717,11 +1758,15 @@ sub forecastGraphic {
|
||||
# Parameter f. Anzeige extrahieren
|
||||
###################################
|
||||
my $maxhours = AttrNum ($name, 'hourCount', 24 );
|
||||
my $offset = AttrNum($name, 'history_hour', 0 );
|
||||
|
||||
my $hourstyle = AttrVal ($name, 'hourStyle', undef );
|
||||
my $colorfc = AttrVal ($name, 'beam1Color', undef );
|
||||
|
||||
my $colorfc = AttrVal ($name, 'beam1Color', '000000');
|
||||
my $colorc = AttrVal ($name, 'beam2Color', 'C4C4A7');
|
||||
my $beam1cont = AttrVal ($name, 'beam1Content', 'forecast');
|
||||
my $beam2cont = AttrVal ($name, 'beam2Content', 'forecast');
|
||||
|
||||
my $icon = AttrVal ($name, 'consumerAdviceIcon', undef );
|
||||
my $html_start = AttrVal ($name, 'htmlStart', undef ); # beliebige HTML Strings die vor der Grafik ausgegeben werden
|
||||
my $html_end = AttrVal ($name, 'htmlEnd', undef ); # beliebige HTML Strings die nach der Grafik ausgegeben werden
|
||||
@ -1738,7 +1783,7 @@ sub forecastGraphic {
|
||||
my $show_night = AttrNum ($name, 'showNight', 0 ); # alle Balken (Spalten) anzeigen ?
|
||||
my $show_diff = AttrVal ($name, 'showDiff', 'no' ); # zusätzliche Anzeige $di{} in allen Typen
|
||||
my $weather = AttrNum ($name, 'showWeather', 1 );
|
||||
my $colorw = AttrVal ($name, 'weatherColor', undef ); # Wetter Icon Farbe
|
||||
my $colorw = AttrVal ($name, 'weatherColor', 'FFFFFF' ); # Wetter Icon Farbe
|
||||
my $colorwn = AttrVal ($name, 'weatherColor_night', $colorw ); # Wetter Icon Farbe Nacht
|
||||
|
||||
my $wlalias = AttrVal ($name, 'alias', $name );
|
||||
@ -1902,44 +1947,41 @@ sub forecastGraphic {
|
||||
# Werte aktuelle Stunde
|
||||
##########################
|
||||
|
||||
my $t0;
|
||||
my $thishour;
|
||||
|
||||
(undef,undef,undef,$t0) = ReadingsVal($name, "ThisHour_Time", '0000-00-00 24') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x;
|
||||
(undef,undef,undef,$t0) = ReadingsVal($name, "ThisHour_Time", '00.00.0000 24') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x if (AttrVal('global', 'language', '') eq 'DE');
|
||||
(undef,undef,undef,$thishour) = ReadingsVal($name, "ThisHour_Time", '0000-00-00 24') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x;
|
||||
(undef,undef,undef,$thishour) = ReadingsVal($name, "ThisHour_Time", '00.00.0000 24') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x if (AttrVal('global', 'language', '') eq 'DE');
|
||||
$thishour = int($thishour); # keine führende Null
|
||||
$t{0} = $thishour;
|
||||
|
||||
$t{0} = int($t0);
|
||||
|
||||
my $thishour = $t{0}; # aktuelle Stunde, wird erst später gebraucht.
|
||||
|
||||
my $offset = AttrNum($name, 'history_hour', 0);
|
||||
my $val1;
|
||||
my $val2;
|
||||
|
||||
if ($offset) {
|
||||
$t{0} += $offset;
|
||||
$t{0} += 24 if ($t{0} < 0);
|
||||
|
||||
$t0 = sprintf('%02d', $t{0});
|
||||
$we{0} = (exists($data{$hash->{TYPE}}{$name}{weather}{$t0}{id})) ? $data{$hash->{TYPE}}{$name}{weather}{$t0}{id} : -1 if ($weather);
|
||||
|
||||
my $t0 = sprintf('%02d', $t{0}+1); # Index liegt eins höher : 10:00 = Index '11'
|
||||
$val1 = (exists($data{$hash->{TYPE}}{$name}{pvfc}{$t0})) ? $data{$hash->{TYPE}}{$name}{pvfc}{$t0} : 0;
|
||||
$val2 = (exists($data{$hash->{TYPE}}{$name}{pvreal}{$t0})) ? $data{$hash->{TYPE}}{$name}{pvreal}{$t0} : 0;
|
||||
$we{0} = (exists($data{$hash->{TYPE}}{$name}{weather}{$t0}{id})) ? $data{$hash->{TYPE}}{$name}{weather}{$t0}{id} : -1;
|
||||
#$is{0} = undef;
|
||||
}
|
||||
else {
|
||||
$we{0} = (exists($hash->{HELPER}{'ThisHour_WeatherId'})) ? $hash->{HELPER}{"ThisHour_WeatherId"} : -1 if ($weather);
|
||||
|
||||
my $t0 = sprintf('%02d', $t{0}+1);
|
||||
$val1 = (exists($data{$hash->{TYPE}}{$name}{pvfc}{$t0})) ? $data{$hash->{TYPE}}{$name}{pvfc}{$t0} : 0;
|
||||
$val2 = (exists($data{$hash->{TYPE}}{$name}{pvreal}{$t0})) ? $data{$hash->{TYPE}}{$name}{pvreal}{$t0} : 0;
|
||||
# ToDo : klären ob ThisHour:weather_Id stimmt in Bezug zu ThisHour_Time
|
||||
$we{0} = (exists($hash->{HELPER}{'ThisHour_WeatherId'})) ? $hash->{HELPER}{"ThisHour_WeatherId"} : -1;
|
||||
#$is{0} = (ReadingsVal($name,"ThisHour_IsConsumptionRecommended",'no') eq 'yes' ) ? $icon : undef;
|
||||
}
|
||||
|
||||
my $pvfc0 = exists $data{$hash->{TYPE}}{$name}{pvfc}{$t0} ? $data{$hash->{TYPE}}{$name}{pvfc}{$t0} : 0;
|
||||
my $pvreal0 = exists $data{$hash->{TYPE}}{$name}{pvreal}{$t0} ? $data{$hash->{TYPE}}{$name}{pvreal}{$t0} : 0;
|
||||
|
||||
$beam1{0} = $beam1cont eq 'forecast' ? $pvfc0 : $pvreal0;
|
||||
$beam2{0} = $beam2cont eq 'forecast' ? $pvfc0 : $pvreal0;
|
||||
$beam1{0} = ($beam1cont eq 'forecast') ? $val1 : $val2;
|
||||
$beam2{0} = ($beam2cont eq 'forecast') ? $val1 : $val2;
|
||||
$di{0} = $beam1{0} - $beam2{0};
|
||||
|
||||
# User Auswahl überschreiben wenn beide Werte die gleiche Basis haben !
|
||||
$lotype = 'pv' if ($beam1cont eq $beam2cont);
|
||||
|
||||
$we{0} //= -1;
|
||||
|
||||
###########################################################
|
||||
# get consumer list and display it in portalGraphics
|
||||
###########################################################
|
||||
@ -1993,56 +2035,55 @@ sub forecastGraphic {
|
||||
}
|
||||
|
||||
$maxVal = !$maxVal ? $beam1{0} : $maxVal; # Startwert wenn kein Wert bereits via attr vorgegeben ist
|
||||
|
||||
my $maxCon = $beam2{0}; # für Typ co
|
||||
my $maxDif = $di{0}; # für Typ diff
|
||||
my $minDif = $di{0}; # für Typ diff
|
||||
|
||||
#Log3($hash,3 , Dumper($data{$hash->{TYPE}}{$name}));
|
||||
|
||||
for my $i (1..$maxhours-1) {
|
||||
my $ti;
|
||||
my $pvfci;
|
||||
my $pvreali = 0;
|
||||
for my $i (1..($maxhours*2)-1) { # doppelte Anzahl berechnen
|
||||
|
||||
my $val1;
|
||||
my $val2 = 0;
|
||||
my $ii = sprintf('%02d',$i);
|
||||
|
||||
(undef,undef,undef,$ti) = ReadingsVal($name,"NextHour".$ii."_Time", '0000-00-00 24') =~ m/(\d{4})-(\d{2})-(\d{2})\s(\d{2})/x;
|
||||
(undef,undef,undef,$ti) = ReadingsVal($name,"NextHour".$ii."_Time", '00.00.0000 24') =~ m/(\d{2}).(\d{2}).(\d{4})\s(\d{2})/x if (AttrVal('global', 'language', '') eq 'DE');
|
||||
$t{$i} = $thishour +$i;
|
||||
$t{$i} -= 24 if ($t{$i} > 23);
|
||||
|
||||
$t{$i} = int($ti); # keine führende 0
|
||||
if ($offset < 0) {
|
||||
|
||||
$t{$i} += $offset;
|
||||
$t{$i} += 24 if ($t{$i} < 0);
|
||||
|
||||
if ($offset < 0) {
|
||||
my $j = $t{0} + $i;
|
||||
$j -= 24 if ($j > 23);
|
||||
my $jj = sprintf('%02d',$j);
|
||||
my $jj = sprintf('%02d',$t{$i});
|
||||
|
||||
if ($i <= abs($offset)) {
|
||||
$pvfci = (exists($data{$hash->{TYPE}}{$name}{pvfc}{$jj})) ? $data{$hash->{TYPE}}{$name}{pvfc}{$jj} : 0;
|
||||
$pvreali = (exists($data{$hash->{TYPE}}{$name}{pvreal}{$jj})) ? $data{$hash->{TYPE}}{$name}{pvreal}{$jj} : 0;
|
||||
$we{$i} = (exists($data{$hash->{TYPE}}{$name}{weather}{$jj}{id})) ? $data{$hash->{TYPE}}{$name}{weather}{$jj}{id} : -1 if ($weather);
|
||||
|
||||
$val1 = (exists($data{$hash->{TYPE}}{$name}{pvfc}{$jj})) ? $data{$hash->{TYPE}}{$name}{pvfc}{$jj} : 0;
|
||||
$val2 = (exists($data{$hash->{TYPE}}{$name}{pvreal}{$jj})) ? $data{$hash->{TYPE}}{$name}{pvreal}{$jj} : 0;
|
||||
$we{$i} = (exists($data{$hash->{TYPE}}{$name}{weather}{$jj}{id})) ? $data{$hash->{TYPE}}{$name}{weather}{$jj}{id} : -1;
|
||||
}
|
||||
else {
|
||||
my $nh = sprintf('%02d', $t{0}+$i-$thishour);
|
||||
$pvfci = ReadingsNum($name, 'NextHour'.$nh.'_PVforecast', 0);
|
||||
$we{$i} = $hash->{HELPER}{'NextHour'.$nh.'_WeatherId'} if($weather);
|
||||
my $nh = sprintf('%02d', $i+$offset);
|
||||
$val1 = ReadingsNum($name, 'NextHour'.$nh.'_PVforecast', 0);
|
||||
# ToDo : klären ob -1 oder nicht !
|
||||
#$nh = sprintf('%02d', $i+$offset-1);
|
||||
$we{$i} = (exists($hash->{HELPER}{'NextHour'.$nh.'_WeatherId'})) ?$hash->{HELPER}{'NextHour'.$nh.'_WeatherId'} : -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$pvfci = ReadingsNum($name, 'NextHour'.$ii.'_PVforecast', 0); # Forecast
|
||||
$we{$i} = $hash->{HELPER}{'NextHour'.$ii.'_WeatherId'} if($weather); # für Wettericons
|
||||
$val1 = ReadingsNum($name, 'NextHour'.$ii.'_PVforecast', 0); # Forecast
|
||||
$we{$i} = (exists($hash->{HELPER}{'NextHour'.$ii.'_WeatherId'})) ? $hash->{HELPER}{'NextHour'.$ii.'_WeatherId'} : -1; # für Wettericons
|
||||
#$is{$i} = (ReadingsVal($name,"NextHour".$ii."_IsConsumptionRecommended",'no') eq 'yes') ? $icon : undef;
|
||||
}
|
||||
|
||||
$beam1{$i} = $beam1cont eq 'forecast' ? $pvfci : $pvreali;
|
||||
$beam2{$i} = $beam2cont eq 'forecast' ? $pvfci : $pvreali;
|
||||
$beam1{$i} = ($beam1cont eq 'forecast') ? $val1 :$val2;
|
||||
$beam2{$i} = ($beam2cont eq 'forecast') ? $val1 :$val2;
|
||||
|
||||
# sicher stellen das wir keine undefs in der Liste haben !
|
||||
$beam1{$i} //= 0;
|
||||
$beam2{$i} //= 0;
|
||||
$di{$i} = $beam1{$i} - $beam2{$i};
|
||||
$we{$i} //= -1;
|
||||
|
||||
$maxVal = $beam1{$i} if ($beam1{$i} > $maxVal);
|
||||
$maxCon = $beam2{$i} if ($beam2{$i} > $maxCon);
|
||||
@ -2079,15 +2120,20 @@ sub forecastGraphic {
|
||||
if ($weather) {
|
||||
$ret .= "<tr class='even'><td class='smaportal'></td>"; # freier Platz am Anfang
|
||||
|
||||
for my $i (0..$maxhours-1) { # keine Anzeige bei Null Ertrag bzw. in der Nacht , Typ pcvo & diff haben aber immer Daten in der Nacht
|
||||
if ($beam1{$i} || $show_night || ($lotype eq 'pvco') || ($lotype eq 'diff')) { # FHEM Wetter Icons (weather_xxx) , Skalierung und Farbe durch FHEM Bordmittel
|
||||
my $night = ($we{$i} > 99) ? 1 : 0;
|
||||
$we{$i} -= 100 if ($night);
|
||||
my ($icon_name, $title) = weather_icon($we{$i}); # unknown -> FHEM Icon Fragezeichen im Kreis wird als Ersatz Icon ausgegeben
|
||||
Log3($name, 3, "$name - unknown weather id: ".$we{$i}.", please inform the maintainer") if($icon_name eq 'unknown');
|
||||
my $ii;
|
||||
for my $i (0..($maxhours*2)-1) {
|
||||
next if (!$show_night && ($we{$i} > 99) && !$beam1{$i} && !$beam2{$i});
|
||||
# Lässt Nachticons aber noch durch wenn es einen Wert gibt , ToDo : klären ob die Nacht richtig gesetzt wurde
|
||||
$ii++; # wieviele Stunden haben wir bisher angezeigt ?
|
||||
last if ($ii > $maxhours); # vorzeitiger Abbruch
|
||||
|
||||
$icon_name .='@'.$colorw if (defined($colorw) && !$night);
|
||||
$icon_name .='@'.$colorwn if (defined($colorwn) && $night);
|
||||
# FHEM Wetter Icons (weather_xxx) , Skalierung und Farbe durch FHEM Bordmittel
|
||||
# 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) = (($we{$i} > 99)) ? weather_icon($we{$i}-100) : weather_icon($we{$i});
|
||||
# unknown -> FHEM Icon Fragezeichen im Kreis wird als Ersatz Icon ausgegeben
|
||||
Log3($name, 4, "$name - unknown weather id: ".$we{$i}.", please inform the maintainer") if($icon_name eq 'unknown');
|
||||
|
||||
$icon_name .= ($we{$i} < 100 ) ? '@'.$colorw : '@'.$colorwn;
|
||||
$val = FW_makeImage($icon_name);
|
||||
|
||||
if ($val eq $icon_name) { # passendes Icon beim User nicht vorhanden ! ( attr web iconPath falsch/prüfen/update ? )
|
||||
@ -2096,11 +2142,8 @@ sub forecastGraphic {
|
||||
}
|
||||
|
||||
$ret .= "<td title='$title' class='smaportal' width='$width' style='margin:1px; vertical-align:middle align:center; padding-bottom:1px;'>$val</td>"; # title -> Mouse Over Text
|
||||
}
|
||||
else { # Kein Ertrag oder show_night = 0
|
||||
$ret .= "<td></td>"; $we{$i} = undef;
|
||||
}
|
||||
# mit $we{$i} = undef kann man unten leicht feststellen ob für diese Spalte bereits ein Icon ausgegeben wurde oder nicht
|
||||
# Todo : ist jetzt nicht so , prüfen da formatVal6 we undef auswertet
|
||||
}
|
||||
|
||||
$ret .= "<td class='smaportal'></td></tr>"; # freier Platz am Ende der Icon Zeile
|
||||
@ -2108,11 +2151,15 @@ sub forecastGraphic {
|
||||
|
||||
if($show_diff eq 'top') { # Zusätzliche Zeile Ertrag - Verbrauch
|
||||
$ret .= "<tr class='even'><td class='smaportal'></td>"; # freier Platz am Anfang
|
||||
my $ii;
|
||||
for my $i (0..($maxhours*2)-1) {
|
||||
# gleiche Bedingung wie oben
|
||||
next if (!$show_night && ($we{$i} > 99) && !$beam1{$i} && !$beam2{$i});
|
||||
$ii++; # wieviele Stunden haben wir bisher angezeigt ?
|
||||
last if ($ii > $maxhours); # vorzeitiger Abbruch
|
||||
|
||||
for my $i (0..$maxhours-1) {
|
||||
$val = formatVal6($di{$i},$kw,$we{$i});
|
||||
#$val = ($di{$i} < 0) ? '<b>'.$val.'<b/>' : '+'.$val; # negative Zahlen in Fettschrift
|
||||
$val = '<b>'.$val.'<b/>' if ($di{$i} < 0);
|
||||
$val = ($di{$i} < 0) ? '<b>'.$val.'<b/>' : ($val>0) ? '+'.$val : $val; # negative Zahlen in Fettschrift, 0 aber ohne +
|
||||
$ret .= "<td class='smaportal' style='vertical-align:middle; text-align:center;'>$val</td>";
|
||||
}
|
||||
$ret .= "<td class='smaportal'></td></tr>"; # freier Platz am Ende
|
||||
@ -2120,24 +2167,22 @@ sub forecastGraphic {
|
||||
|
||||
$ret .= "<tr class='even'><td class='smaportal'></td>"; # Neue Zeile mit freiem Platz am Anfang
|
||||
|
||||
my $ii = 0;
|
||||
for my $i (0..($maxhours*2)-1) {
|
||||
# gleiche Bedingung wie oben
|
||||
next if (!$show_night && ($we{$i} > 99) && !$beam1{$i} && !$beam2{$i});
|
||||
$ii++;
|
||||
last if ($ii > $maxhours);
|
||||
|
||||
for my $i (0..$maxhours-1) {
|
||||
# Achtung Falle, Division by Zero möglich,
|
||||
# maxVal kann gerade bei kleineren maxhours Ausgaben in der Nacht leicht auf 0 fallen
|
||||
$height = 200 if (!$height); # Fallback, sollte eigentlich nicht vorkommen, außer der User setzt es auf 0
|
||||
$maxVal = 1 if (!int $maxVal);
|
||||
$maxCon = 1 if (!$maxCon);
|
||||
|
||||
#Log3($hash,3, "h $height , V:$maxVal , C: $maxCon");
|
||||
|
||||
# Der zusätzliche Offset durch $fsize verhindert bei den meisten Skins
|
||||
# dass die Grundlinie der Balken nach unten durchbrochen wird
|
||||
|
||||
#if($lotype eq 'co') {
|
||||
# $he = int(($maxCon-$beam2{$i})/$maxCon*$height) + $fsize; # he - freier der Raum über den Balken.
|
||||
# $z3 = int($height + $fsize - $he); # Resthöhe
|
||||
#}
|
||||
|
||||
if ($lotype eq 'pv') {
|
||||
$he = int(($maxVal-$beam1{$i}) / $maxVal*$height) + $fsize;
|
||||
$z3 = int($height + $fsize - $he);
|
||||
@ -2210,10 +2255,10 @@ sub forecastGraphic {
|
||||
}
|
||||
|
||||
# Alle vorbesetzen Werte umrechnen auf echte Ausgabe px
|
||||
$he = (!$px_pos) ? 0 : int(($maxDif-$z2)/$maxDif*$px_pos); # Teilung durch 0 vermeiden
|
||||
$he = (!$px_pos || !$maxDif) ? 0 : int(($maxDif-$z2)/$maxDif*$px_pos); # Teilung durch 0 vermeiden
|
||||
$z2 = ($px_pos - $he) ;
|
||||
|
||||
$z4 = (!$px_neg) ? 0 : int((abs($minDif)-$z3)/abs($minDif)*$px_neg); # Teilung durch 0 unbedingt vermeiden
|
||||
$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ß fsize als zusätzlicher Raum zugeschlagen werden !
|
||||
@ -2227,17 +2272,16 @@ sub forecastGraphic {
|
||||
|
||||
$ret .="<td style='text-align: center; padding-left:1px; padding-right:1px; margin:0px; vertical-align:bottom; padding-top:0px'>\n";
|
||||
|
||||
my $v;
|
||||
if ($lotype eq 'pv') {
|
||||
$v = ($lotype eq 'co') ? $beam2{$i} : $beam1{$i} ;
|
||||
#my $v = ($lotype eq 'co') ? $beam2{$i} : $beam1{$i} ;
|
||||
#$v = 0 if (($lotype eq 'co') && !$beam1{$i} && !$show_night); # auch bei type co die Nacht ggf. unterdrücken
|
||||
$val = formatVal6($v,$kw,$we{$i});
|
||||
$val = formatVal6($beam1{$i},$kw,$we{$i});
|
||||
|
||||
$ret .="<table width='100%' height='100%'>"; # mit width=100% etwas bessere Füllung der Balken
|
||||
$ret .="<tr class='even' style='height:".$he."px'>";
|
||||
$ret .="<td class='smaportal' style='vertical-align:bottom'>".$val."</td></tr>";
|
||||
|
||||
if ($v || $show_night) { # Balken nur einfärben wenn der User via Attr eine Farbe vorgibt, sonst bestimmt class odd von TR alleine die Farbe
|
||||
if ($beam1{$i} || $show_night) { # Balken nur einfärben wenn der User via Attr eine Farbe vorgibt, sonst bestimmt class odd von TR alleine die Farbe
|
||||
my $style = "style=\"padding-bottom:0px; vertical-align:top; margin-left:auto; margin-right:auto;";
|
||||
$style .= defined $colorfc ? " background-color:#$colorfc\"" : '"'; # Syntaxhilight
|
||||
|
||||
@ -2249,20 +2293,19 @@ sub forecastGraphic {
|
||||
|
||||
##################################
|
||||
# inject the new icon if defined
|
||||
$ret .= consinject($hash,$i,@pgCDev) if($ret);
|
||||
#$ret .= consinject($hash,$i,@pgCDev) if($s);
|
||||
|
||||
$ret .= "</td></tr>";
|
||||
}
|
||||
}
|
||||
|
||||
if ($lotype eq 'pvco') {
|
||||
my ($color1, $color2, $style1, $style2);
|
||||
my ($color1, $color2, $style1, $style2, $v);
|
||||
|
||||
$ret .="<table width='100%' height='100%'>\n"; # mit width=100% etwas bessere Füllung der Balken
|
||||
|
||||
if($he) { # der Freiraum oben kann beim größten Balken ganz entfallen
|
||||
$ret .="<tr class='even' style='height:".$he."px'><td class='smaportal'></td></tr>";
|
||||
}
|
||||
# der Freiraum oben kann beim größten Balken ganz entfallen
|
||||
$ret .="<tr class='even' style='height:".$he."px'><td class='smaportal'></td></tr>" if ($he);
|
||||
|
||||
if($beam1{$i} > $beam2{$i}) { # wer ist oben, co pder pv ? Wert und Farbe für Zone 2 & 3 vorbesetzen
|
||||
$val = formatVal6($beam1{$i},$kw,$we{$i});
|
||||
@ -2297,7 +2340,7 @@ sub forecastGraphic {
|
||||
|
||||
##################################
|
||||
# inject the new icon if defined
|
||||
$ret .= consinject($hash,$i,@pgCDev) if($ret);
|
||||
#$ret .= consinject($hash,$i,@pgCDev) if($s);
|
||||
|
||||
$ret .= "</td></tr>";
|
||||
|
||||
@ -2355,17 +2398,17 @@ sub forecastGraphic {
|
||||
|
||||
if ($show_diff eq 'bottom') { # zusätzliche diff Anzeige
|
||||
$val = formatVal6($di{$i},$kw,$we{$i});
|
||||
#$val = ($di{$i} < 0) ? '<b>'.$val.'<b/>' : '+'.$val; # Kommentar siehe oben bei show_diff eq top
|
||||
$val = '<b>'.$val.'<b/>' if ($di{$i} < 0);
|
||||
$val = ($di{$i} < 0) ? '<b>'.$val.'<b/>' : ($val>0) ? '+'.$val : $val; # negative Zahlen in Fettschrift, 0 aber ohne +
|
||||
$ret .= "<tr class='even'><td class='smaportal' style='vertical-align:middle; text-align:center;'>$val</td></tr>";
|
||||
}
|
||||
|
||||
$ret .= "<tr class='even'><td class='smaportal' style='vertical-align:bottom; text-align:center;'>";
|
||||
$t{$i} = $t{$i}.$hourstyle if(defined($hourstyle));# z.B. 10:00 statt 10
|
||||
#$ret .= (($t{$i} == $thishour) && ($offset < 0)) ? "<b>$t{$i}</b>" : $t{$i}; # Stundenwerte ohne führende 0
|
||||
$ret .= (($t{$i} == $thishour) && ($offset < 0)) ? '<a class="changed" style="visibility:visible"><span>'.$t{$i}.'</span></a>' : $t{$i};
|
||||
$thishour = 24 if ($t{$i} == $thishour); # nur einmal verwenden !
|
||||
$ret .="</td></tr></table></td>";
|
||||
}
|
||||
} ## for i
|
||||
|
||||
|
||||
$ret .= "<td class='smaportal'></td></tr>";
|
||||
|
||||
@ -2773,13 +2816,12 @@ sub setPVhistory {
|
||||
my $name = $paref->{name};
|
||||
my $t = $paref->{t}; # aktuelle Unix-Zeit
|
||||
my $nhour = $paref->{nhour};
|
||||
my $day = $paref->{day};
|
||||
my $histname = $paref->{histname} // qq{};
|
||||
my $ethishour = $paref->{ethishour} // 0;
|
||||
my $calcpv = $paref->{calcpv} // 0;
|
||||
|
||||
my $type = $hash->{TYPE};
|
||||
my $day = strftime "%d", localtime($t); # aktueller Tag
|
||||
|
||||
my $val = q{};
|
||||
|
||||
if($histname eq "pvrl") { # realer Energieertrag
|
||||
@ -2807,7 +2849,6 @@ sub setPVhistory {
|
||||
}
|
||||
|
||||
Log3 ($name, 5, "$name - set PV History hour: $nhour, hash: $histname, val: $val");
|
||||
delete $data{$type}{$name}{pvhist}{$day}{summary};
|
||||
|
||||
return;
|
||||
}
|
||||
@ -3117,7 +3158,7 @@ werden weitere SolarForecast Devices zugeordnet.
|
||||
|
||||
<ul>
|
||||
<a name="currentInverterDev"></a>
|
||||
<li><b>currentInverterDev <Inverter Device Name> pv=<Reading aktuelle PV-Leistung>:<Einheit> etoday=<Reading Energieerzeugung aktueller Tag>:<Einheit> </b> <br>
|
||||
<li><b>currentInverterDev <Inverter Device Name> pv=<Reading aktuelle PV-Leistung>:<Einheit> etotal=<Reading Energieerzeugung total>:<Einheit> </b> <br>
|
||||
Legt ein beliebiges Device zur Lieferung der aktuellen PV Erzeugungswerte fest.
|
||||
<br>
|
||||
|
||||
@ -3125,7 +3166,7 @@ werden weitere SolarForecast Devices zugeordnet.
|
||||
<table>
|
||||
<colgroup> <col width=10%> <col width=90%> </colgroup>
|
||||
<tr><td> <b>pv</b> </td><td>Reading mit aktueller PV-Leistung </td></tr>
|
||||
<tr><td> <b>etoday</b> </td><td>PV Erzeugung des aktuellen Tages beginnend mit 0 um 00:00 Uhr aufsteigend bis zum maximalen täglichen Ertrag am Ende des Tages </td></tr>
|
||||
<tr><td> <b>etotal</b> </td><td>ein stetig aufsteigender Zähler der gesamten erzeugten Energie </td></tr>
|
||||
<tr><td> <b>Einheit</b> </td><td>die jeweilige Einheit (W,kW,Wh,kWh) </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
@ -3133,9 +3174,9 @@ werden weitere SolarForecast Devices zugeordnet.
|
||||
|
||||
<ul>
|
||||
<b>Beispiel: </b> <br>
|
||||
set <name> currentInverterDev STP5000 pv=total_pac:kW etoday=etoday:kWh <br>
|
||||
set <name> currentInverterDev STP5000 pv=total_pac:kW etotal=etotal:kWh <br>
|
||||
# Device STP5000 liefert PV-Werte. Die aktuell erzeugte Leistung im Reading "total_pac" (kW) und die tägliche Erzeugung im
|
||||
Reading "etoday" (kWh)
|
||||
Reading "etotal" (kWh)
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
Loading…
x
Reference in New Issue
Block a user