2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 18:59:33 +00:00

93_DbRep: contrib 8.38.0

git-svn-id: https://svn.fhem.de/fhem/trunk@21466 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2020-03-21 15:38:22 +00:00
parent cbeb1a7d32
commit 1398dc8eb0

View File

@ -58,6 +58,8 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Version History intern
our %DbRep_vNotesIntern = (
"8.38.0" => "21.03.2020 sqlSpecial diffBetweenValuesOfReading, fix FHEM crash if no time-attribute is set and time option of delEntries / reduceLog is used ",
"8.37.0" => "20.03.2020 add column header for free selects (sqlCmd) ",
"8.36.0" => "19.03.2020 sqlSpecial recentReadingsOfDevice ",
"8.35.0" => "19.03.2020 option older than days and newer than days for delEntries function ",
"8.34.0" => "18.03.2020 option writeToDBSingle for functions averageValue, sumValue ",
@ -191,6 +193,8 @@ our %DbRep_vNotesIntern = (
# Version History extern:
our %DbRep_vNotesExtern = (
"8.36.0" => "19.03.2020 Some simplifications for fast mutable module usage is built in, such as possible command option older than / newer than days for reduceLog and delEntries function. ".
"A new option \"writeToDBSingle\" for functions averageValue, sumValue is built in as well as a new sqlSpecial \"recentReadingsOfDevice\". ",
"8.32.0" => "29.01.2020 A new option \"deleteOther\" is available for commands \"maxValue\" and \"minValue\". Now it is possible to delete all values except the ".
"extreme values (max/min) from the database within the specified limits of time, device, reading and so on. ",
"8.30.4" => "22.01.2020 The behavior of write back values to database is changed for functions averageValue and sumValue. The solution values of that functions now are ".
@ -570,7 +574,7 @@ sub DbRep_Set($@) {
(($hash->{ROLE} ne "Agent")?"reduceLog ":"").
(($hash->{ROLE} ne "Agent")?"sqlCmd:textField-long ":"").
(($hash->{ROLE} ne "Agent" && $hl)?"sqlCmdHistory:".$hl." ":"").
(($hash->{ROLE} ne "Agent")?"sqlSpecial:50mostFreqLogsLast2days,allDevCount,allDevReadCount,recentReadingsOfDevice ":"").
(($hash->{ROLE} ne "Agent")?"sqlSpecial:50mostFreqLogsLast2days,allDevCount,allDevReadCount,recentReadingsOfDevice".(($dbmodel eq "MYSQL")?",diffBetweenValuesOfReading":"")." ":"").
(($hash->{ROLE} ne "Agent")?"syncStandby ":"").
(($hash->{ROLE} ne "Agent")?"tableCurrentFillup:noArg ":"").
(($hash->{ROLE} ne "Agent")?"tableCurrentPurge:noArg ":"").
@ -1954,15 +1958,16 @@ sub DbRep_Main($$;$) {
# zentrales Timestamp-Array und Zeitgrenzen bereitstellen
my ($epoch_seconds_begin,$epoch_seconds_end,$runtime_string_first,$runtime_string_next);
my $ts = "no_aggregation"; # Dummy für eine Select-Schleife wenn != $IsTimeSet || $IsAggrSet
my ($IsTimeSet,$IsAggrSet,$aggregation) = DbRep_checktimeaggr($hash);
my ($IsTimeSet,$IsAggrSet,$aggregation) = DbRep_checktimeaggr($hash);
if($IsTimeSet || $IsAggrSet) {
($epoch_seconds_begin,$epoch_seconds_end,$runtime_string_first,$runtime_string_next,$ts) = DbRep_createTimeArray($hash,$aggregation,$opt);
} else {
Log3 ($name, 4, "DbRep $name - Timestamp begin human readable: not set") if($opt !~ /tableCurrentPurge/);
Log3 ($name, 4, "DbRep $name - Timestamp end human readable: not set") if($opt !~ /tableCurrentPurge/);
}
Log3 ($name, 4, "DbRep $name - Aggregation: $aggregation") if($opt !~ /tableCurrentPurge|tableCurrentFillup|fetchrows|insert|reduceLog/);
Log3 ($name, 4, "DbRep $name - Aggregation: $aggregation") if($opt !~ /tableCurrentPurge|tableCurrentFillup|fetchrows|insert|reduceLog|delEntries/);
##### Funktionsaufrufe #####
if ($opt eq "sumValue") {
@ -2046,16 +2051,20 @@ sub DbRep_Main($$;$) {
} elsif ($opt =~ /sqlCmd|sqlSpecial/ ) {
# Execute a generic sql command or special sql
if ($opt =~ /sqlSpecial/) {
my ($tq,$gcl);
if($prop eq "50mostFreqLogsLast2days") {
$prop = "select Device, reading, count(0) AS `countA` from history where ( TIMESTAMP > (now() - interval 2 day)) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /MYSQL/);
$prop = "select Device, reading, count(0) AS `countA` from history where ( TIMESTAMP > ('now' - '2 days')) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /SQLITE/);
$prop = "select Device, reading, count(0) AS countA from history where ( TIMESTAMP > (NOW() - INTERVAL '2' DAY)) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /POSTGRESQL/);
} elsif ($prop eq "allDevReadCount") {
$prop = "select device, reading, count(*) from history group by DEVICE, READING;";
} elsif ($prop eq "allDevCount") {
$prop = "select device, count(*) from history group by DEVICE;";
} elsif ($prop eq "recentReadingsOfDevice") {
my ($tq,$gcl);
if($dbmodel =~ /MYSQL/) {$tq = "NOW() - INTERVAL 1 DAY"; $gcl = "READING"};
if($dbmodel =~ /SQLITE/) {$tq = "datetime('now','-1 day')"; $gcl = "READING"};
if($dbmodel =~ /POSTGRESQL/) {$tq = "CURRENT_TIMESTAMP - INTERVAL '1 day'"; $gcl = "READING,DEVICE"};
@ -2070,6 +2079,26 @@ sub DbRep_Main($$;$) {
x.READING = t1.READING;");
$prop = join(" ", @cmd);
} elsif ($prop eq "diffBetweenValuesOfReading") {
my @cmd = split(/\s/, "SET \@diff=0;
SET \@delta=NULL;
SELECT t1.TIMESTAMP,t1.READING,t1.VALUE,t1.DIFF,t1.TIME_DELTA
FROM (SELECT TIMESTAMP,READING,VALUE,
cast((VALUE-\@diff) AS DECIMAL(12,4)) AS DIFF,
\@diff:=VALUE AS curr_V,
TIMESTAMPDIFF(MINUTE,\@delta,TIMESTAMP) AS TIME_DELTA,
\@delta:=TIMESTAMP AS curr_T
FROM history
WHERE DEVICE = '".$device."' AND
READING = '".$reading."' AND
TIMESTAMP >= §timestamp_begin§ AND
TIMESTAMP <= §timestamp_end§
ORDER BY TIMESTAMP
) t1;"
);
$prop = join(" ", @cmd);
}
}
$hash->{HELPER}{RUNNING_PID} = BlockingCall("sqlCmd_DoParse", "$name|$opt|$runtime_string_first|$runtime_string_next|$prop", "sqlCmd_ParseDone", $to, "DbRep_ParseAborted", $hash);
@ -6179,33 +6208,39 @@ sub sqlCmd_DoParse($) {
return "$name|''|$opt|$sql|''|''|$err";
}
my @rows;
my (@rows,$row,@head);
my $nrows = 0;
if($sql =~ m/^\s*(explain|select|pragma|show)/is) {
while (my @line = $sth->fetchrow_array()) {
Log3 ($name, 4, "DbRep $name - SQL result: @line");
my $row = join("$srs", @line);
@head = map { uc($sth->{NAME}[$_]) } keys @{$sth->{NAME}}; # https://metacpan.org/pod/DBI#NAME1
if (@head) {
$row = join("$srs", @head);
push(@rows, $row);
}
# join Delimiter "§" escapen
$row =~ s/§/|°escaped°|/g;
while (my @line = $sth->fetchrow_array()) {
Log3 ($name, 4, "DbRep $name - SQL result: @line");
$row = join("$srs", @line);
push(@rows, $row);
# Anzahl der Datensätze
$nrows++;
}
# join Delimiter "§" escapen
$row =~ s/§/|°escaped°|/g;
push(@rows, $row);
# Anzahl der Datensätze
$nrows++;
}
} else {
$nrows = $sth->rows;
eval {$dbh->commit() if(!$dbh->{AutoCommit});};
if ($@) {
$err = encode_base64($@,"");
Log3 ($name, 2, "DbRep $name - ERROR - $@");
$dbh->disconnect;
return "$name|''|$opt|$sql|''|''|$err";
}
$nrows = $sth->rows;
eval {$dbh->commit() if(!$dbh->{AutoCommit});};
if ($@) {
$err = encode_base64($@,"");
Log3 ($name, 2, "DbRep $name - ERROR - $@");
$dbh->disconnect;
return "$name|''|$opt|$sql|''|''|$err";
}
push(@rows, $r);
my $com = (split(" ",$sql, 2))[0];
Log3 ($name, 3, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com");
push(@rows, $r);
my $com = (split(" ",$sql, 2))[0];
Log3 ($name, 3, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com");
}
$sth->finish;
@ -6294,8 +6329,8 @@ sub sqlCmd_ParseDone($) {
foreach $row ( @rows ) {
$row =~ s/\|°escaped°\|/§/g;
$row =~ s/$srs/\|/g if($srs !~ /\|/);
$row =~ s/\|/<\/td><td style='padding-right:5px;padding-left:5px'>/g;
$res .= "<tr><td style='padding-right:5px;padding-left:5px'>".$row."</td></tr>";
$row =~ s/\|/<\/td><td style='padding-right:5px;padding-left:5px;text-align: right;'>/g;
$res .= "<tr><td style='padding-right:5px;padding-left:5px;text-align: right;'>".$row."</td></tr>";
}
$row .= $res."</table></html>";
@ -6461,6 +6496,7 @@ sub dbmeta_DoParse($) {
}
}
} elsif ($opt eq "procinfo") {
my $row;
my $res = "<html><table border=2 bordercolor='darkgreen' cellspacing=0>";
$res .= "<tr><td style='padding-right:5px;padding-left:5px;font-weight:bold'>ID</td>";
$res .= "<td style='padding-right:5px;padding-left:5px;font-weight:bold'>USER</td>";
@ -6471,11 +6507,12 @@ sub dbmeta_DoParse($) {
$res .= "<td style='padding-right:5px;padding-left:5px;font-weight:bold'>STATE</td>";
$res .= "<td style='padding-right:5px;padding-left:5px;font-weight:bold'>INFO</td>";
$res .= "<td style='padding-right:5px;padding-left:5px;font-weight:bold'>PROGRESS</td></tr>";
while (my @line = $sth->fetchrow_array()) {
while (my @line = $sth->fetchrow_array()) {
Log3 ($name, 4, "DbRep $name - SQL result: @line");
my $row = join("|", @line);
$row =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd;
$row =~ s/\|/<\/td><td style='padding-right:5px;padding-left:5px'>/g;
$row = join("|", @line);
$row =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd;
$row =~ s/\|/<\/td><td style='padding-right:5px;padding-left:5px'>/g;
$res .= "<tr><td style='padding-right:5px;padding-left:5px'>".$row."</td></tr>";
}
my $tab .= $res."</table></html>";
@ -9670,9 +9707,22 @@ sub DbRep_checktimeaggr ($) {
my $IsAggrSet = 0;
my $aggregation = AttrVal($name,"aggregation","no");
if ( AttrVal($name,"timestamp_begin",undef) || AttrVal($name,"timestamp_end",undef) ||
AttrVal($name,"timeDiffToNow",undef) || AttrVal($name,"timeOlderThan",undef) || AttrVal($name,"timeYearPeriod",undef) ) {
$IsTimeSet = 1;
my @a;
@a = @{$hash->{HELPER}{REDUCELOG}} if($hash->{HELPER}{REDUCELOG});
@a = @{$hash->{HELPER}{DELENTRIES}} if($hash->{HELPER}{DELENTRIES});
my $timeoption = 0;
foreach (@a) { # evtl. Relativzeiten bei "reduceLog" oder "deleteEntries" berücksichtigen
if($_ =~ /\b(\d+(:\d+)?)\b/) {
$timeoption = 1;
}
}
if ( AttrVal($name,"timestamp_begin", undef) ||
AttrVal($name,"timestamp_end", undef) ||
AttrVal($name,"timeDiffToNow", undef) ||
AttrVal($name,"timeOlderThan", undef) ||
AttrVal($name,"timeYearPeriod", undef) || $timeoption ) {
$IsTimeSet = 1;
}
if ($aggregation ne "no") {
@ -9686,7 +9736,7 @@ sub DbRep_checktimeaggr ($) {
$aggregation = "day"; # für Tagesmittelwertberechnung des deutschen Wetterdienstes immer "day"
$IsAggrSet = 1;
}
if($hash->{LASTCMD} =~ /delEntries|fetchrows|deviceRename|readingRename|tableCurrentFillup|reduceLog/) {
if($hash->{LASTCMD} =~ /delEntries|fetchrows|deviceRename|readingRename|tableCurrentFillup|reduceLog|\bdiffBetweenValuesOfReading\b/) {
$IsAggrSet = 0;
$aggregation = "no";
}
@ -13010,12 +13060,16 @@ return;
<ul>
<table>
<colgroup> <col width=5%> <col width=95%> </colgroup>
<tr><td> <b>50mostFreqLogsLast2days </b> </td><td>: reports the 50 most occuring log entries of the last 2 days </td></tr>
<tr><td> <b>allDevCount </b> </td><td>: all devices occuring in database and their quantity </td></tr>
<tr><td> <b>allDevReadCount </b> </td><td>: all device/reading combinations occuring in database and their quantity </td></tr>
<tr><td> <b>recentReadingsOfDevice </b> </td><td>: determines the newest records of a device available in the database. The
device must be defined in attribute <a href="#reading">reading</a>.
Only <b>one</b> device to be evaluated can be specified.. </td></tr>
<tr><td> <b>50mostFreqLogsLast2days </b> </td><td>: reports the 50 most occuring log entries of the last 2 days </td></tr>
<tr><td> <b>allDevCount </b> </td><td>: all devices occuring in database and their quantity </td></tr>
<tr><td> <b>allDevReadCount </b> </td><td>: all device/reading combinations occuring in database and their quantity </td></tr>
<tr><td> <b>recentReadingsOfDevice </b> </td><td>: determines the newest records of a device available in the database. The
device must be defined in attribute <a href="#device">device</a>.
Only <b>one</b> device to be evaluated can be specified.. </td></tr>
<tr><td> <b>diffBetweenValuesOfReading </b> </td><td>: determines the value difference of successive data records of a reading. The
device and reading must be defined in the attribute <a href="#device">device</a> or <a href="#reading">reading</a>.
Only <b>one</b> device to be evaluated and only <b>one</b> reading to be evaluated can be specified.
The time limits of the evaluation are defined by the time.*-attributes. </td></tr>
</table>
</ul>
<br>
@ -15556,12 +15610,16 @@ sub bdump {
<ul>
<table>
<colgroup> <col width=5%> <col width=95%> </colgroup>
<tr><td> <b>50mostFreqLogsLast2days </b> </td><td>: ermittelt die 50 am häufigsten vorkommenden Loggingeinträge der letzten 2 Tage </td></tr>
<tr><td> <b>allDevCount </b> </td><td>: alle in der Datenbank vorkommenden Devices und deren Anzahl </td></tr>
<tr><td> <b>allDevReadCount </b> </td><td>: alle in der Datenbank vorkommenden Device/Reading-Kombinationen und deren Anzahl</td></tr>
<tr><td> <b>recentReadingsOfDevice </b> </td><td>: ermittelt die neuesten in der Datenbank vorhandenen Datensätze eines Devices. Das auszuwertende
Device muß im Attribut <a href="#reading">reading</a> definiert sein.
Es kann nur <b>ein</b> auszuwertendes Device angegeben werden. </td></tr>
<tr><td> <b>50mostFreqLogsLast2days </b> </td><td>: ermittelt die 50 am häufigsten vorkommenden Loggingeinträge der letzten 2 Tage </td></tr>
<tr><td> <b>allDevCount </b> </td><td>: alle in der Datenbank vorkommenden Devices und deren Anzahl </td></tr>
<tr><td> <b>allDevReadCount </b> </td><td>: alle in der Datenbank vorkommenden Device/Reading-Kombinationen und deren Anzahl</td></tr>
<tr><td> <b>recentReadingsOfDevice </b> </td><td>: ermittelt die neuesten in der Datenbank vorhandenen Datensätze eines Devices. Das auszuwertende
Device muß im Attribut <a href="#device">device</a> definiert sein.
Es kann nur <b>ein</b> auszuwertendes Device angegeben werden. </td></tr>
<tr><td> <b>diffBetweenValuesOfReading </b> </td><td>: ermittelt die Wertedifferenz aufeinanderfolgender Datensätze eines Readings. Das auszuwertende
Device und Reading muß im Attribut <a href="#device">device</a> bzw. <a href="#reading">reading</a> definiert sein.
Es kann nur <b>ein</b> auszuwertendes Device und nur <b>ein</b> auszuwertendes Reading angegeben werden.
Die Zeitgrenzen der Auswertung werden durch die time.*-Attribute festgelegt. </td></tr>
</table>
</ul>
<br>