2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-28 15:04:51 +00:00

93_DbRep: new attrbute avgDailyMeanGWSwithGTS for Grassland temperature sum calculation

git-svn-id: https://svn.fhem.de/fhem/trunk@23141 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2020-11-11 21:41:39 +00:00
parent 884dd3ee29
commit b59e8a693c
2 changed files with 320 additions and 234 deletions

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- feature: 93_DbRep: new attrbute avgDailyMeanGWSwithGTS for Grassland
temperature sum calculation
- feature: 76_SMAPortal: random select the default user agent - feature: 76_SMAPortal: random select the default user agent
- new: 48_MieleAtHome: Module to integrate the Miele@Home API - new: 48_MieleAtHome: Module to integrate the Miele@Home API
- feature: 59_Twilight: add experimental option: myUtils forecast code - feature: 59_Twilight: add experimental option: myUtils forecast code

@ -56,7 +56,8 @@ use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
no if $] >= 5.017011, warnings => 'experimental::smartmatch'; no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Version History intern # Version History intern
our %DbRep_vNotesIntern = ( my %DbRep_vNotesIntern = (
"8.41.0" => "08.11.2020 new attrbute avgDailyMeanGWSwithGTS for Grassland temperature sum, minor bugfixes in create time array ",
"8.40.8" => "17.09.2020 sqlCmd supports PREPARE statament Forum: #114293, commandRef revised ", "8.40.8" => "17.09.2020 sqlCmd supports PREPARE statament Forum: #114293, commandRef revised ",
"8.40.7" => "03.09.2020 rename getter dbValue to sqlCmdBlocking, consider attr timeout in function DbRep_sqlCmdBlocking (blocking function), commandRef revised ", "8.40.7" => "03.09.2020 rename getter dbValue to sqlCmdBlocking, consider attr timeout in function DbRep_sqlCmdBlocking (blocking function), commandRef revised ",
"8.40.6" => "27.08.2020 commandRef revised ", "8.40.6" => "27.08.2020 commandRef revised ",
@ -87,56 +88,11 @@ our %DbRep_vNotesIntern = (
"8.30.4" => "22.01.2020 adjust behavior of OutputWriteToDB (averageValue,sumValue) - write value at every begin and also at every end of period ". "8.30.4" => "22.01.2020 adjust behavior of OutputWriteToDB (averageValue,sumValue) - write value at every begin and also at every end of period ".
"Forum: https://forum.fhem.de/index.php/topic,105787.msg1013920.html#msg1013920 ". "Forum: https://forum.fhem.de/index.php/topic,105787.msg1013920.html#msg1013920 ".
"fix Warning when Agent has detected a renamed device", "fix Warning when Agent has detected a renamed device",
"8.30.3" => "28.11.2019 countEntries encode \$device, change count_ParseDone for \"countEntriesDetail\" ",
"8.30.2" => "24.11.2019 change order of delete(\$hash->{HELPER}{RUNNING_PID}) in *_ParseDone routines, Forum: https://forum.fhem.de/index.php/topic,105591.msg996089.html#msg996089 ",
"8.30.1" => "22.11.2019 commandref revised ",
"8.30.0" => "14.11.2019 new command set adminCredentials and get storedCredentials, attribute useAdminCredentials ",
"8.29.1" => "11.11.2019 commandref revised ",
"8.29.0" => "08.11.2019 add option FullDay for timeDiffToNow and timeOlderThan, Forum: https://forum.fhem.de/index.php/topic,53584.msg991139.html#msg991139 ",
"8.28.2" => "18.10.2019 change SQL selection in deldoublets_DoParse due to Incompatible change of MySQL 8.0.13, Forum: https://forum.fhem.de/index.php/topic,104593.msg985007.html#msg985007 ",
"8.28.1" => "09.10.2019 fix warnings line 5173 ",
"8.28.0" => "30.09.2019 seqDoubletsVariance - separate specification of positive and negative variance possible, Forum: https://forum.fhem.de/index.php/topic,53584.msg959963.html#msg959963 ",
"8.27.2" => "27.09.2019 fix export data to file, fix delDoublets if MySQL and VALUE contains \, fix readingRename without leading device ",
"8.27.1" => "22.09.2019 comma are shown in sqlCmdHistory, Forum: #103908 ",
"8.27.0" => "15.09.2019 save memory usage by eliminating \$hash -> {dbloghash}, fix warning uninitialized value \$idevice in split ",
"8.26.0" => "07.09.2019 make SQL Wildcard (\%) possible as placeholder in a reading list: https://forum.fhem.de/index.php/topic,101756.0.html ".
"sub DbRep_createUpdateSql deleted, new sub DbRep_createCommonSql ",
"8.25.0" => "01.09.2019 make SQL Wildcard (\%) possible as placeholder in a device list: https://forum.fhem.de/index.php/topic,101756.0.html ".
"sub DbRep_modAssociatedWith changed ",
"8.24.0" => "24.08.2019 devices marked as \"Associated With\" if possible, fhem.pl 20069 2019-08-27 08:36:02Z is needed ",
"8.23.1" => "26.08.2019 fix add newline at the end of DbRep_sqlCmdBlocking result, Forum: #103295 ",
"8.23.0" => "24.08.2019 prepared for devices marked as \"Associated With\" if possible ",
"8.22.0" => "23.08.2019 new attr fetchValueFn. When fetching the database content, manipulate the VALUE-field before create reading ",
"8.21.2" => "14.08.2019 commandRef revised ",
"8.21.1" => "31.05.2019 syncStandby considers executeBeforeProc, commandRef revised ",
"8.21.0" => "28.04.2019 implement FHEM command \"dbReadingsVal\" ",
"8.20.1" => "28.04.2019 set index verbose changed, check index \"Report_Idx\" in getInitData ",
"8.20.0" => "27.04.2019 don't save hash refs in central hash to prevent potential memory leak, new set \"index\" ".
"command, \"repository\" added in Meta.json ",
"8.19.1" => "10.04.2019 adjust \$hash->{HELPER}{IDRETRIES} if value is negative ",
"8.19.0" => "04.04.2019 explain is possible in sqlCmd ",
"8.18.0" => "01.04.2019 new aggregation year ",
"8.17.2" => "28.03.2019 consideration of daylight saving time/leap year changed (func DbRep_corrRelTime) ",
"8.17.1" => "24.03.2019 edit Meta data, activate Meta.pm, prevent module from deactivation in case of unavailable Meta.pm ",
"8.17.0" => "20.03.2019 prepare for Meta.pm, new attribute \"sqlCmdVars\" ",
"8.16.0" => "17.03.2019 include sortTopicNum from 99_Utils, allow PRAGMAS leading an SQLIte SQL-Statement in sqlCmd, switch to DbRep_setVersionInfo ",
"8.15.0" => "04.03.2019 readingsRename can rename readings of a given (optional) device ",
"8.14.1" => "04.03.2019 Bugfix in deldoublets with SQLite, Forum: https://forum.fhem.de/index.php/topic,53584.msg914489.html#msg914489 ",
"8.14.0" => "19.02.2019 delete Readings if !goodReadingName and featurelevel > 5.9 ",
"8.13.0" => "11.02.2019 executeBeforeProc / executeAfterProc for sumValue, maxValue, minValue, diffValue, averageValue ",
"8.12.0" => "10.02.2019 executeBeforeProc / executeAfterProc for sqlCmd ",
"8.11.2" => "03.02.2019 fix no running tableCurrentFillup if database is closed ",
"8.11.1" => "25.01.2019 fix sort of versionNotes ",
"8.11.0" => "24.01.2019 command exportToFile or attribute \"expimpfile\" accepts option \"MAXLINES=\" ",
"8.10.1" => "23.01.2019 change DbRep_charfilter to eliminate \xc2",
"8.10.0" => "19.01.2019 sqlCmd, sqlCmdBlocking may input SQL session variables, Forum:#96082 ",
"8.9.10" => "18.01.2019 fix warnings Malformed UTF-8 character during importFromFile, Forum:#96056 ",
"8.9.9" => "06.01.2019 diffval_DoParse: 'ORDER BY TIMESTAMP' added to statements Forum:https://forum.fhem.de/index.php/topic,53584.msg882082.html#msg882082",
"1.0.0" => "19.05.2016 Initial" "1.0.0" => "19.05.2016 Initial"
); );
# Version History extern: # Version History extern:
our %DbRep_vNotesExtern = ( my %DbRep_vNotesExtern = (
"8.40.7" => "03.09.2020 The get Command \"dbValue\" has been renamed to \"sqlCmdBlocking\. You can use \"dbValue\" furthermore in your scripts, but it is ". "8.40.7" => "03.09.2020 The get Command \"dbValue\" has been renamed to \"sqlCmdBlocking\. You can use \"dbValue\" furthermore in your scripts, but it is ".
"deprecated and will be removed soon. Please change your scripts to use \"sqlCmdBlocking\" instead. ", "deprecated and will be removed soon. Please change your scripts to use \"sqlCmdBlocking\" instead. ",
"8.40.4" => "23.07.2020 The new aggregation type 'minute' is now available. ", "8.40.4" => "23.07.2020 The new aggregation type 'minute' is now available. ",
@ -287,7 +243,15 @@ our %DbRep_vNotesExtern = (
); );
# Hint Hash en # Hint Hash en
our %DbRep_vHintsExt_en = ( my %DbRep_vHintsExt_en = (
"5" => "The grassland temperature sum (GTS) is a special form of the growth degree days, which is used in agricultural meteorology. ".
"It is used to determine the date for the beginning of field work after winter in Central Europe.<br> ".
"All positive daily averages are recorded from the beginning of the year. In January is multiplied by the factor 0.5, in February ".
" by the factor 0.75, and from March onwards the „full“ daily value (times factor 1) is then included in the calculation.<br> ".
"If the sum of 200 is exceeded in spring, the sustainable vegetation start is reached. The background is the ".
" nitrogen uptake and processing of the soil, which is dependent on this temperature sum. In middle latitudes ".
"this is usually achieved in the course of March, at the turn from early spring to mid-spring. <br>".
"(see also <a href=\"https://de.wikipedia.org/wiki/Gr%C3%BCnlandtemperatursumme\">Grünlandtemperatursumme in Wikipedia</a>) ",
"4" => "The attribute 'valueFilter' can specify a REGEXP expression that is used for additional field selection as described in set-function. " "4" => "The attribute 'valueFilter' can specify a REGEXP expression that is used for additional field selection as described in set-function. "
."If you need more assistance please to the manual of your used database. For example the overview about REGEXP for " ."If you need more assistance please to the manual of your used database. For example the overview about REGEXP for "
."MariaDB refer to <a href=\"https://mariadb.com/kb/en/library/regular-expressions-overview\">Regular Expressions " ."MariaDB refer to <a href=\"https://mariadb.com/kb/en/library/regular-expressions-overview\">Regular Expressions "
@ -306,11 +270,19 @@ our %DbRep_vHintsExt_en = (
); );
# Hint Hash de # Hint Hash de
our %DbRep_vHintsExt_de = ( my %DbRep_vHintsExt_de = (
"4" => "Im Attribut 'valueFilter' können REGEXP zur erweiterten Feldselektion angegeben werden. Welche Felder berücksichtigt " "5" => "Die Grünlandtemperatursumme (GTS) ist eine Spezialform der Wachstumsgradtage, die in der Agrarmeteorologie verwendet wird. ".
."werden, ist in der jeweiligen set-Funktion beschrieben. Für weitere Hilfe bitte die REGEXP-Dokumentation ihrer " "Sie wird herangezogen, um in Mitteleuropa den Termin für das Einsetzen der Feldarbeit nach dem Winter zu bestimmen.<br> ".
."verwendeten Datenbank konsultieren. Ein Überblick über REGEXP mit MariaDB ist zum Beispiel hier verfügbar:<br>" "Es werden ab Jahresbeginn alle positiven Tagesmittel erfasst. Im Januar wird mit dem Faktor 0,5 multipliziert, im Februar ".
."<a href=\"https://mariadb.com/kb/en/library/regular-expressions-overview\">Regular Expressions Overview</a>. ", "mit dem Faktor 0,75, und ab März geht dann der „volle“ Tageswert (mal Faktor 1) in die Rechnung ein.<br> ".
"Wird im Frühjahr die Summe von 200 überschritten, ist der nachhaltige Vegetationsbeginn erreicht. Hintergrund ist die ".
"Stickstoffaufnahme und -verarbeitung des Bodens, welcher von dieser Temperatursumme abhängig ist. In mittleren Breiten ".
"wird das meist im Laufe des März, an der Wende von Vorfrühling zu Mittfrühling erreicht. <br>".
"(siehe auch <a href=\"https://de.wikipedia.org/wiki/Gr%C3%BCnlandtemperatursumme\">Grünlandtemperatursumme in Wikipedia</a>) ",
"4" => "Im Attribut 'valueFilter' können REGEXP zur erweiterten Feldselektion angegeben werden. Welche Felder berücksichtigt ".
"werden, ist in der jeweiligen set-Funktion beschrieben. Für weitere Hilfe bitte die REGEXP-Dokumentation ihrer ".
"verwendeten Datenbank konsultieren. Ein Überblick über REGEXP mit MariaDB ist zum Beispiel hier verfügbar:<br>".
"<a href=\"https://mariadb.com/kb/en/library/regular-expressions-overview\">Regular Expressions Overview</a>. ",
"3" => "Merkmale und Restriktionen von komplexen <a href=\"https://fhem.de/commandref_DE.html#devspec\">Geräte-Spezifikationen (devspec) ", "3" => "Merkmale und Restriktionen von komplexen <a href=\"https://fhem.de/commandref_DE.html#devspec\">Geräte-Spezifikationen (devspec) ",
"2" => "Mit dem gesetzten Attribut <b>averageCalcForm = avgDailyMeanGWS</b> wird die Durchschnittsauswertung nach den Vorgaben des ". "2" => "Mit dem gesetzten Attribut <b>averageCalcForm = avgDailyMeanGWS</b> wird die Durchschnittsauswertung nach den Vorgaben des ".
"deutschen Wetterdienstes vorgenommen.<br> Seit dem 01.04.2001 wurde der Standard wie folgt festgelegt: <br>". "deutschen Wetterdienstes vorgenommen.<br> Seit dem 01.04.2001 wurde der Standard wie folgt festgelegt: <br>".
@ -352,7 +324,7 @@ sub DbRep_Initialize {
"reading ". "reading ".
"allowDeletion:1,0 ". "allowDeletion:1,0 ".
"autoForward:textField-long ". "autoForward:textField-long ".
"averageCalcForm:avgArithmeticMean,avgDailyMeanGWS,avgTimeWeightMean ". "averageCalcForm:avgArithmeticMean,avgDailyMeanGWS,avgDailyMeanGWSwithGTS,avgTimeWeightMean ".
"countEntriesDetail:1,0 ". "countEntriesDetail:1,0 ".
"device " . "device " .
"dumpComment ". "dumpComment ".
@ -763,10 +735,12 @@ sub DbRep_Set {
} elsif ($opt =~ m/delEntries|tableCurrentPurge/ && $hash->{ROLE} ne "Agent") { } elsif ($opt =~ m/delEntries|tableCurrentPurge/ && $hash->{ROLE} ne "Agent") {
$hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; $hash->{LASTCMD} = $prop?"$opt $prop":"$opt";
delete $hash->{HELPER}{DELENTRIES};
if (!AttrVal($hash->{NAME}, "allowDeletion", undef)) { if (!AttrVal($hash->{NAME}, "allowDeletion", undef)) {
return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !";
} }
delete $hash->{HELPER}{DELENTRIES};
shift @a; shift @a;
shift @a; shift @a;
$hash->{HELPER}{DELENTRIES} = \@a if(@a); $hash->{HELPER}{DELENTRIES} = \@a if(@a);
@ -2009,16 +1983,18 @@ sub DbRep_Main {
$hash->{HELPER}{RUNNING_PID} = BlockingCall("minval_DoParse", "$name§$device§$reading§$prop§$ts", "minval_ParseDone", $to, "DbRep_ParseAborted", $hash); $hash->{HELPER}{RUNNING_PID} = BlockingCall("minval_DoParse", "$name§$device§$reading§$prop§$ts", "minval_ParseDone", $to, "DbRep_ParseAborted", $hash);
} elsif ($opt eq "delEntries") { } elsif ($opt eq "delEntries") {
delete $hash->{HELPER}{DELENTRIES};
if($IsTimeSet || $IsAggrSet) { # Forum:#113202 if($IsTimeSet || $IsAggrSet) { # Forum:#113202
my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = ($runtime_string_first =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = $runtime_string_first =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x;
my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = ($runtime_string_next =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = $runtime_string_next =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x;
my $nthants = timelocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900); my $nthants = fhemTimeLocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900);
my $othants = timelocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900); my $othants = fhemTimeLocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900);
if($nthants > $othants) { if($nthants > $othants) {
ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The <nn> (days newer than) option must be greater than the <no> (older than) one !", 1); ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The <nn> (days newer than) option must be greater than the <no> (older than) one !", 1);
return; return;
} }
} }
$hash->{HELPER}{RUNNING_PID} = BlockingCall("del_DoParse", "$name|history|$device|$reading|$runtime_string_first|$runtime_string_next", "del_ParseDone", $to, "DbRep_ParseAborted", $hash); $hash->{HELPER}{RUNNING_PID} = BlockingCall("del_DoParse", "$name|history|$device|$reading|$runtime_string_first|$runtime_string_next", "del_ParseDone", $to, "DbRep_ParseAborted", $hash);
} elsif ($opt eq "tableCurrentPurge") { } elsif ($opt eq "tableCurrentPurge") {
@ -2110,17 +2086,19 @@ sub DbRep_Main {
} }
if ($opt =~ /reduceLog/) { if ($opt =~ /reduceLog/) {
my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = ($runtime_string_first =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); delete $hash->{HELPER}{REDUCELOG};
my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = ($runtime_string_next =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = $runtime_string_first =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x;
my $nthants = timelocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900); my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = $runtime_string_next =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x;
my $othants = timelocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900); my $nthants = fhemTimeLocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900);
my $othants = fhemTimeLocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900);
if($nthants > $othants) { if($nthants > $othants) {
ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The <nn> (days newer than) option must be greater than the <no> (older than) one !", 1); ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The <nn> (days newer than) option must be greater than the <no> (older than) one !", 1);
return; return;
} }
$hash->{HELPER}{RUNNING_REDUCELOG} = BlockingCall("DbRep_reduceLog", "$name|$device|$reading|$runtime_string_first|$runtime_string_next", "DbRep_reduceLogDone", $to, "DbRep_reduceLogAborted", $hash); $hash->{HELPER}{RUNNING_REDUCELOG} = BlockingCall("DbRep_reduceLog", "$name|$device|$reading|$runtime_string_first|$runtime_string_next", "DbRep_reduceLogDone", $to, "DbRep_reduceLogAborted", $hash);
ReadingsSingleUpdateValue ($hash, "state", "reduceLog database is running - be patient and see Logfile !", 1);
$hash->{HELPER}{RUNNING_REDUCELOG}{loglevel} = 5 if($hash->{HELPER}{RUNNING_REDUCELOG}); # Forum #77057 $hash->{HELPER}{RUNNING_REDUCELOG}{loglevel} = 5 if($hash->{HELPER}{RUNNING_REDUCELOG}); # Forum #77057
ReadingsSingleUpdateValue ($hash, "state", "reduceLog database is running - be patient and see Logfile !", 1);
return; return;
} }
@ -2133,7 +2111,9 @@ return;
# Create zentrales Timsstamp-Array # Create zentrales Timsstamp-Array
################################################################################################################ ################################################################################################################
sub DbRep_createTimeArray { sub DbRep_createTimeArray {
my ($hash,$aggregation,$opt) = @_; my $hash = shift;
my $aggregation = shift;
my $opt = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
# year als Jahre seit 1900 # year als Jahre seit 1900
@ -2143,14 +2123,13 @@ sub DbRep_createTimeArray {
my ($tsbegin,$tsend,$dim,$tsub,$tadd); my ($tsbegin,$tsend,$dim,$tsub,$tadd);
my ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear); my ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear);
# absolute Auswertungszeiträume statische und dynamische (Beginn / Ende) berechnen # absolute Auswertungszeiträume statische und dynamische (Beginn / Ende) berechnen
if($hash->{HELPER}{MINTS} && $hash->{HELPER}{MINTS} =~ m/0000-00-00/) { if($hash->{HELPER}{MINTS} && $hash->{HELPER}{MINTS} =~ m/0000-00-00/) {
Log3 ($name, 1, "DbRep $name - ERROR - wrong timestamp \"$hash->{HELPER}{MINTS}\" found in database. Please delete it !"); Log3 ($name, 1, "DbRep $name - ERROR - wrong timestamp \"$hash->{HELPER}{MINTS}\" found in database. Please delete it !");
delete $hash->{HELPER}{MINTS}; delete $hash->{HELPER}{MINTS};
} }
my $mints = $hash->{HELPER}{MINTS}?$hash->{HELPER}{MINTS}:"1970-01-01 01:00:00"; # Timestamp des 1. Datensatzes verwenden falls ermittelt my $mints = $hash->{HELPER}{MINTS} // "1970-01-01 01:00:00"; # Timestamp des 1. Datensatzes verwenden falls ermittelt
$tsbegin = AttrVal($name, "timestamp_begin", $mints); $tsbegin = AttrVal($name, "timestamp_begin", $mints);
$tsbegin = DbRep_formatpicker($tsbegin); $tsbegin = DbRep_formatpicker($tsbegin);
$tsend = AttrVal($name, "timestamp_end", strftime "%Y-%m-%d %H:%M:%S", localtime(time)); $tsend = AttrVal($name, "timestamp_end", strftime "%Y-%m-%d %H:%M:%S", localtime(time));
@ -2168,11 +2147,14 @@ sub DbRep_createTimeArray {
my $dep = $4; my $dep = $4;
my $c = ($mon+1).$mday; my $c = ($mon+1).$mday;
my $e = $mep.$dep; my $e = $mep.$dep;
if ($mep <= $mbp && $c <= $e) { if ($mep <= $mbp && $c <= $e) {
$ybp--; $ybp--;
} else { }
else {
$yep++; $yep++;
} }
$tsbegin = "$ybp-$mbp-$dbp 00:00:00"; $tsbegin = "$ybp-$mbp-$dbp 00:00:00";
$tsend = "$yep-$mep-$dep 23:59:59"; $tsend = "$yep-$mep-$dep 23:59:59";
} }
@ -2367,12 +2349,12 @@ sub DbRep_createTimeArray {
$tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_begin"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_begin");
} }
if (AttrVal($name, "timestamp_begin", "") eq "previous_hour_end" || if (AttrVal($name, "timestamp_begin", "") eq "previous_hour_end" || AttrVal($name, "timestamp_end", "") eq "previous_hour_end") {
AttrVal($name, "timestamp_end", "") eq "previous_hour_end") {
$rhour = $hour-1; $rhour = $hour-1;
$rmday = $mday; $rmday = $mday;
$rmon = $mon; $rmon = $mon;
$ryear = $year; $ryear = $year;
if($rhour<0) { if($rhour<0) {
$rhour = 23; $rhour = 23;
$rmday = $mday-1; $rmday = $mday-1;
@ -2385,33 +2367,31 @@ sub DbRep_createTimeArray {
$rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11)
} }
} }
$tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_hour_end"); $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_hour_end");
$tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_end");
} }
# extrahieren der Einzelwerte von Datum/Zeit Beginn my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = $tsbegin =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x; # extrahieren der Einzelwerte von Datum/Zeit Beginn
my ($yyyy1, $mm1, $dd1, $hh1, $min1, $sec1) = ($tsbegin =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = $tsend =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/x; # extrahieren der Einzelwerte von Datum/Zeit Ende
# extrahieren der Einzelwerte von Datum/Zeit Ende
my ($yyyy2, $mm2, $dd2, $hh2, $min2, $sec2) = ($tsend =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/);
# relative Zeit normieren my ($timeolderthan,$timedifftonow,$fdopt) = DbRep_normRelTime($hash); # relative Zeit normieren
my ($timeolderthan,$timedifftonow,$fdopt) = DbRep_normRelTime($hash);
### relative Auswertungszeit Beginn berücksichtigen, Umwandeln in Epochesekunden Beginn ### ### relative Auswertungszeit Beginn berücksichtigen, Umwandeln in Epochesekunden Beginn ###
my $epoch_seconds_begin = timelocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900) if($tsbegin); my $epoch_seconds_begin = fhemTimeLocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900) if($tsbegin);
if($timedifftonow) { if($timedifftonow) {
$epoch_seconds_begin = time() - $timedifftonow; $epoch_seconds_begin = time() - $timedifftonow;
Log3 ($name, 4, "DbRep $name - Time difference to current time for calculating Timestamp begin: $timedifftonow sec"); Log3 ($name, 4, "DbRep $name - Time difference to current time for calculating Timestamp begin: $timedifftonow sec");
} elsif ($timeolderthan) { }
my $mints = $hash->{HELPER}{MINTS}?$hash->{HELPER}{MINTS}:"1970-01-01 01:00:00"; # Timestamp des 1. Datensatzes verwenden falls ermittelt elsif ($timeolderthan) {
$mints =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/; $mints =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/;
$epoch_seconds_begin = timelocal($6, $5, $4, $3, $2-1, $1-1900); $epoch_seconds_begin = fhemTimeLocal ($6, $5, $4, $3, $2-1, $1-1900);
} }
if($fdopt) { # FullDay Option ist gesetzt if($fdopt) { # FullDay Option ist gesetzt
my $tbs = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin); my $tbs = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin);
$tbs =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/; $tbs =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/;
$epoch_seconds_begin = timelocal(00, 00, 00, $3, $2-1, $1-1900); $epoch_seconds_begin = fhemTimeLocal(00, 00, 00, $3, $2-1, $1-1900);
} }
my $tsbegin_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin); my $tsbegin_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin);
@ -2422,7 +2402,8 @@ sub DbRep_createTimeArray {
########################################################################################### ###########################################################################################
### relative Auswertungszeit Ende berücksichtigen, Umwandeln in Epochesekunden Endezeit ### ### relative Auswertungszeit Ende berücksichtigen, Umwandeln in Epochesekunden Endezeit ###
my $epoch_seconds_end = timelocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900); my $epoch_seconds_end = fhemTimeLocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900);
if($timeolderthan) { if($timeolderthan) {
$epoch_seconds_end = time() - $timeolderthan; $epoch_seconds_end = time() - $timeolderthan;
} }
@ -2431,7 +2412,7 @@ sub DbRep_createTimeArray {
if($fdopt) { # FullDay Option ist gesetzt if($fdopt) { # FullDay Option ist gesetzt
my $tes = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end); my $tes = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end);
$tes =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/; $tes =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/;
$epoch_seconds_end = timelocal(59, 59, 23, $3, $2-1, $1-1900); $epoch_seconds_end = fhemTimeLocal(59, 59, 23, $3, $2-1, $1-1900);
} }
my $tsend_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end); my $tsend_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end);
@ -2768,7 +2749,7 @@ return ($runtime,$runtime_string,$runtime_string_first,$runtime_string_next,$ll)
# nichtblockierende DB-Abfrage averageValue # nichtblockierende DB-Abfrage averageValue
#################################################################################################### ####################################################################################################
sub averval_DoParse { sub averval_DoParse {
my ($string) = @_; my $string = shift;
my ($name,$device,$reading,$prop,$ts) = split("\\§", $string); my ($name,$device,$reading,$prop,$ts) = split("\\§", $string);
my $hash = $defs{$name}; my $hash = $defs{$name};
my $dbloghash = $defs{$hash->{HELPER}{DBLOGDEVICE}}; my $dbloghash = $defs{$hash->{HELPER}{DBLOGDEVICE}};
@ -2778,61 +2759,67 @@ sub averval_DoParse {
my $dbpassword = $attr{"sec$dblogname"}{secret}; my $dbpassword = $attr{"sec$dblogname"}{secret};
my $acf = AttrVal($name, "averageCalcForm", "avgArithmeticMean"); # Festlegung Berechnungsschema f. Mittelwert my $acf = AttrVal($name, "averageCalcForm", "avgArithmeticMean"); # Festlegung Berechnungsschema f. Mittelwert
my $qlf = "avg"; my $qlf = "avg";
my ($gts,$gtsstr) = (0,q{}); # Variablen für Grünlandtemperatursumme GTS
my $gtsreached;
my ($dbh,$sql,$sth,$err,$selspec,$addon); my ($dbh,$sql,$sth,$err,$selspec,$addon);
# Background-Startzeit my $bst = [gettimeofday]; # Background-Startzeit
my $bst = [gettimeofday];
eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; eval { $dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0,
if ($@) { RaiseError => 1,
$err = encode_base64($@,""); AutoInactiveDestroy => 1
}
); 1;
}
or do { $err = encode_base64($@,"");
Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 2, "DbRep $name - $@");
return "$name|''|$device|$reading|''|$err|''"; return "$name|''|$device|$reading|''|$err|''";
} };
# only for this block because of warnings if details of readings are not set
no warnings 'uninitialized'; no warnings 'uninitialized';
# ist Zeiteingrenzung und/oder Aggregation gesetzt ? (wenn ja -> "?" in SQL sonst undef) my ($IsTimeSet,$IsAggrSet) = DbRep_checktimeaggr($hash); # ist Zeiteingrenzung und/oder Aggregation gesetzt ? (wenn ja -> "?" in SQL sonst undef)
my ($IsTimeSet,$IsAggrSet) = DbRep_checktimeaggr($hash);
Log3 ($name, 5, "DbRep $name - IsTimeSet: $IsTimeSet, IsAggrSet: $IsAggrSet"); Log3 ($name, 5, "DbRep $name - IsTimeSet: $IsTimeSet, IsAggrSet: $IsAggrSet");
# Timestampstring to Array my @ts = split("\\|", $ts); # Timestampstring to Array
my @ts = split("\\|", $ts);
Log3 ($name, 5, "DbRep $name - Timestamp-Array: \n@ts"); Log3 ($name, 5, "DbRep $name - Timestamp-Array: \n@ts");
if($acf eq "avgArithmeticMean") { if($acf eq "avgArithmeticMean") { # arithmetischer Mittelwert
# arithmetischer Mittelwert
# vorbereiten der DB-Abfrage, DB-Modell-abhaengig # vorbereiten der DB-Abfrage, DB-Modell-abhaengig
$addon = ''; $addon = '';
if ($dbloghash->{MODEL} eq "POSTGRESQL") { if ($dbloghash->{MODEL} eq "POSTGRESQL") {
$selspec = "AVG(VALUE::numeric)"; $selspec = "AVG(VALUE::numeric)";
} elsif ($dbloghash->{MODEL} eq "MYSQL") { }
elsif ($dbloghash->{MODEL} eq "MYSQL") {
$selspec = "AVG(VALUE)"; $selspec = "AVG(VALUE)";
} elsif ($dbloghash->{MODEL} eq "SQLITE") { }
elsif ($dbloghash->{MODEL} eq "SQLITE") {
$selspec = "AVG(VALUE)"; $selspec = "AVG(VALUE)";
} else { }
else {
$selspec = "AVG(VALUE)"; $selspec = "AVG(VALUE)";
} }
$qlf = "avgam"; $qlf = "avgam";
} elsif ($acf eq "avgDailyMeanGWS") { }
# Tagesmittelwert Temperaturen nach Schema des deutschen Wetterdienstes elsif ($acf =~ /avgDailyMeanGWS/x) { # Tagesmittelwert Temperaturen nach Schema des deutschen Wetterdienstes
# SELECT VALUE FROM history WHERE DEVICE="MyWetter" AND READING="temperature" AND TIMESTAMP >= "2018-01-28 $i:00:00" AND TIMESTAMP <= "2018-01-28 ($i+1):00:00" ORDER BY TIMESTAMP DESC LIMIT 1; # SELECT VALUE FROM history WHERE DEVICE="MyWetter" AND READING="temperature" AND TIMESTAMP >= "2018-01-28 $i:00:00" AND TIMESTAMP <= "2018-01-28 ($i+1):00:00" ORDER BY TIMESTAMP DESC LIMIT 1;
$addon = "ORDER BY TIMESTAMP DESC LIMIT 1"; $addon = "ORDER BY TIMESTAMP DESC LIMIT 1";
$selspec = "VALUE"; $selspec = "VALUE";
$qlf = "avgdmgws"; $qlf = "avgdmgws";
} elsif ($acf eq "avgTimeWeightMean") { }
elsif ($acf eq "avgTimeWeightMean") {
$addon = "ORDER BY TIMESTAMP ASC"; $addon = "ORDER BY TIMESTAMP ASC";
$selspec = "TIMESTAMP,VALUE"; $selspec = "TIMESTAMP,VALUE";
$qlf = "avgtwm"; $qlf = "avgtwm";
} }
# SQL-Startzeit my $st = [gettimeofday]; # SQL-Startzeit
my $st = [gettimeofday];
# DB-Abfrage zeilenweise für jeden Array-Eintrag my ($arrstr,$wrstr,@rsf,@rsn,@wsf,@wsn); # DB-Abfrage zeilenweise für jeden Array-Eintrag
my ($arrstr,$wrstr,@rsf,@rsn,@wsf,@wsn);
foreach my $row (@ts) { for my $row (@ts) {
my @a = split("#", $row); my @a = split("#", $row);
my $runtime_string = $a[0]; my $runtime_string = $a[0];
my $runtime_string_first = $a[1]; my $runtime_string_first = $a[1];
@ -2843,20 +2830,21 @@ sub averval_DoParse {
# #
if ($IsTimeSet || $IsAggrSet) { if ($IsTimeSet || $IsAggrSet) {
$sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon);
} else { }
else {
$sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon);
} }
Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); Log3 ($name, 4, "DbRep $name - SQL execute: $sql");
eval{ $sth = $dbh->prepare($sql); eval{ $sth = $dbh->prepare($sql);
$sth->execute(); $sth->execute();
}; 1;
if ($@) { }
$err = encode_base64($@,""); or do { $err = encode_base64($@,"");
Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 2, "DbRep $name - $@");
$dbh->disconnect; $dbh->disconnect;
return "$name|''|$device|$reading|''|$err|''"; return "$name|''|$device|$reading|''|$err|''";
} };
my @line = $sth->fetchrow_array(); my @line = $sth->fetchrow_array();
@ -2867,11 +2855,13 @@ sub averval_DoParse {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."_".$rsf[1]."|"; $arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."_".$rsf[1]."|";
} elsif ($aval eq "minute") { }
elsif ($aval eq "minute") {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|"; $arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|";
} else { }
else {
@rsf = split(" ",$runtime_string_first); @rsf = split(" ",$runtime_string_first);
@rsn = split(" ",$runtime_string_next); @rsn = split(" ",$runtime_string_next);
$arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."|"; $arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."|";
@ -2880,7 +2870,8 @@ sub averval_DoParse {
@wsn = split(" ",$runtime_string_next); @wsn = split(" ",$runtime_string_next);
$wrstr .= $runtime_string."#".$line[0]."#".$wsf[0]."_".$wsf[1]."#".$wsn[0]."_".$wsn[1]."|"; # Kombi zum Rückschreiben in die DB $wrstr .= $runtime_string."#".$line[0]."#".$wsf[0]."_".$wsf[1]."#".$wsn[0]."_".$wsn[1]."|"; # Kombi zum Rückschreiben in die DB
} elsif ($acf eq "avgDailyMeanGWS") { }
elsif ($acf =~ /avgDailyMeanGWS/x) {
# Berechnung des Tagesmittelwertes (Temperatur) nach der Vorschrift des deutschen Wetterdienstes # Berechnung des Tagesmittelwertes (Temperatur) nach der Vorschrift des deutschen Wetterdienstes
# Berechnung der Tagesmittel aus 24 Stundenwerten, Bezugszeit für einen Tag i.d.R. 23:51 UTC des # Berechnung der Tagesmittel aus 24 Stundenwerten, Bezugszeit für einen Tag i.d.R. 23:51 UTC des
# Vortages bis 23:50 UTC, d.h. 00:51 bis 23:50 MEZ # Vortages bis 23:50 UTC, d.h. 00:51 bis 23:50 MEZ
@ -2892,6 +2883,7 @@ sub averval_DoParse {
my $anz = 0; # Anzahl der Messwerte am Tag my $anz = 0; # Anzahl der Messwerte am Tag
my($t01,$t07,$t13,$t19); # Temperaturen der Haupttermine my($t01,$t07,$t13,$t19); # Temperaturen der Haupttermine
my ($bdate,undef) = split(" ",$runtime_string_first); my ($bdate,undef) = split(" ",$runtime_string_first);
for my $i (0..23) { for my $i (0..23) {
my $bsel = $bdate." ".sprintf("%02d",$i).":00:00"; my $bsel = $bdate." ".sprintf("%02d",$i).":00:00";
my $esel = ($i<23) ? $bdate." ".sprintf("%02d",$i).":59:59" : $runtime_string_next; my $esel = ($i<23) ? $bdate." ".sprintf("%02d",$i).":59:59" : $runtime_string_next;
@ -2902,15 +2894,18 @@ sub averval_DoParse {
eval{ $sth = $dbh->prepare($sql); eval{ $sth = $dbh->prepare($sql);
$sth->execute(); $sth->execute();
}; };
if ($@) { if ($@) {
$err = encode_base64($@,""); $err = encode_base64($@,"");
Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 2, "DbRep $name - $@");
$dbh->disconnect; $dbh->disconnect;
return "$name|''|$device|$reading|''|$err|''"; return "$name|''|$device|$reading|''|$err|''";
} }
my $val = $sth->fetchrow_array(); my $val = $sth->fetchrow_array();
Log3 ($name, 5, "DbRep $name - SQL result: $val") if($val); Log3 ($name, 5, "DbRep $name - SQL result: $val") if($val);
$val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren
if(defined($val) && looks_like_number($val)) { if(defined($val) && looks_like_number($val)) {
$sum += $val; $sum += $val;
$t01 = $val if($val && $i == 00); # Wert f. Stunde 01 ist zw. letzter Wert vor 01 $t01 = $val if($val && $i == 00); # Wert f. Stunde 01 ist zw. letzter Wert vor 01
@ -2920,33 +2915,61 @@ sub averval_DoParse {
$anz++; $anz++;
} }
} }
if($anz >= 21) { if($anz >= 21) {
$sum = $sum/24; $sum = $sum/24;
} elsif ($anz >= 4 && $t01 && $t07 && $t13 && $t19) { }
elsif ($anz >= 4 && $t01 && $t07 && $t13 && $t19) {
$sum = ($t01+$t07+$t13+$t19)/4; $sum = ($t01+$t07+$t13+$t19)/4;
} else { }
else {
$sum = qq{<html>insufficient values - execute <b>get $name versionNotes 2</b> for further information</html>}; $sum = qq{<html>insufficient values - execute <b>get $name versionNotes 2</b> for further information</html>};
} }
my $aval = (DbRep_checktimeaggr($hash))[2]; my $aval = (DbRep_checktimeaggr($hash))[2];
if($aval eq "hour") { if($aval eq "hour") {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."|";
} elsif ($aval eq "minute") { }
elsif ($aval eq "minute") {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|";
} else { }
else {
@rsf = split(" ",$runtime_string_first); @rsf = split(" ",$runtime_string_first);
@rsn = split(" ",$runtime_string_next); @rsn = split(" ",$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."|";
} }
@wsf = split(" ",$runtime_string_first); @wsf = split(" ",$runtime_string_first);
@wsn = split(" ",$runtime_string_next); @wsn = split(" ",$runtime_string_next);
$wrstr .= $runtime_string."#".$sum."#".$wsf[0]."_".$wsf[1]."#".$wsn[0]."_".$wsn[1]."|"; # Kombi zum Rückschreiben in die DB $wrstr .= $runtime_string."#".$sum."#".$wsf[0]."_".$wsf[1]."#".$wsn[0]."_".$wsn[1]."|"; # Kombi zum Rückschreiben in die DB
} elsif ($acf eq "avgTimeWeightMean") { ### Grünlandtemperatursumme lt. https://de.wikipedia.org/wiki/Gr%C3%BCnlandtemperatursumme ###
my ($y,$m,$d) = split "-", $runtime_string;
if ($acf eq "avgDailyMeanGWSwithGTS" && looks_like_number($sum)) {
$m = DbRep_removeLeadingZero ($m);
$d = DbRep_removeLeadingZero ($d);
$gts = 0 if($m == 1 && $d == 1);
my $f = $sum <= 0 ? 0 :
$m >= 3 ? 1.00 : # Faktorenberechnung lt. https://de.wikipedia.org/wiki/Gr%C3%BCnlandtemperatursumme
$m == 2 ? 0.75 : 0.5;
$gts += $sum*$f;
if($gts >= 200) {
$gtsreached = $gtsreached // $runtime_string;
}
$gtsstr .= $runtime_string."#".$gts."#".$rsf[0]."|";
}
#############################################################################################
}
elsif ($acf eq "avgTimeWeightMean") {
# zeitgewichteten Mittelwert berechnen # zeitgewichteten Mittelwert berechnen
# http://massmatics.de/merkzettel/#!837:Gewichteter_Mittelwert # http://massmatics.de/merkzettel/#!837:Gewichteter_Mittelwert
# #
@ -2980,14 +3003,16 @@ sub averval_DoParse {
if(!$tf || !$tl) { if(!$tf || !$tl) {
# kein Start- und/oder Ende Timestamp in Zeitscheibe vorhanden -> keine Werteberechnung möglich # kein Start- und/oder Ende Timestamp in Zeitscheibe vorhanden -> keine Werteberechnung möglich
$sum = "insufficient values"; $sum = "insufficient values";
} else { }
else {
my ($yyyyf, $mmf, $ddf, $hhf, $minf, $secf) = ($tf =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyyf, $mmf, $ddf, $hhf, $minf, $secf) = ($tf =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/);
my ($yyyyl, $mml, $ddl, $hhl, $minl, $secl) = ($tl =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyyl, $mml, $ddl, $hhl, $minl, $secl) = ($tl =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/);
$tsum = (timelocal($secl, $minl, $hhl, $ddl, $mml-1, $yyyyl-1900))-(timelocal($secf, $minf, $hhf, $ddf, $mmf-1, $yyyyf-1900)); $tsum = (timelocal($secl, $minl, $hhl, $ddl, $mml-1, $yyyyl-1900))-(timelocal($secf, $minf, $hhf, $ddf, $mmf-1, $yyyyf-1900));
if ($IsTimeSet || $IsAggrSet) { if ($IsTimeSet || $IsAggrSet) {
$sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon);
} else { }
else {
$sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon);
} }
Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); Log3 ($name, 4, "DbRep $name - SQL execute: $sql");
@ -3004,16 +3029,18 @@ sub averval_DoParse {
my @twm_array = map { $_->[0]."_ESC_".$_->[1] } @{$sth->fetchall_arrayref()}; my @twm_array = map { $_->[0]."_ESC_".$_->[1] } @{$sth->fetchall_arrayref()};
foreach my $twmrow (@twm_array) { for my $twmrow (@twm_array) {
($tn,$val) = split("_ESC_",$twmrow); ($tn,$val) = split("_ESC_",$twmrow);
$val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren
my ($yyyyt1, $mmt1, $ddt1, $hht1, $mint1, $sect1) = ($tn =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); my ($yyyyt1, $mmt1, $ddt1, $hht1, $mint1, $sect1) = ($tn =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/);
$tn = timelocal($sect1, $mint1, $hht1, $ddt1, $mmt1-1, $yyyyt1-1900); $tn = timelocal($sect1, $mint1, $hht1, $ddt1, $mmt1-1, $yyyyt1-1900);
if(!$to) { if(!$to) {
$val1 = $val; $val1 = $val;
$to = $tn; $to = $tn;
next; next;
} }
$dt = $tn - $to; $dt = $tn - $to;
$sum += $val1*($dt/$tsum); $sum += $val1*($dt/$tsum);
$val1 = $val; $val1 = $val;
@ -3028,11 +3055,13 @@ sub averval_DoParse {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."|";
} elsif ($aval eq "minute") { }
elsif ($aval eq "minute") {
@rsf = split(/[ :]/,$runtime_string_first); @rsf = split(/[ :]/,$runtime_string_first);
@rsn = split(/[ :]/,$runtime_string_next); @rsn = split(/[ :]/,$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."_".$rsf[1]."-".$rsf[2]."|";
} else { }
else {
@rsf = split(" ",$runtime_string_first); @rsf = split(" ",$runtime_string_first);
@rsn = split(" ",$runtime_string_next); @rsn = split(" ",$runtime_string_next);
$arrstr .= $runtime_string."#".$sum."#".$rsf[0]."|"; $arrstr .= $runtime_string."#".$sum."#".$rsf[0]."|";
@ -3046,12 +3075,10 @@ sub averval_DoParse {
$sth->finish; $sth->finish;
$dbh->disconnect; $dbh->disconnect;
# SQL-Laufzeit ermitteln my $rt = tv_interval($st); # SQL-Laufzeit ermitteln
my $rt = tv_interval($st);
# Ergebnisse in Datenbank schreiben
my ($wrt,$irowdone); my ($wrt,$irowdone);
if($prop =~ /writeToDB/) { if($prop =~ /writeToDB/) { # Ergebnisse in Datenbank schreiben
($wrt,$irowdone,$err) = DbRep_OutputWriteToDB($name,$device,$reading,$wrstr,$qlf); ($wrt,$irowdone,$err) = DbRep_OutputWriteToDB($name,$device,$reading,$wrstr,$qlf);
if ($err) { if ($err) {
Log3 $hash->{NAME}, 2, "DbRep $name - $err"; Log3 $hash->{NAME}, 2, "DbRep $name - $err";
@ -3064,20 +3091,21 @@ sub averval_DoParse {
# Daten müssen als Einzeiler zurückgegeben werden # Daten müssen als Einzeiler zurückgegeben werden
$arrstr = encode_base64($arrstr,""); $arrstr = encode_base64($arrstr,"");
$device = encode_base64($device,""); $device = encode_base64($device,"");
$gtsstr = encode_base64($gtsstr,"");
# Background-Laufzeit ermitteln # Background-Laufzeit ermitteln
my $brt = tv_interval($bst); my $brt = tv_interval($bst);
$rt = $rt.",".$brt; $rt = $rt.",".$brt;
return "$name|$arrstr|$device|$reading|$rt|0|$irowdone"; return "$name|$arrstr|$device|$reading|$rt|0|$irowdone|$gtsstr|$gtsreached";
} }
#################################################################################################### ####################################################################################################
# Auswertungsroutine der nichtblockierenden DB-Abfrage averageValue # Auswertungsroutine der nichtblockierenden DB-Abfrage averageValue
#################################################################################################### ####################################################################################################
sub averval_ParseDone { sub averval_ParseDone {
my ($string) = @_; my $string = shift;
my @a = split("\\|",$string); my @a = split("\\|",$string);
my $hash = $defs{$a[0]}; my $hash = $defs{$a[0]};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
@ -3090,6 +3118,8 @@ sub averval_ParseDone {
my ($rt,$brt) = split(",", $bt); my ($rt,$brt) = split(",", $bt);
my $err = $a[5] ? decode_base64($a[5]) : undef; my $err = $a[5] ? decode_base64($a[5]) : undef;
my $irowdone = $a[6]; my $irowdone = $a[6];
my $gtsstr = $a[7] ? decode_base64($a[7]) : undef;
my $gtsreached = $a[8];
my $reading_runtime_string; my $reading_runtime_string;
my $erread; my $erread;
@ -3108,20 +3138,40 @@ sub averval_ParseDone {
no warnings 'uninitialized'; no warnings 'uninitialized';
my $acf = AttrVal($name, "averageCalcForm", "avgArithmeticMean"); my $acf = AttrVal($name, "averageCalcForm", "avgArithmeticMean");
if($acf eq "avgArithmeticMean") { if($acf eq "avgArithmeticMean") {
$acf = "AM" $acf = "AM"
} elsif ($acf eq "avgDailyMeanGWS") { }
elsif ($acf =~ /avgDailyMeanGWS/) {
$acf = "DMGWS"; $acf = "DMGWS";
} elsif ($acf eq "avgTimeWeightMean") { }
elsif ($acf eq "avgTimeWeightMean") {
$acf = "TWM"; $acf = "TWM";
} }
# Readingaufbereitung # Readingaufbereitung
my $state = $erread ? $erread : "done"; my $state = $erread ? $erread : "done";
readingsBeginUpdate($hash);
readingsBeginUpdate($hash); # Readings für Grünlandtemperatursumme
my @agts = split("\\|", $gtsstr);
for my $gts (@agts) {
my @ay = split("#", $gts);
my $rt_string = $ay[0];
my $val = $ay[1];
my $rtf = $ay[2]."__";
my $dev = $device."__" if ($device);
my $rdg = $reading."__" if ($reading);
my $reading_rt_string = $rtf.$dev.$rdg."GrasslandTemperatureSum";
ReadingsBulkUpdateValue ($hash, $reading_rt_string, sprintf("%.1f",$val));
}
ReadingsBulkUpdateValue ($hash, "reachedGTSthreshold", $gtsreached) if($gtsreached);
readingsEndUpdate ($hash, 1);
readingsBeginUpdate($hash);
my @arr = split("\\|", $arrstr); my @arr = split("\\|", $arrstr);
foreach my $row (@arr) { for my $row (@arr) {
my @a = split("#", $row); my @a = split("#", $row);
my $runtime_string = $a[0]; my $runtime_string = $a[0];
my $c = $a[1]; my $c = $a[1];
@ -3129,14 +3179,16 @@ sub averval_ParseDone {
if (AttrVal($hash->{NAME}, "readingNameMap", "")) { if (AttrVal($hash->{NAME}, "readingNameMap", "")) {
$reading_runtime_string = $rsf.AttrVal($hash->{NAME}, "readingNameMap", "")."__".$runtime_string; $reading_runtime_string = $rsf.AttrVal($hash->{NAME}, "readingNameMap", "")."__".$runtime_string;
} else { }
else {
my $ds = $device."__" if ($device); my $ds = $device."__" if ($device);
my $rds = $reading."__" if ($reading); my $rds = $reading."__" if ($reading);
$reading_runtime_string = $rsf.$ds.$rds."AVG".$acf."__".$runtime_string; $reading_runtime_string = $rsf.$ds.$rds."AVG".$acf."__".$runtime_string;
} }
if($acf eq "DMGWS") { if($acf eq "DMGWS") {
ReadingsBulkUpdateValue ($hash, $reading_runtime_string, looks_like_number($c) ? sprintf("%.1f",$c) :$c); ReadingsBulkUpdateValue ($hash, $reading_runtime_string, looks_like_number($c) ? sprintf("%.1f",$c) :$c);
} else { }
else {
ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c ? sprintf("%.4f",$c) : "-"); ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c ? sprintf("%.4f",$c) : "-");
} }
} }
@ -9845,7 +9897,7 @@ sub DbRep_checktimeaggr {
$aggregation = ($aggregation eq "no") ? "day" : $aggregation; # wenn Aggregation "no", für delSeqDoublets immer "day" setzen $aggregation = ($aggregation eq "no") ? "day" : $aggregation; # wenn Aggregation "no", für delSeqDoublets immer "day" setzen
$IsAggrSet = 1; $IsAggrSet = 1;
} }
if($hash->{LASTCMD} =~ /averageValue/ && AttrVal($name,"averageCalcForm","avgArithmeticMean") eq "avgDailyMeanGWS") { if($hash->{LASTCMD} =~ /averageValue/ && AttrVal($name, "averageCalcForm", "avgArithmeticMean") =~ /avgDailyMeanGWS/x) {
$aggregation = "day"; # für Tagesmittelwertberechnung des deutschen Wetterdienstes immer "day" $aggregation = "day"; # für Tagesmittelwertberechnung des deutschen Wetterdienstes immer "day"
$IsAggrSet = 1; $IsAggrSet = 1;
} }
@ -9860,7 +9912,8 @@ sub DbRep_checktimeaggr {
if($hash->{HELPER}{COMPLEX}) { if($hash->{HELPER}{COMPLEX}) {
$IsAggrSet = 1; $IsAggrSet = 1;
$aggregation = "day"; $aggregation = "day";
} else { }
else {
$IsAggrSet = 0; $IsAggrSet = 0;
$aggregation = "no"; $aggregation = "no";
} }
@ -10063,8 +10116,8 @@ sub DbRep_normRelTime {
# evtl. Relativzeiten bei "reduceLog" oder "deleteEntries" berücksichtigen # evtl. Relativzeiten bei "reduceLog" oder "deleteEntries" berücksichtigen
@a = @{$hash->{HELPER}{REDUCELOG}} if($hash->{HELPER}{REDUCELOG}); @a = @{$hash->{HELPER}{REDUCELOG}} if($hash->{HELPER}{REDUCELOG});
@a = @{$hash->{HELPER}{DELENTRIES}} if($hash->{HELPER}{DELENTRIES}); @a = @{$hash->{HELPER}{DELENTRIES}} if($hash->{HELPER}{DELENTRIES});
foreach (@a) { for my $ey (@a) {
if($_ =~ /\b(\d+(:\d+)?)\b/) { if($ey =~ /\b(\d+(:\d+)?)\b/) {
my ($od,$nd) = split(":",$1); # $od - Tage älter als , $nd - Tage neuer als my ($od,$nd) = split(":",$1); # $od - Tage älter als , $nd - Tage neuer als
$toth = "d:$od" if($od); $toth = "d:$od" if($od);
$tdtn = "d:$nd" if($nd); $tdtn = "d:$nd" if($nd);
@ -10276,16 +10329,20 @@ return;
# Befehl nach Procedure ausführen # Befehl nach Procedure ausführen
################################################################################### ###################################################################################
sub DbRep_afterproc { sub DbRep_afterproc {
my ($hash, $txt) = @_; my $hash = shift;
my $txt = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $erread; my $erread;
# Befehl nach Procedure ausführen # Befehl nach Procedure ausführen
no warnings 'uninitialized'; no warnings 'uninitialized';
my $ead = AttrVal($name, "executeAfterProc", undef); my $ead = AttrVal($name, "executeAfterProc", undef);
if($ead) { if($ead) {
Log3 ($name, 4, "DbRep $name - execute command after $txt: '$ead' "); Log3 ($name, 4, "DbRep $name - execute command after $txt: '$ead' ");
my $err = AnalyzeCommandChain(undef, $ead); my $err = AnalyzeCommandChain(undef, $ead);
if ($err) { if ($err) {
Log3 ($name, 2, "DbRep $name - command message after $txt: \"$err\" "); Log3 ($name, 2, "DbRep $name - command message after $txt: \"$err\" ");
ReadingsSingleUpdateValue ($hash, "after".$txt."_message", $err, 1); ReadingsSingleUpdateValue ($hash, "after".$txt."_message", $err, 1);
@ -11485,13 +11542,28 @@ return ($upkh,$upkc,$pkh,$pkc);
# extrahiert aus dem übergebenen Wert nur die Zahl # extrahiert aus dem übergebenen Wert nur die Zahl
################################################################ ################################################################
sub DbRep_numval { sub DbRep_numval {
my ($val) = @_; my $val = shift;
return undef if(!defined($val)); return undef if(!defined($val));
$val = ($val =~ /(-?\d+(\.\d+)?)/ ? $1 : ""); $val = ($val =~ /(-?\d+(\.\d+)?)/ ? $1 : "");
return $val; return $val;
} }
################################################################
# entfernt führende Mullen einer Zahl
################################################################
sub DbRep_removeLeadingZero {
my $val = shift;
return if(!defined($val));
$val =~ s/^0//;
return $val;
}
#################################################################################################### ####################################################################################################
# löscht einen Wert vom $hash des Hauptprozesses aus einem BlockingCall heraus # löscht einen Wert vom $hash des Hauptprozesses aus einem BlockingCall heraus
#################################################################################################### ####################################################################################################
@ -13715,9 +13787,14 @@ sub dbval {
<colgroup> <col width=20%> <col width=80%> </colgroup> <colgroup> <col width=20%> <col width=80%> </colgroup>
<tr><td><b>avgArithmeticMean:</b> </td><td>the arithmetic average is calculated (default) </td></tr> <tr><td><b>avgArithmeticMean:</b> </td><td>the arithmetic average is calculated (default) </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td><b>avgDailyMeanGWS :</b> </td><td>calculates the daily medium temperature according the <tr><td><b>avgDailyMeanGWS:</b> </td><td>calculates the daily medium temperature according the </td></tr>
specifications of german weather service (pls. see "get &lt;name&gt; versionNotes 2"). <br> <tr><td> </td><td>specifications of german weather service (see also "get &lt;name&gt; versionNotes 2") </td></tr>
This variant uses aggregation "day" automatically. </td></tr> <tr><td> </td><td>This variant uses aggregation "day" automatically. </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>avgDailyMeanGWSwithGTS:</b> </td><td>like "avgDailyMeanGWS" and additionally the grassland temperature sum </td></tr>
<tr><td> </td><td>If the value 200 is reached, the reading "reachedGTSthreshold" is created with the </td></tr>
<tr><td> </td><td>date of the first time this threshold value is reached. </td></tr> <tr><td> </td><td><b>Note:</b> the attribute timestamp_begin must be set to the beginning of a year ! </td></tr>
<tr><td> </td><td>(see also "get &lt;name&gt; versionNotes 5") </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td><b>avgTimeWeightMean:</b> </td><td>calculates a time weighted average mean value is calculated </td></tr> <tr><td><b>avgTimeWeightMean:</b> </td><td>calculates a time weighted average mean value is calculated </td></tr>
</table> </table>
@ -14923,6 +15000,7 @@ sub bdump {
<br> <br>
<br> <br>
<a name="delEntries"></a>
<li><b> delEntries [&lt;no&gt;[:&lt;nn&gt;]] </b> - löscht alle oder die durch die <a href="#DbRepattr">Attribute</a> device und/oder <li><b> delEntries [&lt;no&gt;[:&lt;nn&gt;]] </b> - löscht alle oder die durch die <a href="#DbRepattr">Attribute</a> device und/oder
reading definierten Datenbankeinträge. Die Eingrenzung über Timestamps erfolgt reading definierten Datenbankeinträge. Die Eingrenzung über Timestamps erfolgt
folgendermaßen: <br><br> folgendermaßen: <br><br>
@ -16362,9 +16440,15 @@ sub dbval {
<colgroup> <col width=20%> <col width=80%> </colgroup> <colgroup> <col width=20%> <col width=80%> </colgroup>
<tr><td> <b>avgArithmeticMean: </b></td><td>es wird der arithmetische Mittelwert berechnet (default) </td></tr> <tr><td> <b>avgArithmeticMean: </b></td><td>es wird der arithmetische Mittelwert berechnet (default) </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>avgDailyMeanGWS :</b> </td><td>berechnet die Tagesmitteltemperatur entsprechend den <tr><td> <b>avgDailyMeanGWS:</b> </td><td>berechnet die Tagesmitteltemperatur entsprechend den </td></tr>
Vorschriften des deutschen Wetterdienstes (siehe "get &lt;name&gt; versionNotes 2"). <br> <tr><td> </td><td>Vorschriften des deutschen Wetterdienstes (siehe "get &lt;name&gt; versionNotes 2") </td></tr>
Diese Variante verwendet automatisch die Aggregation "day". </td></tr> <tr><td> </td><td>Diese Variante verwendet automatisch die Aggregation "day". </td></tr>
<tr><td> </td><td> </td></tr>
<tr><td> <b>avgDailyMeanGWSwithGTS:</b> </td><td>wie "avgDailyMeanGWS" und berechnet zusätzlich die Grünlandtemperatursumme. </td></tr>
<tr><td> </td><td>Ist der Wert 200 erreicht, wird das Reading "reachedGTSthreshold" mit dem Datum </td></tr>
<tr><td> </td><td>des erstmaligen Erreichens dieses Schwellenwertes erstellt. </td></tr>
<tr><td> </td><td><b>Hinweis:</b> das Attribut timestamp_begin muß auf den Anfang eines Jahres gesetzt sein ! </td></tr>
<tr><td> </td><td>(siehe "get &lt;name&gt; versionNotes 5") </td></tr>
<tr><td> </td><td> </td></tr> <tr><td> </td><td> </td></tr>
<tr><td> <b>avgTimeWeightMean:</b> </td><td>berechnet den zeitgewichteten Mittelwert </td></tr> <tr><td> <b>avgTimeWeightMean:</b> </td><td>berechnet den zeitgewichteten Mittelwert </td></tr>
</table> </table>