2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-25 22:15:09 +00:00

76_SolarForecast: contrib 0.82.0

git-svn-id: https://svn.fhem.de/fhem/trunk@27923 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2023-09-03 19:23:00 +00:00
parent 44d27f5b81
commit 067917be2b

View File

@ -30,18 +30,19 @@ package FHEM::SolarForecast; ## no critic 'package'
use strict; use strict;
use warnings; use warnings;
use POSIX; use POSIX;
use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt use GPUtils qw(GP_Import GP_Export); # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
use Time::HiRes qw(gettimeofday tv_interval); use Time::HiRes qw(gettimeofday tv_interval);
eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic 'eval' eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic 'eval'
eval "use FHEM::Utility::CTZ qw(:all);1" or my $ctzAbsent = 1; ## no critic 'eval' eval "use FHEM::Utility::CTZ qw(:all);1;" or my $ctzAbsent = 1; ## no critic 'eval'
use Encode; use Encode;
use Color; use Color;
use utf8; use utf8;
use HttpUtils; use HttpUtils;
eval "use JSON;1;" or my $jsonabs = 'JSON'; ## no critic 'eval' # Debian: apt-get install libjson-perl eval "use JSON;1;" or my $jsonabs = 'JSON'; ## no critic 'eval' # Debian: sudo apt-get install libjson-perl
eval "use AI::DecisionTree;1;" or my $aidtabs = 'AI::DecisionTree'; ## no critic 'eval' eval "use AI::DecisionTree;1;" or my $aidtabs = 'AI::DecisionTree'; ## no critic 'eval'
eval "use Test2::Tools::Class qw(isa_ok);1;" or my $t2sabs = 'Test2::Suite'; ## no critic 'eval' # Debian: sudo apt-get install libtest2-suite-perl
use FHEM::SynoModules::SMUtils qw( use FHEM::SynoModules::SMUtils qw(
evaljson evaljson
@ -49,12 +50,11 @@ use FHEM::SynoModules::SMUtils qw(
delClHash delClHash
moduleVersion moduleVersion
trim trim
); # Hilfsroutinen Modul ); # Hilfsroutinen Modul
use Data::Dumper; use Data::Dumper;
use Storable qw(dclone freeze thaw nstore store retrieve); use Storable qw(dclone freeze thaw nstore store retrieve);
use MIME::Base64; use MIME::Base64;
use Test2::Tools::Class qw(isa_ok);
no if $] >= 5.017011, warnings => 'experimental::smartmatch'; no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Run before module compilation # Run before module compilation
@ -649,8 +649,10 @@ my %hqtxt = (
DE => qq{KI Status:} }, DE => qq{KI Status:} },
aimstt => { EN => qq{Perl module AI::DecisionTree is missing}, aimstt => { EN => qq{Perl module AI::DecisionTree is missing},
DE => qq{Perl Modul AI::DecisionTree ist nicht vorhanden} }, DE => qq{Perl Modul AI::DecisionTree ist nicht vorhanden} },
aiwook => { EN => qq{AI support works properly}, aimmts => { EN => qq{Perl module Test2::Suite is missing},
DE => qq{KI Unterstützung arbeitet einwandfrei} }, DE => qq{Perl Modul Test2::Suite ist nicht vorhanden} },
aiwook => { EN => qq{AI support works properly, but does not provide a value for the current hour},
DE => qq{KI Unterstützung arbeitet einwandfrei, liefert jedoch keinen Wert für die aktuelle Stunde} },
nxtscc => { EN => qq{next SolCast call}, nxtscc => { EN => qq{next SolCast call},
DE => qq{nächste SolCast Abfrage} }, DE => qq{nächste SolCast Abfrage} },
fulfd => { EN => qq{fulfilled}, fulfd => { EN => qq{fulfilled},
@ -4493,9 +4495,6 @@ sub centralTask {
_getRoofTopData ($centpars); # Strahlungswerte/Forecast-Werte in solcastapi-Hash erstellen _getRoofTopData ($centpars); # Strahlungswerte/Forecast-Werte in solcastapi-Hash erstellen
_transferAPIRadiationValues ($centpars); # Raw Erzeugungswerte aus solcastapi-Hash übertragen und Forecast mit/ohne Korrektur erstellen _transferAPIRadiationValues ($centpars); # Raw Erzeugungswerte aus solcastapi-Hash übertragen und Forecast mit/ohne Korrektur erstellen
#aiGetResult ($centpars);
_calcMaxEstimateToday ($centpars); # heutigen Max PV Estimate & dessen Tageszeit ermitteln _calcMaxEstimateToday ($centpars); # heutigen Max PV Estimate & dessen Tageszeit ermitteln
_transferInverterValues ($centpars); # WR Werte übertragen _transferInverterValues ($centpars); # WR Werte übertragen
_transferMeterValues ($centpars); # Energy Meter auswerten _transferMeterValues ($centpars); # Energy Meter auswerten
@ -4924,9 +4923,128 @@ sub __delObsoleteAPIData {
return; return;
} }
################################################################
# Wetter Werte aus dem angebenen Wetterdevice extrahieren
################################################################
sub _transferWeatherValues {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $t = $paref->{t}; # Epoche Zeit
my $chour = $paref->{chour};
my $daref = $paref->{daref};
my $date = $paref->{date}; # aktuelles Datum
my $fcname = ReadingsVal($name, 'currentWeatherDev', ""); # Weather Forecast Device
return if(!$fcname || !$defs{$fcname});
my $err = checkdwdattr ($name,$fcname,\@dweattrmust);
$paref->{state} = $err if($err);
my $type = $paref->{type};
debugLog ($paref, "collectData", "collect Weather data - device: $fcname =>");
my ($time_str);
my $fc0_SunRise = ReadingsVal($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute
my $fc0_SunSet = ReadingsVal($fcname, "fc0_SunSet", "00:00"); # Sonnenuntergang heute
my $fc1_SunRise = ReadingsVal($fcname, "fc1_SunRise", "23:59"); # Sonnenaufgang morgen
my $fc1_SunSet = ReadingsVal($fcname, "fc1_SunSet", "00:00"); # Sonnenuntergang morgen
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_SunRise.':00';
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunRise.':00');
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_SunSet.':00';
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunSet.':00');
debugLog ($paref, "collectData", "sunrise/sunset today: $fc0_SunRise / $fc0_SunSet, sunrise/sunset tomorrow: $fc1_SunRise / $fc1_SunSet");
push @$daref, "Today_SunRise<>". $fc0_SunRise;
push @$daref, "Today_SunSet<>". $fc0_SunSet;
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 $fc1_SunRise_round = sprintf "%02d", (split ":", $fc1_SunRise)[0];
my $fc1_SunSet_round = sprintf "%02d", (split ":", $fc1_SunSet)[0];
for my $num (0..46) {
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
last if($fd > 1);
my $fh1 = $fh+1;
my $fh2 = $fh1 == 24 ? 23 : $fh1;
my $wid = ReadingsNum($fcname, "fc${fd}_${fh2}_ww", -1);
my $neff = ReadingsNum($fcname, "fc${fd}_${fh2}_Neff", 0); # Effektive Wolkendecke
my $r101 = ReadingsNum($fcname, "fc${fd}_${fh2}_R101", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde
my $temp = ReadingsNum($fcname, "fc${fd}_${fh2}_TTT", 0); # Außentemperatur
my $don = 1; # es ist default "Tag"
my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden
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
$don = 0;
}
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
$don = 0;
}
my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", '');
debugLog ($paref, "collectData", "wid: fc${fd}_${fh1}_ww, val: $wid, txt: $txt, cc: $neff, rp: $r101, temp: $temp");
$time_str = "NextHour".sprintf "%02d", $num;
$data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid;
$data{$type}{$name}{nexthours}{$time_str}{cloudcover} = $neff;
$data{$type}{$name}{nexthours}{$time_str}{rainprob} = $r101;
$data{$type}{$name}{nexthours}{$time_str}{temp} = $temp;
$data{$type}{$name}{nexthours}{$time_str}{DoN} = $don;
if($num < 23 && $fh < 24) { # Ringspeicher Weather Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weatherid} = $wid;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weathertxt} = $txt;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wcc} = $neff;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wrp} = $r101;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{temp} = $temp;
if($num == 0) { # aktuelle Außentemperatur
$data{$type}{$name}{current}{temp} = $temp;
}
}
if($fd == 0 && $fh1) { # Weather in pvhistory speichern
$paref->{wid} = $wid;
$paref->{histname} = "weatherid";
$paref->{nhour} = sprintf("%02d",$fh1);
setPVhistory ($paref);
$paref->{wcc} = $neff;
$paref->{histname} = "weathercloudcover";
setPVhistory ($paref);
$paref->{wrp} = $r101;
$paref->{histname} = "weatherrainprob";
setPVhistory ($paref);
$paref->{temp} = $temp;
$paref->{histname} = "temperature";
setPVhistory ($paref);
delete $paref->{histname};
}
}
return;
}
################################################################ ################################################################
# Strahlungsvorhersage Werte aus solcastapi-Hash # Strahlungsvorhersage Werte aus solcastapi-Hash
# übertragen und ggf. manipulieren # übertragen und PV Vorhersage berechnen / in Nexthours
# speichern
################################################################ ################################################################
sub _transferAPIRadiationValues { sub _transferAPIRadiationValues {
my $paref = shift; my $paref = shift;
@ -4957,7 +5075,7 @@ sub _transferAPIRadiationValues {
my $wantts = (timestringToTimestamp ($date.' '.$chour.':00:00')) + ($num * 3600); my $wantts = (timestringToTimestamp ($date.' '.$chour.':00:00')) + ($num * 3600);
my $wantdt = (timestampToTimestring ($wantts, $lang))[1]; my $wantdt = (timestampToTimestring ($wantts, $lang))[1];
my $time_str = "NextHour".sprintf "%02d", $num; my $time_str = 'NextHour'.sprintf "%02d", $num;
my ($hod) = $wantdt =~ /\s(\d{2}):/xs; my ($hod) = $wantdt =~ /\s(\d{2}):/xs;
$hod = sprintf "%02d", int $hod + 1; # Stunde des Tages $hod = sprintf "%02d", int $hod + 1; # Stunde des Tages
@ -4969,6 +5087,7 @@ sub _transferAPIRadiationValues {
type => $type, type => $type,
wantdt => $wantdt, wantdt => $wantdt,
hod => $hod, hod => $hod,
nhidx => $time_str,
num => $num, num => $num,
fh1 => $fh1, fh1 => $fh1,
fd => $fd, fd => $fd,
@ -4984,6 +5103,15 @@ sub _transferAPIRadiationValues {
$data{$type}{$name}{nexthours}{$time_str}{today} = $fd == 0 ? 1 : 0; $data{$type}{$name}{nexthours}{$time_str}{today} = $fd == 0 ? 1 : 0;
$data{$type}{$name}{nexthours}{$time_str}{rad1h} = $rad; $data{$type}{$name}{nexthours}{$time_str}{rad1h} = $rad;
my ($err, $pvaifc) = aiGetResult ($params); # KI Entscheidungen abfragen
if (!$err) {
$data{$type}{$name}{nexthours}{$time_str}{pvaifc} = $pvaifc;
$data{$type}{$name}{current}{aigetresult} = 'ok';
}
else {
$data{$type}{$name}{current}{aigetresult} = $err;
}
if($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350 if($num < 23 && $fh < 24) { # Ringspeicher PV forecast Forum: https://forum.fhem.de/index.php/topic,117864.msg1133350.html#msg1133350
$data{$type}{$name}{circular}{sprintf "%02d",$fh1}{pvfc} = $est; $data{$type}{$name}{circular}{sprintf "%02d",$fh1}{pvfc} = $est;
} }
@ -5393,124 +5521,6 @@ sub _transferInverterValues {
return; return;
} }
################################################################
# Wetter Werte aus dem angebenen Wetterdevice extrahieren
################################################################
sub _transferWeatherValues {
my $paref = shift;
my $hash = $paref->{hash};
my $name = $paref->{name};
my $t = $paref->{t}; # Epoche Zeit
my $chour = $paref->{chour};
my $daref = $paref->{daref};
my $date = $paref->{date}; # aktuelles Datum
my $fcname = ReadingsVal($name, 'currentWeatherDev', ""); # Weather Forecast Device
return if(!$fcname || !$defs{$fcname});
my $err = checkdwdattr ($name,$fcname,\@dweattrmust);
$paref->{state} = $err if($err);
my $type = $paref->{type};
debugLog ($paref, "collectData", "collect Weather data - device: $fcname =>");
my ($time_str);
my $fc0_SunRise = ReadingsVal($fcname, "fc0_SunRise", "23:59"); # Sonnenaufgang heute
my $fc0_SunSet = ReadingsVal($fcname, "fc0_SunSet", "00:00"); # Sonnenuntergang heute
my $fc1_SunRise = ReadingsVal($fcname, "fc1_SunRise", "23:59"); # Sonnenaufgang morgen
my $fc1_SunSet = ReadingsVal($fcname, "fc1_SunSet", "00:00"); # Sonnenuntergang morgen
$data{$type}{$name}{current}{sunriseToday} = $date.' '.$fc0_SunRise.':00';
$data{$type}{$name}{current}{sunriseTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunRise.':00');
$data{$type}{$name}{current}{sunsetToday} = $date.' '.$fc0_SunSet.':00';
$data{$type}{$name}{current}{sunsetTodayTs} = timestringToTimestamp ($date.' '.$fc0_SunSet.':00');
debugLog ($paref, "collectData", "sunrise/sunset today: $fc0_SunRise / $fc0_SunSet, sunrise/sunset tomorrow: $fc1_SunRise / $fc1_SunSet");
push @$daref, "Today_SunRise<>". $fc0_SunRise;
push @$daref, "Today_SunSet<>". $fc0_SunSet;
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 $fc1_SunRise_round = sprintf "%02d", (split ":", $fc1_SunRise)[0];
my $fc1_SunSet_round = sprintf "%02d", (split ":", $fc1_SunSet)[0];
for my $num (0..46) {
my ($fd,$fh) = _calcDayHourMove ($chour, $num);
last if($fd > 1);
my $fh1 = $fh+1;
my $fh2 = $fh1 == 24 ? 23 : $fh1;
my $wid = ReadingsNum($fcname, "fc${fd}_${fh2}_ww", -1);
my $neff = ReadingsNum($fcname, "fc${fd}_${fh2}_Neff", 0); # Effektive Wolkendecke
my $r101 = ReadingsNum($fcname, "fc${fd}_${fh2}_R101", 0); # Niederschlagswahrscheinlichkeit> 0,1 mm während der letzten Stunde
my $temp = ReadingsNum($fcname, "fc${fd}_${fh2}_TTT", 0); # Außentemperatur
my $don = 1; # es ist default "Tag"
my $fhstr = sprintf "%02d", $fh; # hier kann Tag/Nacht-Grenze verstellt werden
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
$don = 0;
}
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
$don = 0;
}
my $txt = ReadingsVal($fcname, "fc${fd}_${fh2}_wwd", '');
debugLog ($paref, "collectData", "wid: fc${fd}_${fh1}_ww, val: $wid, txt: $txt, cc: $neff, rp: $r101, temp: $temp");
$time_str = "NextHour".sprintf "%02d", $num;
$data{$type}{$name}{nexthours}{$time_str}{weatherid} = $wid;
$data{$type}{$name}{nexthours}{$time_str}{cloudcover} = $neff;
$data{$type}{$name}{nexthours}{$time_str}{rainprob} = $r101;
$data{$type}{$name}{nexthours}{$time_str}{temp} = $temp;
$data{$type}{$name}{nexthours}{$time_str}{DoN} = $don;
if($num < 23 && $fh < 24) { # Ringspeicher Weather Forum: https://forum.fhem.de/index.php/topic,117864.msg1139251.html#msg1139251
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weatherid} = $wid;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{weathertxt} = $txt;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wcc} = $neff;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{wrp} = $r101;
$data{$type}{$name}{circular}{sprintf("%02d",$fh1)}{temp} = $temp;
if($num == 0) { # aktuelle Außentemperatur
$data{$type}{$name}{current}{temp} = $temp;
}
}
if($fd == 0 && $fh1) { # Weather in pvhistory speichern
$paref->{wid} = $wid;
$paref->{histname} = "weatherid";
$paref->{nhour} = sprintf("%02d",$fh1);
setPVhistory ($paref);
$paref->{wcc} = $neff;
$paref->{histname} = "weathercloudcover";
setPVhistory ($paref);
$paref->{wrp} = $r101;
$paref->{histname} = "weatherrainprob";
setPVhistory ($paref);
$paref->{temp} = $temp;
$paref->{histname} = "temperature";
setPVhistory ($paref);
delete $paref->{histname};
}
}
return;
}
################################################################ ################################################################
# Werte Meter Device ermitteln und übertragen # Werte Meter Device ermitteln und übertragen
################################################################ ################################################################
@ -8527,14 +8537,16 @@ sub _graphicHeader {
my $aiast = CurrentVal ($hash, 'aiaddistate', 'ok'); my $aiast = CurrentVal ($hash, 'aiaddistate', 'ok');
my $aitit = $aidtabs ? $hqtxt{aimstt}{$lang} : my $aitit = $aidtabs ? $hqtxt{aimstt}{$lang} :
$t2sabs ? $hqtxt{aimmts}{$lang} :
$aiist ne 'ok' ? $hqtxt{ainuse}{$lang} : $aiist ne 'ok' ? $hqtxt{ainuse}{$lang} :
q{}; q{};
my $aiimg = $aidtabs ? FW_makeImage ('--', $aitit) : my $aiimg = $aidtabs ? FW_makeImage ('--', $aitit) :
$t2sabs ? FW_makeImage ('--', $aitit) :
$aiist ne 'ok' ? FW_makeImage ('-', $aitit) : $aiist ne 'ok' ? FW_makeImage ('-', $aitit) :
$aitst ne 'ok' ? FW_makeImage ('10px-kreis-rot.png', $aitst) : $aitst ne 'ok' ? FW_makeImage ('10px-kreis-rot.png', $aitst) :
$aiast ne 'ok' ? FW_makeImage ('10px-kreis-rot.png', $aiast) : $aiast ne 'ok' ? FW_makeImage ('10px-kreis-rot.png', $aiast) :
FW_makeImage ('10px-kreis-gruen.png', $hqtxt{aiwook}{$lang}); FW_makeImage ('10px-kreis-gelb.png', $hqtxt{aiwook}{$lang});
my $aiicon = qq{<a title="$aitit">$aiimg</a>}; my $aiicon = qq{<a title="$aitit">$aiimg</a>};
@ -10568,6 +10580,8 @@ sub aiTrain { ## no critic "not used"
return; return;
} }
####################################################################################
################################################################ ################################################################
# AI Ergebnis für ermitteln # AI Ergebnis für ermitteln
################################################################ ################################################################
@ -10576,50 +10590,49 @@ sub aiGetResult { ## no critic "not used"
my $hash = $paref->{hash}; my $hash = $paref->{hash};
my $name = $paref->{name}; my $name = $paref->{name};
my $type = $paref->{type}; my $type = $paref->{type};
my $hod = $paref->{hod};
my $nhidx = $paref->{nhidx};
return if(!isDWDUsed ($hash)); my $err = 'no decition delivered';
return $err if(!isDWDUsed ($hash) || !$hod || !$nhidx);
my $err;
my $dtree = AiDetreeVal ($hash, undef); my $dtree = AiDetreeVal ($hash, undef);
if (!$dtree) { if (!$dtree) {
($err, $dtree) = aiInit ($paref); ($err, $dtree) = aiInit ($paref);
return if($err); return $err if($err);
} }
for my $idx (sort keys %{$data{$type}{$name}{nexthours}}) { my $rad1h = NexthoursVal ($hash, $nhidx, "rad1h", undef);
my $rad1h = NexthoursVal ($hash, $idx, "rad1h", undef); return "no rad1h for hod: $hod" if(!defined $rad1h);
next if(!defined $rad1h);
my $hod = NexthoursVal ($hash, $idx, "hourofday", undef); my $wcc = NexthoursVal ($hash, $nhidx, "cloudcover", 0);
next if(!defined $hod); my $wrp = NexthoursVal ($hash, $nhidx, "rainprob", 0);
my $temp = NexthoursVal ($hash, $nhidx, "temp", 20);
my $wcc = NexthoursVal ($hash, $idx, "cloudcover", 0); my $pvaifc;
my $wrp = NexthoursVal ($hash, $idx, "rainprob", 0);
my $temp = NexthoursVal ($hash, $idx, "temp", 20);
my $pvfc; eval { $pvaifc = $dtree->get_result (attributes => { rad1h => $rad1h,
temp => $temp,
wcc => $wcc,
wrp => $wrp,
hod => $hod
}
);
};
eval { $pvfc = $dtree->get_result (attributes => { rad1h => $rad1h, if ($@) {
temp => $temp, Log3 ($name, 1, "$name - aiGetResult ERROR: $@");
wcc => $wcc, return $@;
wrp => $wrp,
hod => $hod
}
);
};
if ($@) {
Log3 ($name, 1, "$name - aiGetResult ERROR: $@");
return;
}
if (defined $pvfc) {
debugLog ($paref, 'aiProcess', qq{result AI: pvfc: $pvfc (hod: $hod, rad1h: $rad1h, wcc: $wcc, wrp: $wrp, temp: $temp)});
}
} }
return; if (defined $pvaifc) {
debugLog ($paref, 'aiData', qq{result AI: pvaifc: $pvaifc (hod: $hod, rad1h: $rad1h, wcc: $wcc, wrp: $wrp, temp: $temp)});
return ('', $pvaifc);
}
return $err;
} }
################################################################ ################################################################
@ -10633,8 +10646,9 @@ sub aiInit { ## no critic "not used"
my $err; my $err;
if ($aidtabs) { if ($aidtabs || $t2sabs) {
my $err = qq(The Perl module AI::DecisionTree is missing. Please install it with e.g. "sudo apt-get install libai-decisiontree-perl" for AI support); $err = qq(The Perl module AI::DecisionTree is missing. Please install it with e.g. "sudo apt-get install libai-decisiontree-perl" for AI support) if($aidtabs);
$err = qq(The Perl module Test2::Suite is missing. Please install it with e.g. "sudo apt-get install libtest2-suite-perl") if($t2sabs);
debugLog ($paref, 'aiProcess', $err); debugLog ($paref, 'aiProcess', $err);
$data{$type}{$name}{current}{aiinitstate} = $err; $data{$type}{$name}{current}{aiinitstate} = $err;
return $err; return $err;
@ -11185,24 +11199,25 @@ sub listDataPool {
return qq{NextHours cache is empty.}; return qq{NextHours cache is empty.};
} }
for my $idx (sort keys %{$h}) { for my $idx (sort keys %{$h}) {
my $nhts = NexthoursVal ($hash, $idx, "starttime", "-"); my $nhts = NexthoursVal ($hash, $idx, 'starttime', "-");
my $hod = NexthoursVal ($hash, $idx, "hourofday", "-"); my $hod = NexthoursVal ($hash, $idx, 'hourofday', "-");
my $today = NexthoursVal ($hash, $idx, "today", "-"); my $today = NexthoursVal ($hash, $idx, 'today', "-");
my $pvfc = NexthoursVal ($hash, $idx, "pvforecast", "-"); my $pvfc = NexthoursVal ($hash, $idx, 'pvforecast', "-");
my $wid = NexthoursVal ($hash, $idx, "weatherid", "-"); my $pvaifc = NexthoursVal ($hash, $idx, 'pvaifc', "-"); # PV Forecast der KI
my $neff = NexthoursVal ($hash, $idx, "cloudcover", "-"); my $wid = NexthoursVal ($hash, $idx, 'weatherid', "-");
my $crange = NexthoursVal ($hash, $idx, "cloudrange", "-"); my $neff = NexthoursVal ($hash, $idx, 'cloudcover', "-");
my $r101 = NexthoursVal ($hash, $idx, "rainprob", "-"); my $crange = NexthoursVal ($hash, $idx, 'cloudrange', "-");
my $rad1h = NexthoursVal ($hash, $idx, "rad1h", "-"); my $r101 = NexthoursVal ($hash, $idx, 'rainprob', "-");
my $pvcorrf = NexthoursVal ($hash, $idx, "pvcorrf", "-"); my $rad1h = NexthoursVal ($hash, $idx, 'rad1h', "-");
my $temp = NexthoursVal ($hash, $idx, "temp", "-"); my $pvcorrf = NexthoursVal ($hash, $idx, 'pvcorrf', "-");
my $confc = NexthoursVal ($hash, $idx, "confc", "-"); my $temp = NexthoursVal ($hash, $idx, 'temp', "-");
my $confcex = NexthoursVal ($hash, $idx, "confcEx", "-"); my $confc = NexthoursVal ($hash, $idx, 'confc', "-");
my $don = NexthoursVal ($hash, $idx, "DoN", "-"); my $confcex = NexthoursVal ($hash, $idx, 'confcEx', "-");
my $don = NexthoursVal ($hash, $idx, 'DoN', "-");
$sq .= "\n" if($sq); $sq .= "\n" if($sq);
$sq .= $idx." => starttime: $nhts, hourofday: $hod, today: $today\n"; $sq .= $idx." => starttime: $nhts, hourofday: $hod, today: $today\n";
$sq .= " pvfc: $pvfc, confc: $confc, confcEx: $confcex, DoN: $don\n"; $sq .= " pvfc: $pvfc, pvaifc: $pvaifc, confc: $confc, confcEx: $confcex\n";
$sq .= " wid: $wid, wcc: $neff, wrp: $r101, temp=$temp\n"; $sq .= " DoN: $don, wid: $wid, wcc: $neff, wrp: $r101, temp=$temp\n";
$sq .= " rad1h: $rad1h, crange: $crange, correff: $pvcorrf"; $sq .= " rad1h: $rad1h, crange: $crange, correff: $pvcorrf";
} }
} }
@ -11614,6 +11629,13 @@ sub checkPlantConfig {
$result->{'Common Settings'}{info} = 1; $result->{'Common Settings'}{info} = 1;
} }
if ($t2sabs) {
$result->{'Common Settings'}{state} = $info;
$result->{'Common Settings'}{result} .= qq{The Perl module Test2::Suite is missing. <br>};
$result->{'Common Settings'}{note} .= qq{If you want use AI support, please install it with e.g. "sudo apt-get install libtest2-suite-perl".<br>};
$result->{'Common Settings'}{info} = 1;
}
if (!$pcf || $pcf !~ /on/xs) { if (!$pcf || $pcf !~ /on/xs) {
$result->{'Common Settings'}{state} = $info; $result->{'Common Settings'}{state} = $info;
$result->{'Common Settings'}{result} .= qq{pvCorrectionFactor_Auto is set to "$pcf" <br>}; $result->{'Common Settings'}{result} .= qq{pvCorrectionFactor_Auto is set to "$pcf" <br>};
@ -11624,8 +11646,8 @@ sub checkPlantConfig {
$result->{'Common Settings'}{result} = $hqtxt{fulfd}{$lang}; $result->{'Common Settings'}{result} = $hqtxt{fulfd}{$lang};
$result->{'Common Settings'}{note} .= qq{checked parameters: <br>}; $result->{'Common Settings'}{note} .= qq{checked parameters: <br>};
$result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, event-on-change-reading, ctrlLanguage, global language <br>}; $result->{'Common Settings'}{note} .= qq{pvCorrectionFactor_Auto, event-on-change-reading, ctrlLanguage, global language <br>};
$result->{'Common Settings'}{note} .= qq{checked Perl module: <br>}; $result->{'Common Settings'}{note} .= qq{checked Perl modules: <br>};
$result->{'Common Settings'}{note} .= qq{AI::DecisionTree <br>}; $result->{'Common Settings'}{note} .= qq{AI::DecisionTree, Test2::Suite <br>};
} }
} }
@ -13932,8 +13954,9 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
<tr><td> </td><td>Faktor/0..1 - Qualität der PV Prognose (1 = beste Qualität) </td></tr> <tr><td> </td><td>Faktor/0..1 - Qualität der PV Prognose (1 = beste Qualität) </td></tr>
<tr><td> <b>DoN</b> </td><td>Sonnenauf- und untergangsstatus (0 - Nacht, 1 - Tag) </td></tr> <tr><td> <b>DoN</b> </td><td>Sonnenauf- und untergangsstatus (0 - Nacht, 1 - Tag) </td></tr>
<tr><td> <b>hourofday</b> </td><td>laufende Stunde des Tages </td></tr> <tr><td> <b>hourofday</b> </td><td>laufende Stunde des Tages </td></tr>
<tr><td> <b>pvfc</b> </td><td>erwartete PV Erzeugung (Wh) </td></tr> <tr><td> <b>pvfc</b> </td><td>erwartete PV Erzeugung (Wh) ohne KI Unterstützung </td></tr>
<tr><td> <b>today</b> </td><td>"1" wenn Startdatum am aktuellen Tag </td></tr> <tr><td> <b>pvaifc</b> </td><td>erwartete PV Erzeugung der KI (Wh) </td></tr>
<tr><td> <b>today</b> </td><td>hat Wert '1' wenn Startdatum am aktuellen Tag </td></tr>
<tr><td> <b>rad1h</b> </td><td>vorhergesagte Globalstrahlung </td></tr> <tr><td> <b>rad1h</b> </td><td>vorhergesagte Globalstrahlung </td></tr>
<tr><td> <b>starttime</b> </td><td>Startzeit des Datensatzes </td></tr> <tr><td> <b>starttime</b> </td><td>Startzeit des Datensatzes </td></tr>
<tr><td> <b>temp</b> </td><td>vorhergesagte Außentemperatur </td></tr> <tr><td> <b>temp</b> </td><td>vorhergesagte Außentemperatur </td></tr>
@ -14881,7 +14904,7 @@ die ordnungsgemäße Anlagenkonfiguration geprüft werden.
"Time::HiRes": 0, "Time::HiRes": 0,
"MIME::Base64": 0, "MIME::Base64": 0,
"Storable": 0, "Storable": 0,
"Test2::Tools::Class": 0 "Test2::Suite": 0
}, },
"recommends": { "recommends": {
"FHEM::Meta": 0, "FHEM::Meta": 0,