mit $name,$reading,$value
####################################################################################################
sub userexit ($$$) {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
return if(!$hash->{HELPER}{USEREXITFN});
if(!defined($reading)) {$reading = "";}
if(!defined($value)) {$value = "";}
$value =~ s/\\/\\\\/g; # escapen of chars for evaluation
$value =~ s/'/\\'/g;
my $re = $hash->{HELPER}{UEFN_REGEXP}?$hash->{HELPER}{UEFN_REGEXP}:".*:.*";
if("$reading:$value" =~ m/^$re$/ ) {
my @res;
my $cmd = $hash->{HELPER}{USEREXITFN}."('$name','$reading','$value')";
$cmd = "{".$cmd."}";
my $r = AnalyzeCommandChain(undef, $cmd);
}
return;
}
####################################################################################################
# delete Readings before new operation
####################################################################################################
sub DbRep_delread($) {
# Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen
my ($hash) = @_;
my $name = $hash->{NAME};
my @allrds = keys%{$defs{$name}{READINGS}};
my @rdpfdel = split(",", $hash->{HELPER}{RDPFDEL}) if($hash->{HELPER}{RDPFDEL});
if (@rdpfdel) {
foreach my $key(@allrds) {
# Log3 ($name, 1, "DbRep $name - Reading Schlüssel: $key");
my $dodel = 1;
foreach my $rdpfdel(@rdpfdel) {
if($key =~ /$rdpfdel/ || $key eq "state") {
$dodel = 0;
}
}
if($dodel) {
delete($defs{$name}{READINGS}{$key});
}
}
} else {
foreach my $key(@allrds) {
# Log3 ($name, 1, "DbRep $name - Reading Schlüssel: $key");
delete($defs{$name}{READINGS}{$key}) if($key ne "state");
}
}
return undef;
}
####################################################################################################
# erstellen neues SQL-File für Dumproutine
####################################################################################################
sub NewDumpFilename ($$$$$){
my ($sql_text,$dump_path,$dbname,$time_stamp,$character_set) = @_;
my $part = "";
my $sql_file = $dump_path.$dbname."_".$time_stamp.$part.".sql";
my $backupfile = $dbname."_".$time_stamp.$part.".sql";
$sql_text .= "/*!40101 SET NAMES '".$character_set."' */;\n";
$sql_text .= "SET FOREIGN_KEY_CHECKS=0;\n";
my ($filesize,$err) = WriteToDumpFile($sql_text,$sql_file);
if($err) {
return (undef,undef,undef,undef,$err);
}
chmod(0777,$sql_file);
$sql_text = "";
my $first_insert = 0;
return ($sql_text,$first_insert,$sql_file,$backupfile,undef);
}
####################################################################################################
# Schreiben DB-Dumps in SQL-File
####################################################################################################
sub WriteToDumpFile ($$) {
my ($inh,$sql_file) = @_;
my $filesize;
my $err = 0;
if(length($inh) > 0) {
unless(open(DATEI,">>$sql_file")) {
$err = "Can't open file '$sql_file' for write access";
return (undef,$err);
}
print DATEI $inh;
close(DATEI);
$filesize = (stat($sql_file))[7];
}
return ($filesize,undef);
}
####################################################################################################
# Filesize (Byte) umwandeln in KB bzw. MB
####################################################################################################
sub byte_output ($) {
my $bytes = shift;
return if(!defined($bytes));
return $bytes if(!looks_like_number($bytes));
my $suffix = "Bytes";
if ($bytes >= 1024) { $suffix = "KB"; $bytes = sprintf("%.2f",($bytes/1024));};
if ($bytes >= 1024) { $suffix = "MB"; $bytes = sprintf("%.2f",($bytes/1024));};
my $ret = sprintf "%.2f",$bytes;
$ret.=' '.$suffix;
return $ret;
}
####################################################################################################
# Tabellenoptimierung MySQL
####################################################################################################
sub mysql_optimize_tables ($$@) {
my ($hash,$dbh,@tablenames) = @_;
my $name = $hash->{NAME};
my $dbname = $hash->{DATABASE};
my $ret = 0;
my $opttbl = 0;
my $db_tables = $hash->{HELPER}{DBTABLES};
my ($engine,$tablename,$query,$sth,$value,$db_MB_start,$db_MB_end);
# Anfangsgröße ermitteln
$query = "SELECT sum( data_length + index_length ) / 1024 / 1024 FROM information_schema.TABLES where table_schema='$dbname' ";
Log3 ($name, 5, "DbRep $name - current query: $query ");
eval { $sth = $dbh->prepare($query);
$sth->execute;
};
if ($@) {
Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@);
Log3 ($name, 4, "DbRep $name -> BlockingCall DbRep_optimizeTables finished");
$sth->finish;
$dbh->disconnect;
return ($@,undef,undef);
}
$value = $sth->fetchrow();
$db_MB_start = sprintf("%.2f",$value);
Log3 ($name, 3, "DbRep $name - Size of database $dbname before optimize (MB): $db_MB_start");
Log3($name, 3, "DbRep $name - Optimizing tables");
foreach $tablename (@tablenames) {
#optimize table if engine supports optimization
$engine = '';
$engine = uc($db_tables->{$tablename}{Engine}) if($db_tables->{$tablename}{Engine});
if ($engine =~ /(MYISAM|BDB|INNODB|ARIA)/) {
Log3($name, 3, "DbRep $name - Optimizing table `$tablename` ($engine). It will take a while.");
my $sth_to = $dbh->prepare("OPTIMIZE TABLE `$tablename`");
$ret = $sth_to->execute;
if ($ret) {
Log3($name, 3, "DbRep $name - Table ".($opttbl+1)." `$tablename` optimized successfully.");
$opttbl++;
} else {
Log3($name, 2, "DbRep $name - Error while optimizing table $tablename. Continue with next table or backup.");
}
}
}
Log3($name, 3, "DbRep $name - $opttbl tables have been optimized.") if($opttbl > 0);
# Endgröße ermitteln
eval { $sth->execute; };
if ($@) {
Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@);
Log3 ($name, 4, "DbRep $name -> BlockingCall DbRep_optimizeTables finished");
$sth->finish;
$dbh->disconnect;
return ($@,undef,undef);
}
$value = $sth->fetchrow();
$db_MB_end = sprintf("%.2f",$value);
Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB_end");
$sth->finish;
return (undef,$db_MB_start,$db_MB_end);
}
####################################################################################################
# Dump-Files im dumpDirLocal löschen bis auf die letzten "n"
####################################################################################################
sub deldumpfiles ($$) {
my ($hash,$bfile) = @_;
my $name = $hash->{NAME};
my $dbloghash = $hash->{dbloghash};
my $dump_path_def = $attr{global}{modpath}."/log/";
my $dump_path_loc = AttrVal($name,"dumpDirLocal", $dump_path_def);
my $dfk = AttrVal($name,"dumpFilesKeep", 3);
my $pfix = (split '\.', $bfile)[-1];
my $dbname = (split '_', $bfile)[0];
my $file = $dbname."_.*".$pfix;
my @fd;
if(!opendir(DH, $dump_path_loc)) {
push(@fd, "No files deleted - Can't open path '$dump_path_loc'");
return @fd;
}
my @files = sort grep {/^$file$/} readdir(DH);
@files = sort { (stat("$dump_path_loc/$a"))[9] cmp (stat("$dump_path_loc/$b"))[9] } @files
if(AttrVal("global", "archivesort", "alphanum") eq "timestamp");
closedir(DH);
Log3($name, 5, "DbRep $name - Dump files have been found in dumpDirLocal '$dump_path_loc': ".join(', ',@files) );
my $max = int(@files)-$dfk;
for(my $i = 0; $i < $max; $i++) {
push(@fd, $files[$i]);
Log3($name, 3, "DbRep $name - Deleting old dumpfile '$files[$i]' ");
unlink("$dump_path_loc/$files[$i]");
}
return @fd;
}
####################################################################################################
# erzeugtes Dump-File aus dumpDirLocal zum FTP-Server übertragen
####################################################################################################
sub sendftp ($$) {
my ($hash,$bfile) = @_;
my $name = $hash->{NAME};
my $dbloghash = $hash->{dbloghash};
my $dump_path_def = $attr{global}{modpath}."/log/";
my $dump_path_loc = AttrVal($name,"dumpDirLocal", $dump_path_def);
my $file = (split /[\/]/, $bfile)[-1];
my $ftpto = AttrVal($name,"ftpTimeout",30);
my $ftpUse = AttrVal($name,"ftpUse",0);
my $ftpuseSSL = AttrVal($name,"ftpUseSSL",0);
my $ftpDir = AttrVal($name,"ftpDir","/");
my $ftpPort = AttrVal($name,"ftpPort",21);
my $ftpServer = AttrVal($name,"ftpServer",undef);
my $ftpUser = AttrVal($name,"ftpUser","anonymous");
my $ftpPwd = AttrVal($name,"ftpPwd",undef);
my $ftpPassive = AttrVal($name,"ftpPassive",0);
my $ftpDebug = AttrVal($name,"ftpDebug",0);
my ($ftperr,$ftpmsg,$ftp);
# kein FTP verwenden oder möglich
return ($ftperr,$ftpmsg) if((!$ftpUse && !$ftpuseSSL) || !$bfile);
if(!$ftpServer) {
$ftperr = "FTP-Error: FTP-Server isn't set.";
Log3($name, 2, "DbRep $name - $ftperr");
return ($ftperr,undef);
}
if(!opendir(DH, $dump_path_loc)) {
$ftperr = "FTP-Error: Can't open path '$dump_path_loc'";
Log3($name, 2, "DbRep $name - $ftperr");
return ($ftperr,undef);
}
my $mod_ftpssl = 0;
my $mod_ftp = 0;
my $mod;
if ($ftpuseSSL) {
# FTP mit SSL soll genutzt werden
$mod = "Net::FTPSSL => e.g. with 'sudo cpan -i Net::FTPSSL' ";
eval { require Net::FTPSSL; };
if(!$@){
$mod_ftpssl = 1;
import Net::FTPSSL;
}
} else {
# nur FTP
$mod = "Net::FTP";
eval { require Net::FTP; };
if(!$@){
$mod_ftp = 1;
import Net::FTP;
}
}
if ($ftpuseSSL && $mod_ftpssl) {
# use ftp-ssl
my $enc = "E";
eval { $ftp = Net::FTPSSL->new($ftpServer, Port => $ftpPort, Timeout => $ftpto, Debug => $ftpDebug, Encryption => $enc) }
or $ftperr = "FTP-SSL-ERROR: Can't connect - $@";
} elsif (!$ftpuseSSL && $mod_ftp) {
# use plain ftp
eval { $ftp = Net::FTP->new($ftpServer, Port => $ftpPort, Timeout => $ftpto, Debug => $ftpDebug, Passive => $ftpPassive) }
or $ftperr = "FTP-Error: Can't connect - $@";
} else {
$ftperr = "FTP-Error: required module couldn't be loaded. You have to install it first: $mod.";
}
if ($ftperr) {
Log3($name, 2, "DbRep $name - $ftperr");
return ($ftperr,undef);
}
my $pwdstr = $ftpPwd?$ftpPwd:" ";
$ftp->login($ftpUser, $ftpPwd) or $ftperr = "FTP-Error: Couldn't login with user '$ftpUser' and password '$pwdstr' ";
if ($ftperr) {
Log3($name, 2, "DbRep $name - $ftperr");
return ($ftperr,undef);
}
$ftp->binary();
# FTP Verzeichnis setzen
$ftp->cwd($ftpDir) or $ftperr = "FTP-Error: Couldn't change directory to '$ftpDir' ";
if ($ftperr) {
Log3($name, 2, "DbRep $name - $ftperr");
return ($ftperr,undef);
}
$dump_path_loc =~ s/(\/$|\\$)//;
Log3($name, 3, "DbRep $name - FTP: transferring ".$dump_path_loc."/".$file);
$ftpmsg = $ftp->put($dump_path_loc."/".$file);
if (!$ftpmsg) {
$ftperr = "FTP-Error: Couldn't transfer ".$file." to ".$ftpServer." into dir ".$ftpDir;
Log3($name, 2, "DbRep $name - $ftperr");
} else {
$ftpmsg = "FTP: ".$file." transferred successfully to ".$ftpServer." into dir ".$ftpDir;
Log3($name, 3, "DbRep $name - $ftpmsg");
}
return ($ftperr,$ftpmsg);
}
####################################################################################################
# Browser Refresh nach DB-Abfrage
####################################################################################################
sub browser_refresh($) {
my ($hash) = @_;
RemoveInternalTimer($hash, "browser_refresh");
{FW_directNotify("#FHEMWEB:WEB", "location.reload('true')", "")};
# map { FW_directNotify("#FHEMWEB:$_", "location.reload(true)", "") } devspec2array("WEB.*");
return;
}
####################################################################################################
# Test auf Daylight saving time
####################################################################################################
sub dsttest ($$$) {
my ($hash,$runtime,$aggsec) = @_;
my $name = $hash->{NAME};
my $dstchange = 0;
# der Wechsel der daylight saving time wird dadurch getestet, dass geprüft wird
# ob im Vergleich der aktuellen zur nächsten Selektionsperiode von "$aggsec (day, week, month)"
# ein Wechsel der daylight saving time vorliegt
my $dst = (localtime($runtime))[8]; # ermitteln daylight saving aktuelle runtime
my $time_str = localtime($runtime+$aggsec); # textual time representation
my $dst_new = (localtime($runtime+$aggsec))[8]; # ermitteln daylight saving nächste runtime
if ($dst != $dst_new) {
$dstchange = 1;
}
Log3 ($name, 5, "DbRep $name - Daylight savings changed: $dstchange (on $time_str)");
return $dstchange;
}
####################################################################################################
# Counthash Untersuchung
# Logausgabe der Anzahl verarbeiteter Datensätze pro Zeitraum / Aggregation
# Rückgabe eines ncp-hash (no calc in period) mit den Perioden für die keine Differenz berechnet
# werden konnte weil nur ein Datensatz in der Periode zur Verfügung stand
####################################################################################################
sub calcount ($$) {
my ($hash,$ch) = @_;
my $name = $hash->{NAME};
my %ncp = ();
Log3 ($name, 4, "DbRep $name - count of values used for calc:");
foreach my $key (sort(keys%{$ch})) {
Log3 ($name, 4, "$key => ". $ch->{$key});
if($ch->{$key} eq "1") {
$ncp{"$key"} = " ||";
}
}
return \%ncp;
}
####################################################################################################
# Funktionsergebnisse in Datenbank schreiben
####################################################################################################
sub DbRep_OutputWriteToDB($$$$$) {
my ($name,$device,$reading,$arrstr,$optxt) = @_;
my $hash = $defs{$name};
my $dbloghash = $hash->{dbloghash};
my $dbconn = $dbloghash->{dbconn};
my $dbuser = $dbloghash->{dbuser};
my $dblogname = $dbloghash->{NAME};
my $dbmodel = $hash->{dbloghash}{MODEL};
my $DbLogType = AttrVal($hash->{dbloghash}{NAME}, "DbLogType", "History");
my $supk = AttrVal($hash->{dbloghash}{NAME}, "noSupportPK", 0);
my $dbpassword = $attr{"sec$dblogname"}{secret};
my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0;
$device =~ s/[^A-Za-z\/\d_\.-]/\//g;
$reading =~ s/[^A-Za-z\/\d_\.-]/\//g;
my $type = "calculated";
my $event = "calculated";
my $unit = "";
my $wrt = 0;
my $irowdone = 0;
my ($dbh,$sth_ih,$sth_uh,$sth_ic,$sth_uc,$err,$timestamp,$value,$date,$time,$rsf,$aggr,@row_array);
if(!$hash->{dbloghash}{HELPER}{COLSET}) {
$err = "No result of \"$hash->{LASTCMD}\" to database written. Cause: column width in \"$hash->{DEF}\" isn't set";
return ($wrt,$irowdone,$err);
}
no warnings 'uninitialized';
(undef,undef,$aggr) = checktimeaggr($hash);
$reading = $optxt."_".$aggr."_".$reading;
$type = $defs{$device}{TYPE} if($defs{$device}); # $type vom Device ableiten
if($optxt =~ /avg|sum/) {
my @arr = split("\\|", $arrstr);
foreach my $row (@arr) {
my @a = split("#", $row);
my $runtime_string = $a[0]; # Aggregations-Alias (nicht benötigt)
$value = $a[1]?sprintf("%.4f",$a[1]):undef;
$rsf = $a[2]; # Datum / Zeit für DB-Speicherung
($date,$time) = split("_",$rsf);
$time =~ s/-/:/g if($time);
if($time !~ /^(\d{2}):(\d{2}):(\d{2})$/) {
if($aggr =~ /no|day|week|month/) {
$time = "23:59:58";
} elsif ($aggr =~ /hour/) {
$time = "$time:59:58";
}
}
if ($value) {
# Daten auf maximale Länge beschneiden (DbLog-Funktion !)
($device,$type,$event,$reading,$value,$unit) = DbLog_cutCol($hash->{dbloghash},$device,$type,$event,$reading,$value,$unit);
push(@row_array, "$date $time|$device|$type|$event|$reading|$value|$unit");
}
}
}
if($optxt =~ /min|max|diff/) {
my %rh = split("§", $arrstr);
foreach my $key (sort(keys(%rh))) {
my @k = split("\\|",$rh{$key});
$rsf = $k[2]; # Datum / Zeit für DB-Speicherung
$value = $k[1]?sprintf("%.4f",$k[1]):undef;
($date,$time) = split("_",$rsf);
$time =~ s/-/:/g if($time);
if($time !~ /^(\d{2}):(\d{2}):(\d{2})$/) {
if($aggr =~ /no|day|week|month/) {
$time = "23:59:58";
} elsif ($aggr =~ /hour/) {
$time = "$time:59:58";
}
}
if ($value) {
# Daten auf maximale Länge beschneiden (DbLog-Funktion !)
($device,$type,$event,$reading,$value,$unit) = DbLog_cutCol($hash->{dbloghash},$device,$type,$event,$reading,$value,$unit);
push(@row_array, "$date $time|$device|$type|$event|$reading|$value|$unit");
}
}
}
if (@row_array) {
# Schreibzyklus aktivieren
eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, mysql_enable_utf8 => $utf8 });};
if ($@) {
$err = $@;
Log3 ($name, 2, "DbRep $name - $@");
return ($wrt,$irowdone,$err);
}
# check ob PK verwendet wird, @usepkx?Anzahl der Felder im PK:0 wenn kein PK, $pkx?Namen der Felder:none wenn kein PK
my ($usepkh,$usepkc,$pkh,$pkc);
if (!$supk) {
($usepkh,$usepkc,$pkh,$pkc) = DbRep_checkUsePK($hash,$dbh);
} else {
Log3 $hash->{NAME}, 5, "DbRep $name -> Primary Key usage suppressed by attribute noSupportPK in DbLog \"$dblogname\"";
}
if (lc($DbLogType) =~ m(history)) {
# insert history mit/ohne primary key
if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') {
eval { $sth_ih = $dbh->prepare_cached("INSERT IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
} elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') {
eval { $sth_ih = $dbh->prepare_cached("INSERT OR IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
} elsif ($usepkh && $dbloghash->{MODEL} eq 'POSTGRESQL') {
eval { $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?) ON CONFLICT DO NOTHING"); };
} else {
eval { $sth_ih = $dbh->prepare_cached("INSERT INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
}
if ($@) {
$err = $@;
Log3 ($name, 2, "DbRep $name - $@");
return ($wrt,$irowdone,$err);
}
# update history mit/ohne primary key
if ($usepkh && $hash->{MODEL} eq 'MYSQL') {
$sth_uh = $dbh->prepare("REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)");
} elsif ($usepkh && $hash->{MODEL} eq 'SQLITE') {
$sth_uh = $dbh->prepare("INSERT OR REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)");
} elsif ($usepkh && $hash->{MODEL} eq 'POSTGRESQL') {
$sth_uh = $dbh->prepare("INSERT INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?) ON CONFLICT ($pkc)
DO UPDATE SET TIMESTAMP=EXCLUDED.TIMESTAMP, DEVICE=EXCLUDED.DEVICE, TYPE=EXCLUDED.TYPE, EVENT=EXCLUDED.EVENT, READING=EXCLUDED.READING,
VALUE=EXCLUDED.VALUE, UNIT=EXCLUDED.UNIT");
} else {
$sth_uh = $dbh->prepare("UPDATE history SET TYPE=?, EVENT=?, VALUE=?, UNIT=? WHERE (TIMESTAMP=?) AND (DEVICE=?) AND (READING=?)");
}
}
if (lc($DbLogType) =~ m(current) ) {
# insert current mit/ohne primary key
if ($usepkc && $hash->{MODEL} eq 'MYSQL') {
eval { $sth_ic = $dbh->prepare("INSERT IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
} elsif ($usepkc && $hash->{MODEL} eq 'SQLITE') {
eval { $sth_ic = $dbh->prepare("INSERT OR IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
} elsif ($usepkc && $hash->{MODEL} eq 'POSTGRESQL') {
eval { $sth_ic = $dbh->prepare("INSERT INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?) ON CONFLICT DO NOTHING"); };
} else {
# old behavior
eval { $sth_ic = $dbh->prepare("INSERT INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); };
}
if ($@) {
$err = $@;
Log3 ($name, 2, "DbRep $name - $@");
return ($wrt,$irowdone,$err);
}
# update current mit/ohne primary key
if ($usepkc && $hash->{MODEL} eq 'MYSQL') {
$sth_uc = $dbh->prepare("REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)");
} elsif ($usepkc && $hash->{MODEL} eq 'SQLITE') {
$sth_uc = $dbh->prepare("INSERT OR REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)");
} elsif ($usepkc && $hash->{MODEL} eq 'POSTGRESQL') {
$sth_uc = $dbh->prepare("INSERT INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?) ON CONFLICT ($pkc)
DO UPDATE SET TIMESTAMP=EXCLUDED.TIMESTAMP, DEVICE=EXCLUDED.DEVICE, TYPE=EXCLUDED.TYPE, EVENT=EXCLUDED.EVENT, READING=EXCLUDED.READING,
VALUE=EXCLUDED.VALUE, UNIT=EXCLUDED.UNIT");
} else {
$sth_uc = $dbh->prepare("UPDATE current SET TIMESTAMP=?, TYPE=?, EVENT=?, VALUE=?, UNIT=? WHERE (DEVICE=?) AND (READING=?)");
}
}
eval { $dbh->begin_work() if($dbh->{AutoCommit}); };
if ($@) {
Log3($name, 2, "DbRep $name -> Error start transaction for history - $@");
}
Log3 $hash->{NAME}, 5, "DbRep $name - data prepared to db write:";
# SQL-Startzeit
my $wst = [gettimeofday];
my $ihs = 0;
my $uhs = 0;
foreach my $row (@row_array) {
my @a = split("\\|",$row);
$timestamp = $a[0];
$device = $a[1];
$type = $a[2];
$event = $a[3];
$reading = $a[4];
$value = $a[5];
$unit = $a[6];
Log3 $hash->{NAME}, 5, "DbRep $name - $row";
eval {
# update oder insert history
if (lc($DbLogType) =~ m(history) ) {
my $rv_uh = $sth_uh->execute($type,$event,$value,$unit,$timestamp,$device,$reading);
if ($rv_uh == 0) {
$sth_ih->execute($timestamp,$device,$type,$event,$reading,$value,$unit);
$ihs++;
} else {
$uhs++;
}
}
# update oder insert current
if (lc($DbLogType) =~ m(current) ) {
my $rv_uc = $sth_uc->execute($timestamp,$type,$event,$value,$unit,$device,$reading);
if ($rv_uc == 0) {
$sth_ic->execute($timestamp,$device,$type,$event,$reading,$value,$unit);
}
}
};
if ($@) {
$err = $@;
Log3 ($name, 2, "DbRep $name - $@");
$dbh->rollback;
$dbh->disconnect;
$ihs = 0;
$uhs = 0;
return ($wrt,0,$err);
} else {
$irowdone++;
}
}
eval {$dbh->commit() if(!$dbh->{AutoCommit});};
$dbh->disconnect;
Log3 $hash->{NAME}, 3, "DbRep $name - number of lines updated in \"$dblogname\": $uhs";
Log3 $hash->{NAME}, 3, "DbRep $name - number of lines inserted into \"$dblogname\": $ihs";
# SQL-Laufzeit ermitteln
$wrt = tv_interval($wst);
}
return ($wrt,$irowdone,$err);
}
################################################################
# check ob primary key genutzt wird
################################################################
sub DbRep_checkUsePK ($$){
my ($hash,$dbh) = @_;
my $name = $hash->{NAME};
my $dbconn = $hash->{dbloghash}{dbconn};
my $upkh = 0;
my $upkc = 0;
my (@pkh,@pkc);
my $db = (split("=",(split(";",$dbconn))[0]))[1];
eval {@pkh = $dbh->primary_key( undef, undef, 'history' );};
eval {@pkc = $dbh->primary_key( undef, undef, 'current' );};
my $pkh = (!@pkh || @pkh eq "")?"none":join(",",@pkh);
my $pkc = (!@pkc || @pkc eq "")?"none":join(",",@pkc);
$pkh =~ tr/"//d;
$pkc =~ tr/"//d;
$upkh = 1 if(@pkh && @pkh ne "none");
$upkc = 1 if(@pkc && @pkc ne "none");
Log3 $hash->{NAME}, 5, "DbRep $name -> Primary Key used in $db.history: $pkh";
Log3 $hash->{NAME}, 5, "DbRep $name -> Primary Key used in $db.current: $pkc";
return ($upkh,$upkc,$pkh,$pkc);
}
####################################################################################################
# Test-Sub zu Testzwecken
####################################################################################################
sub testexit ($) {
my ($hash) = @_;
my $name = $hash->{NAME};
if ( !DbRep_Connect($hash) ) {
Log3 ($name, 2, "DbRep $name - DB connect failed. Database down ? ");
ReadingsSingleUpdateValue ($hash, "state", "disconnected", 1);
return;
} else {
my $dbh = $hash->{DBH};
Log3 ($name, 3, "DbRep $name - --------------- FILE INFO --------------");
my $sqlfile = $dbh->sqlite_db_filename();
Log3 ($name, 3, "DbRep $name - FILE : $sqlfile ");
# # $dbh->table_info( $catalog, $schema, $table)
# my $sth = $dbh->table_info('', '%', '%');
# my $tables = $dbh->selectcol_arrayref($sth, {Columns => [3]});
# my $table = join ', ', @$tables;
# Log3 ($name, 3, "DbRep $name - SQL_TABLES : $table");
Log3 ($name, 3, "DbRep $name - --------------- PRAGMA --------------");
my @InfoTypes = ('sqlite_db_status');
foreach my $row (@InfoTypes) {
# my @linehash = $dbh->$row;
my $array= $dbh->$row ;
# push(@row_array, @array);
while ((my $key, my $val) = each %{$array}) {
Log3 ($name, 3, "DbRep $name - PRAGMA : $key : ".%{$val});
}
}
# $sth->finish;
$dbh->disconnect;
}
return;
}
1;
=pod
=item helper
=item summary Reporting & Management content of DbLog-DB's. Content is depicted as readings
=item summary_DE Reporting & Management von DbLog-DB Content. Darstellung als Readings
=begin html
DbRep
The purpose of this module is browsing and managing the content of DbLog-databases. The searchresults can be evaluated concerning to various aggregations and the appropriate
Readings will be filled. The data selection will been done by declaration of device, reading and the time settings of selection-begin and selection-end.
All database operations are implemented nonblocking. Optional the execution time of SQL-statements in background can also be determined and provided as reading.
(refer to attributes).
All existing readings will be deleted when a new operation starts. By attribute "readingPreventFromDel" a comma separated list of readings which are should prevent
from deletion can be provided.
Currently the following functions are provided:
- Selection of all datasets within adjustable time limits.
- Exposure of datasets of a Device/Reading-combination within adjustable time limits.
- Selecion of datasets by usage of dynamically calclated time limits at execution time.
- Calculation of quantity of datasets of a Device/Reading-combination within adjustable time limits and several aggregations.
- The calculation of summary-, difference-, maximum-, minimum- and averageValues of numeric readings within adjustable time limits and several aggregations.
- write back results of summary-, difference-, maximum-, minimum- and average calculation into the database
- The deletion of datasets. The containment of deletion can be done by Device and/or Reading as well as fix or dynamically calculated time limits at execution time.
- export of datasets to file (CSV-format).
- import of datasets from file (CSV-Format).
- rename of device names in datasets
- automatic rename of device names in datasets and other DbRep-definitions after FHEM "rename" command (see DbRep-Agent)
- Execution of arbitrary user specific SQL-commands
- creation of backups of the database in running state non-blocking (MySQL, SQLite)
- transfer dumpfiles to a FTP server after backup
- restore of SQLite-dumps and MySQL serverSide-backups non-blocking
- optimize the connected database (optimizeTables, vacuum)
- report of existing database processes (MySQL)
- purge content of current-table
- fill up the current-table with a (tunable) extract of the history-table
- delete consecutive datasets (clearing up consecutive doublets)
To activate the function "Autorename" the attribute "role" has to be assigned to a defined DbRep-device. The standard role after DbRep definition is "Client.
Please read more in section DbRep-Agent .
DbRep provides a UserExit function. By that interface the user can execute own program code dependent from free
definable Reading/Value-combinations (Regex). The interface works without respectively independent from event
generation.
Further informations you can find as described at attribute "userExitFn".
FHEM-Forum:
Modul 93_DbRep - Reporting and Management of database content (DbLog).
Preparations
The module requires the usage of a DbLog instance and the credentials of the database definition will be used.
Only the content of table "history" will be included if isn't other is explained.
Overview which other Perl-modules DbRep is using:
Net::FTP (only if FTP-Transfer after database dump is used)
Net::FTPSSL (only if FTP-Transfer with encoding after database dump is used)
POSIX
Time::HiRes
Time::Local
Scalar::Util
DBI
Blocking (FHEM-module)
Due to performance reason the following index should be created in addition:
CREATE INDEX Report_Idx ON `history` (TIMESTAMP, READING) USING BTREE;
Definition
define <name> DbRep <name of DbLog-instance>
(<name of DbLog-instance> - name of the database instance which is wanted to analyze needs to be inserted)
Set
Currently following set-commands are included. They are used to trigger the evaluations and define the evaluation option option itself.
The criteria of searching database content and determine aggregation is carried out by setting several attributes.
- averageValue [display | writeToDB]
- calculates the average value of database column "VALUE" between period given by
timestamp-attributes which are set.
The reading to evaluate must be specified using attribute "reading".
Is no or the option "display" specified, the results are only displayed. Using
option "writeToDB" the calculated results are stored in the database with a new reading
name.
The new readingname is built of a prefix and the original reading name.
The prefix is made up of the creation function and the aggregation.
The timestamp of the new stored readings is deviated from aggregation period,
unless no unique point of time of the result can be determined.
The field "EVENT" will be filled with "calculated".
Example of building a new reading name from the original reading "totalpac":
avg_day_totalpac
# <creation function>_<aggregation>_<original reading>
- countEntries [history|current] - provides the number of table-entries (default: history) between period set
by timestamp-attributes if set.
If timestamp-attributes are not set, all entries of the table will be count.
The attributes "device" and "reading" can be used to
limit the evaluation.
- delEntries - deletes all database entries or only the database entries specified by attributes Device and/or
Reading and the entered time period between "timestamp_begin", "timestamp_end" (if set) or "timeDiffToNow/timeOlderThan".
"timestamp_begin" is set: deletes db entries from this timestamp until current date/time
"timestamp_end" is set : deletes db entries until this timestamp
both Timestamps are set : deletes db entries between these timestamps
Due to security reasons the attribute attribute "allowDeletion" needs to be set to unlock the
delete-function.
- delSeqDoublets [adviceRemain | adviceDelete | delete] - show respectively delete identical sequentially datasets.
Therefore Device,Reading and Value of the sequentially datasets are compared.
Not deleted are the first und the last dataset of a aggregation period (e.g. hour,day,week and so on) as
well as the datasets before or after a value change (database field VALUE).
The attributes to define the scope of aggregation,time period, device and reading are
considered. If attribute aggregation is not set or set to "no", it will change to the default aggregation
period "day". For datasets containing numerical values it is possible to determine a variance with attribute
"seqDoubletsVariance". Up to this value consecutive numerical datasets are handled as identical and should be
deleted.
adviceRemain | : simulates the remaining datasets in database after delete-operation (nothing will be deleted !) |
adviceDelete | : simulates the datasets to delete in database (nothing will be deleted !) |
delete | : deletes the consecutive doublets (see example) |
Due to security reasons the attribute attribute "allowDeletion" needs to be set for
execute the "delete" option.
The amount of datasets to show by commands "delSeqDoublets adviceDelete", "delSeqDoublets adviceRemain" is
initially limited (default: 1000) and can be adjusted by attribute "limit".
The adjustment of "limit" has no impact to the "delSeqDoublets delete" function, but affects ONLY the
display of the data.
Example - the remaining datasets after executing delete-option are are marked as bold:
2017-11-25_00-00-05__eg.az.fridge_Pwr__power 0
2017-11-25_00-02-26__eg.az.fridge_Pwr__power 0
2017-11-25_00-04-33__eg.az.fridge_Pwr__power 0
2017-11-25_01-06-10__eg.az.fridge_Pwr__power 0
2017-11-25_01-08-21__eg.az.fridge_Pwr__power 0
2017-11-25_01-08-59__eg.az.fridge_Pwr__power 60.32
2017-11-25_01-11-21__eg.az.fridge_Pwr__power 56.26
2017-11-25_01-27-54__eg.az.fridge_Pwr__power 6.19
2017-11-25_01-28-51__eg.az.fridge_Pwr__power 0
2017-11-25_01-31-00__eg.az.fridge_Pwr__power 0
2017-11-25_01-33-59__eg.az.fridge_Pwr__power 0
2017-11-25_02-39-29__eg.az.fridge_Pwr__power 0
2017-11-25_02-41-18__eg.az.fridge_Pwr__power 105.28
2017-11-25_02-41-26__eg.az.fridge_Pwr__power 61.52
2017-11-25_03-00-06__eg.az.fridge_Pwr__power 47.46
2017-11-25_03-00-33__eg.az.fridge_Pwr__power 0
2017-11-25_03-02-07__eg.az.fridge_Pwr__power 0
2017-11-25_23-37-42__eg.az.fridge_Pwr__power 0
2017-11-25_23-40-10__eg.az.fridge_Pwr__power 0
2017-11-25_23-42-24__eg.az.fridge_Pwr__power 1
2017-11-25_23-42-24__eg.az.fridge_Pwr__power 1
2017-11-25_23-45-27__eg.az.fridge_Pwr__power 1
2017-11-25_23-47-07__eg.az.fridge_Pwr__power 0
2017-11-25_23-55-27__eg.az.fridge_Pwr__power 0
2017-11-25_23-48-15__eg.az.fridge_Pwr__power 0
2017-11-25_23-50-21__eg.az.fridge_Pwr__power 59.1
2017-11-25_23-55-14__eg.az.fridge_Pwr__power 52.31
2017-11-25_23-58-09__eg.az.fridge_Pwr__power 51.73
- deviceRename - renames the device name of a device inside the connected database (Internal DATABASE).
The devicename will allways be changed in the entire database. Possibly set time limits or restrictions by
attributes device and/or reading will not be considered.
input format: set <name> deviceRename <old device name>,<new device name>
# The amount of renamed device names (datasets) will be displayed in reading "device_renamed".
# If the device name to be renamed was not found in the database, a WARNUNG will appear in reading "device_not_renamed".
# Appropriate entries will be written to Logfile if verbose >= 3 is set.
Note:
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
is operating in asynchronous mode to avoid FHEMWEB from blocking.
- diffValue [display | writeToDB]
- calculates the difference of database column "VALUE" between period given by
attributes "timestamp_begin", "timestamp_end" or "timeDiffToNow / timeOlderThan".
The reading to evaluate must be defined using attribute "reading".
This function is mostly reasonable if readingvalues are increasing permanently and don't write value-differences to the database.
The difference will be generated from the first available dataset (VALUE-Field) to the last available dataset between the
specified time linits/aggregation, in which a balanced difference value of the previous aggregation period will be transfered to the
following aggregation period in case this period contains a value.
An possible counter overrun (restart with value "0") will be considered (compare attribute "diffAccept").
If only one dataset will be found within the evalution period, the difference can be calculated only in combination with the balanced
difference of the previous aggregation period. In this case a logical inaccuracy according the assignment of the difference to the particular aggregation period
can be possible. Hence in warning in "state" will be placed and the reading "less_data_in_period" with a list of periods
with only one dataset found in it will be created.
Note:
Within the evaluation respectively aggregation period (day, week, month, etc.) you should make available at least one dataset
at the beginning and one dataset at the end of each aggregation period to take the difference calculation as much as possible.
Is no or the option "display" specified, the results are only displayed. Using
option "writeToDB" the calculation results are stored in the database with a new reading
name.
The new readingname is built of a prefix and the original reading name.
The prefix is made up of the creation function and the aggregation.
The timestamp of the new stored readings is deviated from aggregation period,
unless no unique point of time of the result can be determined.
The field "EVENT" will be filled with "calculated".
Example of building a new reading name from the original reading "totalpac":
diff_day_totalpac
# <creation function>_<aggregation>_<original reading>
- dumpMySQL [clientSide | serverSide]
- creates a dump of the connected MySQL database.
Depended from selected option the dump will be created on Client- or on Serv-Side.
The variants differs each other concerning the executing system, the creating location, the usage of
attributes, the function result and the needed hardware ressources.
The option "clientSide" e.g. needs more powerful FHEM-Server hardware, but saves all available
tables inclusive possibly created views.
Option clientSide
The dump will be created by client (FHEM-Server) and will be saved in FHEM log-directory by
default.
The target directory can be set by attribute "dumpDirLocal" and has to be
writable by the FHEM process.
Before executing the dump a table optimization can be processed optionally (see attribute
"optimizeTablesBeforeDump") as well as a FHEM-command (attribute "executeBeforeProc").
Note:
To avoid FHEM from blocking, you have to operate DbLog in asynchronous mode if the table
optimization want to be used !
After the dump a FHEM-command can be executed as well (see attribute "executeAfterProc").
By the attributes "dumpMemlimit" and "dumpSpeed" the run-time behavior of the function can be
controlled to optimize the performance and demand of ressources.
The attributes relevant for function "dumpMySQL clientSide" are "dumpComment", "dumpDirLocal", "dumpMemlimit",
"dumpSpeed ", "dumpFilesKeep", "executeBeforeProc", "executeAfterProc" and
"optimizeTablesBeforeDump".
After a successfull finished dump the old dumpfiles are deleted and only the number of files
defined by attribute "dumpFilesKeep" (default: 3) remain in the target directory
"dumpDirLocal".
The naming convention of dump files is: <dbname>_<date>_<time>.sql
The created dumpfile may imported on the MySQL-Server by e.g.:
mysql -u <user> -p <dbname> < <filename>.sql
to restore the database from the dump.
Option serverSide
The dump will be created on the MySQL-Server and will be saved in its Home-directory
by default.
The whole history-table (not the current-table) will be exported CSV-formatted without
any restrictions.
Before executing the dump a table optimization can be processed optionally (see attribute
"optimizeTablesBeforeDump") as well as a FHEM-command (attribute "executeBeforeProc").
Note:
To avoid FHEM from blocking, you have to operate DbLog in asynchronous mode if the table
optimization want to be used !
After the dump a FHEM-command can be executed as well (see attribute "executeAfterProc").
The attributes relevant for function "dumpMySQL serverSide" are "dumpDirRemote", "dumpDirLocal",
"dumpFilesKeep", "optimizeTablesBeforeDump", "executeBeforeProc" and "executeAfterProc".
The target directory can be set by attribute "dumpDirRemote".
It must be located on the MySQL-Host and has to be writable by the MySQL-server process.
The used database user must have the "FILE"-privilege.
Note:
If the internal version management of DbRep should be used and the size of the created dumpfile be
reported, you have to mount the remote MySQL-Server directory "dumpDirRemote" on the client
and publish it to the DbRep-device by fill out the attribute
"dumpDirLocal".
Same is necessary if ftp transfer after dump is to be used (attribute "ftpUse" respectively "ftpUseSSL").
Example:
attr <DbRep-device> dumpDirRemote /volume1/ApplicationBackup/dumps_FHEM/
attr <DbRep-device> dumpDirLocal /sds1/backup/dumps_FHEM/
attr <DbRep-device> dumpFilesKeep 2
# The dump will be created remote on the MySQL-Server in directory
'/volume1/ApplicationBackup/dumps_FHEM/'.
# The internal version management searches in local mounted directory '/sds1/backup/dumps_FHEM/'
for present dumpfiles and deletes these files except the last two versions.
If the internal version management is used, after a successfull finished dump old dumpfiles will
be deleted and only the number of attribute "dumpFilesKeep" (default: 3) would remain in target
directory "dumpDirLocal" (the mounted "dumpDirRemote").
In that case FHEM needs write permissions to the directory "dumpDirLocal".
The naming convention of dump files is: <dbname>_<date>_<time>.csv
You can start a restore of table history from serverSide-Backup by command:
set <name> <restoreMySQL> <filename>.csv
FTP-Transfer after Dump
If those possibility is be used, the attribute "ftpUse" or
"ftpUseSSL" has to be set. The latter if encoding for FTP is to be used.
Further attributes are:
ftpUse | : FTP Transfer after dump will be switched on (without SSL encoding) |
ftpUser | : User for FTP-server login, default: anonymous |
ftpUseSSL | : FTP Transfer with SSL encoding after dump |
ftpDebug | : debugging of FTP communication for diagnostics |
ftpDir | : directory on FTP-server in which the file will be send into (default: "/") |
ftpPassive | : set if passive FTP is to be used |
ftpPort | : FTP-Port, default: 21 |
ftpPwd | : password of FTP-User, not set by default |
ftpServer | : name or IP-address of FTP-server. absolutely essential ! |
ftpTimeout | : timeout of FTP-connection in seconds (default: 30). |
- dumpSQLite - creates a dump of the connected SQLite database.
This function uses the SQLite Online Backup API and allow to create a consistent backup of the
database during the normal operation.
The dump will be saved in FHEM log-directory by default.
The target directory can be defined by attribute "dumpDirLocal" and
has to be writable by the FHEM process.
Before executing the dump a table optimization can be processed optionally (see attribute
"optimizeTablesBeforeDump").
Note:
To avoid FHEM from blocking, you have to operate DbLog in asynchronous mode if the table
optimization want to be used !
Before and after the dump a FHEM-command can be executed (see attribute "executeBeforeProc",
"executeAfterProc").
The attributes relevant for this function are "dumpDirLocal", "dumpFilesKeep", "executeBeforeProc",
"executeAfterProc" and "optimizeTablesBeforeDump".
After a successfull finished dump the old dumpfiles are deleted and only the number of attribute
"dumpFilesKeep" (default: 3) remain in the target directory "dumpDirLocal".
The naming convention of dump files is: <dbname>_<date>_<time>.sqlitebkp
The database can be restored by command "set <DbRep-device> restoreSQLite <filename>"
The created dump file can be transfered to a FTP-server. Please see explanations about FTP-
transfer in topic "dumpMySQL".
- exportToFile - exports DB-entries to a file in CSV-format between period given by timestamp.
Limitations of selections can be set by attributes Device and/or Reading.
The filename will be defined by attribute "expimpfile".
By setting attribute "aggregation" the export of datasets will be splitted into time slices
recording the specified aggregation.
Is, for example, "aggregation = month" set, the data are selected in monthly packets and written
into the exportfile. Thereby the usage of main memory is optimized if very large amount of data
is exported and avoid the "died prematurely" error.
- fetchrows [history|current] - provides all table-entries (default: history)
between period given by timestamp-attributes.
A possibly aggregation set will not be considered.
The direction of data selection can be determined by attribute
"fetchRoute".
- insert - use it to insert data ito table "history" manually. Input values for Date, Time and Value are mandatory. The database fields for Type and Event will be filled in with "manual" automatically and the values of Device, Reading will be get from set attributes.
input format: Date,Time,Value,[Unit]
# Unit is optional, attributes of device, reading must be set !
# If "Value=0" has to be inserted, use "Value = 0.0" to do it.
example: 2016-08-01,23:00:09,TestValue,TestUnit
# Spaces are NOT allowed in fieldvalues !
Note:
Please consider to insert AT LEAST two datasets into the intended time / aggregatiom period (day, week, month, etc.) because of
it's needed by function diffValue. Otherwise no difference can be calculated and diffValue will be print out "0" for the respective period !
importFromFile - imports datasets in CSV format from file into database. The filename will be set by attribute "expimpfile".
dataset format: "TIMESTAMP","DEVICE","TYPE","EVENT","READING","VALUE","UNIT"
# The fields "TIMESTAMP","DEVICE","TYPE","EVENT","READING" and "VALUE" have to be set. The field "UNIT" is optional.
The file content will be imported transactional. That means all of the content will be imported or, in case of error, nothing of it.
If an extensive file will be used, DON'T set verbose = 5 because of a lot of datas would be written to the logfile in this case.
It could lead to blocking or overload FHEM !
Example: "2016-09-25 08:53:56","STP_5000","SMAUTILS","etotal: 11859.573","etotal","11859.573",""
maxValue [display | writeToDB]
- calculates the maximum value of database column "VALUE" between period given by
attributes "timestamp_begin", "timestamp_end" or "timeDiffToNow / timeOlderThan".
The reading to evaluate must be defined using attribute "reading".
The evaluation contains the timestamp of the last appearing of the identified maximum value
within the given period.
Is no or the option "display" specified, the results are only displayed. Using
option "writeToDB" the calculated results are stored in the database with a new reading
name.
The new readingname is built of a prefix and the original reading name.
The prefix is made up of the creation function and the aggregation.
The timestamp of the new stored readings is deviated from aggregation period,
unless no unique point of time of the result can be determined.
The field "EVENT" will be filled with "calculated".
Example of building a new reading name from the original reading "totalpac":
max_day_totalpac
# <creation function>_<aggregation>_<original reading>
minValue [display | writeToDB]
- calculates the minimum value of database column "VALUE" between period given by
attributes "timestamp_begin", "timestamp_end" or "timeDiffToNow / timeOlderThan".
The reading to evaluate must be defined using attribute "reading".
The evaluation contains the timestamp of the first appearing of the identified minimum
value within the given period.
Is no or the option "display" specified, the results are only displayed. Using
option "writeToDB" the calculated results are stored in the database with a new reading
name.
The new readingname is built of a prefix and the original reading name.
The prefix is made up of the creation function and the aggregation.
The timestamp of the new stored readings is deviated from aggregation period,
unless no unique point of time of the result can be determined.
The field "EVENT" will be filled with "calculated".
Example of building a new reading name from the original reading "totalpac":
min_day_totalpac
# <creation function>_<aggregation>_<original reading>
optimizeTables - optimize tables in the connected database (MySQL).
Before and after an optimization it is possible to execute a FHEM command.
(please see attributes "executeBeforeProc", "executeAfterProc")
Note:
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
is operating in asynchronous mode to avoid FHEMWEB from blocking.
readingRename - renames the reading name of a device inside the connected database (see Internal DATABASE).
The readingname will allways be changed in the entire database. Possibly set time limits or restrictions by
attributes device and/or reading will not be considered.
input format: set <name> readingRename <old reading name>,<new reading name>
# The amount of renamed reading names (datasets) will be displayed in reading "reading_renamed".
# If the reading name to be renamed was not found in the database, a WARNUNG will appear in reading "reading_not_renamed".
# Appropriate entries will be written to Logfile if verbose >= 3 is set.
Note:
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
is operating in asynchronous mode to avoid FHEMWEB from blocking.
restoreMySQL <file>.csv - imports the content of table history from a serverSide-backup.
The function provides a drop-down-list of files which can be used for restore.
Therefore you have to mount the remote directory "dumpDirRemote" of the MySQL-Server on the
Client and make it usable to the DbRep-device by setting the attribute
"dumpDirLocal".
All files with extension "csv" and if the filename is beginning with the name of the connected database
(see Internal DATABASE) are listed.
restoreSQLite <File>.sqlitebkp - restores a backup of SQLite database.
The function provides a drop-down-list of files which can be used for restore.
The data stored in the current database are deleted respectively overwritten.
All files with extension "sqlitebkp" and if the filename is beginning with the name of the connected database
will are listed.
sqlCmd - executes an arbitrary user specific command.
If the command contains a operation to delete data, the attribute
"allowDeletion" has to be set for security reason.
The statement doesn't consider limitations by attributes device and/or reading.
If the attributes "timestamp_begin" respectively "timestamp_end"
should assumed in the statement, you can use the placeholder "§timestamp_begin§" respectively
"§timestamp_end§" on suitable place.
Examples of SQL-statements:
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-01-06 00:00:00" group by DEVICE having count(*) > 800
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-05-06 00:00:00" group by DEVICE
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= §timestamp_begin§ group by DEVICE
- set <name> sqlCmd select * from history where DEVICE like "Te%t" order by `TIMESTAMP` desc
- set <name> sqlCmd select * from history where `TIMESTAMP` > "2017-05-09 18:03:00" order by `TIMESTAMP` desc
- set <name> sqlCmd select * from current order by `TIMESTAMP` desc
- set <name> sqlCmd select sum(VALUE) as 'Einspeisung am 04.05.2017', count(*) as 'Anzahl' FROM history where `READING` = "Einspeisung_WirkP_Zaehler_Diff" and TIMESTAMP between '2017-05-04' AND '2017-05-05'
- set <name> sqlCmd delete from current
- set <name> sqlCmd delete from history where TIMESTAMP < "2016-05-06 00:00:00"
- set <name> sqlCmd update history set VALUE='TestVa$$ue$' WHERE VALUE='TestValue'
- set <name> sqlCmd select * from history where DEVICE = "Test"
- set <name> sqlCmd insert into history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ('2017-05-09 17:00:14','Test','manuell','manuell','Tes§e','TestValue','°C')
The result of the statement will be shown in Reading "SqlResult".
The formatting of result can be choosen by attribute "sqlResultFormat", as well as the used
field separator can be determined by attribute "sqlResultFieldSep".
Note:
Even though the module works non-blocking regarding to database operations, a huge
sample space (number of rows/readings) could block the browser session respectively
FHEMWEB.
If you are unsure about the result of the statement, you should preventively add a limit to
the statement.
sumValue [display | writeToDB]
- calculates the summary of database column "VALUE" between period given by
attributes "timestamp_begin", "timestamp_end" or
"timeDiffToNow / timeOlderThan". The reading to evaluate must be defined using attribute
"reading". Using this function is mostly reasonable if value-differences of readings
are written to the database.
Is no or the option "display" specified, the results are only displayed. Using
option "writeToDB" the calculation results are stored in the database with a new reading
name.
The new readingname is built of a prefix and the original reading name.
The prefix is made up of the creation function and the aggregation.
The timestamp of the new stored readings is deviated from aggregation period,
unless no unique point of time of the result can be determined.
The field "EVENT" will be filled with "calculated".
Example of building a new reading name from the original reading "totalpac":
sum_day_totalpac
# <creation function>_<aggregation>_<original reading>
tableCurrentFillup - the current-table will be filled u with an extract of the history-table.
The attributes for limiting time and device, reading are considered.
Thereby the content of the extract can be affected. In the associated DbLog-device the attribute "DbLogType" should be set to
"SampleFill/History".
tableCurrentPurge - deletes the content of current-table. There are no limits, e.g. by attributes "timestamp_begin", "timestamp_end", device, reading
and so on, considered.
vacuum - optimize tables in the connected database (SQLite, PostgreSQL).
Before and after an optimization it is possible to execute a FHEM command.
(please see attributes "executeBeforeProc", "executeAfterProc")
Note:
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
is operating in asynchronous mode to avoid FHEM from blocking.
For all evaluation variants (except sqlCmd,deviceRename,readingRename) applies:
In addition to the needed reading the device can be complemented to restrict the datasets for reporting / function.
If no time limit attribute is set but aggregation is set, the period from '1970-01-01 01:00:00' to the current date/time will be used as
selection criterion. If both time limit attribute and aggregation isn't set, the selection on database is runnung without timestamp criterion.
Note:
If you are in detail view it could be necessary to refresh the browser to see the result of operation as soon in DeviceOverview section "state = done" will be shown.
Get
The get-commands of DbRep provide to retrieve some metadata of the used database instance.
Those are for example adjusted server parameter, server variables, datadasestatus- and table informations. THe available get-functions depending of
the used database type. So for SQLite curently only "get svrinfo" is usable. The functions nativ are delivering a lot of outpit values.
They can be limited by function specific attributes. The filter has to be setup by a comma separated list.
SQL-Wildcard (%) can be used to setup the list arguments.
Note:
After executing a get-funktion in detail view please make a browser refresh to see the results !
- blockinginfo - list the current system wide running background processes (BlockingCalls) together with their informations.
If character string is too long (e.g. arguments) it is reported shortened.
- dbstatus - lists global informations about MySQL server status (e.g. informations related to cache, threads, bufferpools, etc. ).
Initially all available informations are reported. Using the attribute "showStatus" the quantity of
results can be limited to show only the desired values. Further detailed informations of items meaning are
explained there.
Example
get <name> dbstatus
attr <name> showStatus %uptime%,%qcache%
# Only readings containing "uptime" and "qcache" in name will be created
- dbvars - lists global informations about MySQL system variables. Included are e.g. readings related to InnoDB-Home, datafile path,
memory- or cache-parameter and so on. The Output reports initially all available informations. Using the
attribute "showVariables" the quantity of results can be limited to show only the desired values.
Further detailed informations of items meaning are explained
there.
Example
get <name> dbvars
attr <name> showVariables %version%,%query_cache%
# Only readings containing "version" and "query_cache" in name will be created
- procinfo - reports the existing database processes in a summary table (only MySQL).
Typically only the own processes of the connection user (set in DbLog configuration file) will be
reported. If all precesses have to be reported, the global "PROCESS" right has to be granted to the
user.
As of MariaDB 5.3 for particular SQL-Statements a progress reporting will be provided
(table row "PROGRESS"). So you can track, for instance, the degree of processing during an index
creation.
Further informations can be found
there.
- svrinfo - common database server informations, e.g. DBMS-version, server address and port and so on. The quantity of elements to get depends
on the database type. Using the attribute "showSvrInfo" the quantity of results can be limited to show only
the desired values. Further detailed informations of items meaning are explained
there.
Example
get <name> svrinfo
attr <name> showSvrInfo %SQL_CATALOG_TERM%,%NAME%
# Only readings containing "SQL_CATALOG_TERM" and "NAME" in name will be created
tableinfo - access detailed informations about tables in MySQL database which is connected by the DbRep-device.
All available tables in the connected database will be selected by default.
Using theattribute "showTableInfo" the results can be limited to tables you want to show.
Further detailed informations of items meaning are explained there.
Example
get <name> tableinfo
attr <name> showTableInfo current,history
# Only informations related to tables "current" and "history" are going to be created
Attributes
Using the module specific attributes you are able to define the scope of evaluation and the aggregation.
Note for SQL-Wildcard Usage:
Within the attribute values of "device" and "reading" you may use SQL-Wildcard "%", Character "_" is not supported as a wildcard.
The character "%" stands for any characters.
This rule is valid to all functions except "insert", "importFromFile" and "deviceRename".
The function "insert" doesn't allow setting the mentioned attributes containing the wildcard "%".
In readings the wildcard character "%" will be replaced by "/" to meet the rules of allowed characters in readings.
- aggregation - Aggregation of Device/Reading-selections. Possible is hour, day, week, month or "no".
Delivers e.g. the count of database entries for a day (countEntries), Summation of
difference values of a reading (sumValue) and so on. Using aggregation "no" (default) an
aggregation don't happens but the output contaims all values of Device/Reading in the defined time period.
- allowDeletion - unlocks the delete-function
- device - Selection of a particular device.
You can specify device specifications (devspec).
Inside of device specifications a SQL wildcard (%) will be evaluated as a normal ASCII-character.
The device names are derived from device specification and the active devices in FHEM before
SQL selection will be carried out.
Examples:
attr <Name> device TYPE=DbRep
# select datasets of active present devices with Type "DbRep"
attr <Name> device MySTP_5000
# select datasets of device "MySTP_5000"
attr <Name> device SMA.*
# select datasets of devices starting with "SMA"
attr <Name> device SMA_Energymeter,MySTP_5000
# select datasets of devices "SMA_Energymeter" and "MySTP_5000"
attr <Name> device %5000
# select datasets of devices ending with "5000"
- diffAccept - valid for function diffValue. diffAccept determines the threshold, up to that a calaculated difference between two
straight sequently datasets should be commenly accepted (default = 20).
Hence faulty DB entries with a disproportional high difference value will be eliminated and don't tamper the result.
If a threshold overrun happens, the reading "diff_overrun_limit_<diffLimit>" will be generated
(<diffLimit> will be substituted with the present prest attribute value).
The reading contains a list of relevant pair of values. Using verbose=3 this list will also be reported in the FHEM
logfile.
Example report in logfile if threshold of diffAccept=10 overruns:
DbRep Rep.STP5000.etotal -> data ignored while calc diffValue due to threshold overrun (diffAccept = 10):
2016-04-09 08:50:50 0.0340 -> 2016-04-09 12:42:01 13.3440
# The first dataset with a value of 0.0340 is untypical low compared to the next value of 13.3440 and results a untypical
high difference value.
# Now you have to decide if the (second) dataset should be deleted, ignored of the attribute diffAccept should be adjusted.
- disable - deactivates the module
- dumpComment - User-comment. It will be included in the header of the created dumpfile by
command "dumpMySQL clientSide".
- dumpDirLocal - Target directory of database dumps by command "dumpMySQL clientSide"
(default: "{global}{modpath}/log/" on the FHEM-Server).
In this directory also the internal version administration searches for old backup-files
and deletes them if the number exceeds attribute "dumpFilesKeep".
The attribute is also relevant to publish a local mounted directory "dumpDirRemote" to
DbRep.
- dumpDirRemote - Target directory of database dumps by command "dumpMySQL serverSide"
(default: the Home-directory of MySQL-Server on the MySQL-Host).
- dumpMemlimit - tolerable memory consumption for the SQL-script during generation period (default: 100000 characters).
Please adjust this parameter if you may notice memory bottlenecks and performance problems based
on it on your specific hardware.
- dumpSpeed - Number of Lines which will be selected in source database with one select by dump-command
"dumpMySQL ClientSide" (default: 10000).
This parameter impacts the run-time and consumption of resources directly.
- dumpFilesKeep - The specified number of dumpfiles remain in the dump directory (default: 3).
If there more (older) files has been found, these files will be deleted after a new database dump
was created successfully.
The global attrubute "archivesort" will be considered.
- executeAfterProc - you can specify a FHEM-command which should be executed after dump.
Perl functions have to be enclosed in {} .
Example:
attr <DbRep-device> executeAfterProc set og_gz_westfenster off;
attr <DbRep-device> executeAfterProc {adump ("<DbRep-device>")}
# "adump" is a function defined in 99_myUtils.pm e.g.:
sub adump {
my ($name) = @_;
my $hash = $defs{$name};
# own function, e.g.
Log3($name, 3, "DbRep $name -> Dump finished");
return;
}
- executeBeforeProc - you can specify a FHEM-command which should be executed before dump.
Perl functions have to be enclosed in {} .
Example:
attr <DbRep-device> executeBeforeProc set og_gz_westfenster on;
attr <DbRep-device> executeBeforeProc {bdump ("<DbRep-device>")}
# "bdump" is a function defined in 99_myUtils.pm e.g.:
sub bdump {
my ($name) = @_;
my $hash = $defs{$name};
# own function, e.g.
Log3($name, 3, "DbRep $name -> Dump starts now");
return;
}
- expimpfile - Path/filename for data export/import
- fetchRoute [descent | ascent] - specify the direction of data selection of the fetchrows-command.
descent - the data are read descent (default). If
amount of datasets specified by attribut "limit" is exceeded,
the newest x datasets are shown.
ascent - the data are read ascent . If
amount of datasets specified by attribut "limit" is exceeded,
the oldest x datasets are shown.
- ftpUse - FTP Transfer after dump will be switched on (without SSL encoding). The created
database backup file will be transfered non-blocking to the FTP-Server (Attribut "ftpServer").
- ftpUseSSL - FTP Transfer with SSL encoding after dump. The created database backup file will be transfered
non-blocking to the FTP-Server (Attribut "ftpServer").
- ftpUser - User for FTP-server login, default: "anonymous".
- ftpDebug - debugging of FTP communication for diagnostics.
- ftpDir - directory on FTP-server in which the file will be send into (default: "/").
- ftpPassive - set if passive FTP is to be used
- ftpPort - FTP-Port, default: 21
- ftpPwd - password of FTP-User, is not set by default
- ftpServer - name or IP-address of FTP-server. absolutely essential !
- ftpTimeout - timeout of FTP-connection in seconds (default: 30).
- limit - limits the number of selected datasets by the "fetchrows", or the shown datasets of "delSeqDoublets adviceDelete",
"delSeqDoublets adviceRemain" commands (default: 1000).
This limitation should prevent the browser session from overload and
avoids FHEMWEB from blocking. Please change the attribut according your requirements or change the
selection criteria (decrease evaluation period).
- optimizeTablesBeforeDump - if set to "1", the database tables will be optimized before executing the dump
(default: 0).
Thereby the backup run-time time will be extended.
Note
The table optimizing cause locking the tables and therefore to blocking of
FHEM if DbLog isn't working in asynchronous mode (DbLog-attribute "asyncMode") !
- reading - Selection of a particular reading.
More than one reading are specified as a comma separated list.
If SQL wildcard (%) is set in a list, it will be evaluated as a normal ASCII-character.
Examples:
attr <Name> reading etotal
attr <Name> reading et%
attr <Name> reading etotal,etoday
- readingNameMap - the name of the analyzed reading can be overwritten for output
- role - the role of the DbRep-device. Standard role is "Client". The role "Agent" is described
in section DbRep-Agent.
- readingPreventFromDel - comma separated list of readings which are should prevent from deletion when a
new operation starts
- seqDoubletsVariance - accepted variance (+/-) for the command "set <Name> delSeqDoublets".
The value of this attribute describes the variance up to it consecutive numeric values (VALUE) of
datasets are handled as identical and should be deleted. "seqDoubletsVariance" is an absolut numerical value,
which is used as a positive as well as a negative variance.
Examples:
attr <Name> seqDoubletsVariance 0.0014
attr <Name> seqDoubletsVariance 1.45
- showproctime - if set, the reading "sql_processing_time" shows the required execution time (in seconds)
for the sql-requests. This is not calculated for a single sql-statement, but the summary
of all sql-statements necessara for within an executed DbRep-function in background.
- showStatus - limits the sample space of command "get ... dbstatus". SQL-Wildcard (%) can be used.
Example: attr ... showStatus %uptime%,%qcache%
# Only readings with containing "uptime" and "qcache" in name will be shown
- showVariables - limits the sample space of command "get ... dbvars". SQL-Wildcard (%) can be used.
Example: attr ... showVariables %version%,%query_cache%
# Only readings with containing "version" and "query_cache" in name will be shown
- showSvrInfo - limits the sample space of command "get ... svrinfo". SQL-Wildcard (%) can be used.
Example: attr ... showSvrInfo %SQL_CATALOG_TERM%,%NAME%
# Only readings with containing "SQL_CATALOG_TERM" and "NAME" in name will be shown
- showTableInfo - limits the tablename which is selected by command "get ... tableinfo". SQL-Wildcard
(%) can be used.
Example: attr ... showTableInfo current,history
# Only informations about tables "current" and "history" will be shown
- sqlResultFieldSep - determines the used field separator (default: "|") in the result of command "set ... sqlCmd".
- sqlResultFormat - determines the formatting of the "set ... sqlCmd" command result. possible options are:
separated - every line of the result will be generated sequentially in a single
reading. (default)
mline - the result will be generated as multiline in
Reading SqlResult.
sline - the result will be generated as singleline in
Reading SqlResult.
Datasets are separated by "]|[".
table - the result will be generated as an table in
Reading SqlResult.
json - creates Reading SqlResult as a JSON
coded hash.
Every hash-element consists of the serial number of the dataset (key)
and its value.
To process the result, you may use a userExitFn in 99_myUtils for example:
sub resfromjson {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
if ($reading eq "SqlResult") {
# only reading SqlResult contains JSON encoded data
my $data = decode_json($value);
foreach my $k (keys(%$data)) {
# use your own processing from here for every hash-element
# e.g. output of every element that contains "Cam"
my $ke = $data->{$k};
if($ke =~ m/Cam/i) {
my ($res1,$res2) = split("\\|", $ke);
Log3($name, 1, "$name - extract element $k by userExitFn: ".$res1." ".$res2);
}
}
}
return;
}
timeYearPeriod - Get by this attribute an annual time period will be determined for database data selection.
The time limits are calculated dynamically during execution time. Every time an annual period is determined.
Periods of less than a year are not possible to set.
This attribute is particularly intended to make reports synchronous to an account period, e.g. of an energy- or gas provider.
Example:
attr <DbRep-device> timeYearPeriod 06-25 06-24
# evaluates the database within the time limits 25. june AAAA and 24. june BBBB.
# The year AAAA respectively year BBBB is calculated dynamically depending of the current date.
# If the current date >= 25. june and =< 31. december, than AAAA = current year and BBBB = current year+1
# If the current date >= 01. january und =< 24. june, than AAAA = current year-1 and BBBB = current year
timestamp_begin - begin of data selection (*)
timestamp_end - end of data selection. If not set the current date/time combination will be used. (*)
(*) The format of timestamp is as used with DbLog "YYYY-MM-DD HH:MM:SS". For the attributes "timestamp_begin", "timestamp_end"
you can also use one of the following entries. The timestamp-attribute will be dynamically set to:
current_year_begin : matches "<current year>-01-01 00:00:00"
current_year_end : matches "<current year>-12-31 23:59:59"
previous_year_begin : matches "<previous year>-01-01 00:00:00"
previous_year_end : matches "<previous year>-12-31 23:59:59"
current_month_begin : matches "<current month first day> 00:00:00"
current_month_end : matches "<current month last day> 23:59:59"
previous_month_begin : matches "<previous month first day> 00:00:00"
previous_month_end : matches "<previous month last day> 23:59:59"
current_week_begin : matches "<first day of current week> 00:00:00"
current_week_end : matches "<last day of current week> 23:59:59"
previous_week_begin : matches "<first day of previous week> 00:00:00"
previous_week_end : matches "<last day of previous week> 23:59:59"
current_day_begin : matches "<current day> 00:00:00"
current_day_end : matches "<current day> 23:59:59"
previous_day_begin : matches "<previous day> 00:00:00"
previous_day_end : matches "<previous day> 23:59:59"
current_hour_begin : matches "<current hour>:00:00"
current_hour_end : matches "<current hour>:59:59"
previous_hour_begin : matches "<previous hour>:00:00"
previous_hour_end : matches "<previous hour>:59:59"
Make sure that "timestamp_begin" < "timestamp_end" is fulfilled.
Example:
attr <DbRep-device> timestamp_begin current_year_begin
attr <DbRep-device> timestamp_end current_year_end
# Analyzes the database between the time limits of the current year.
Note
If the attribute "timeDiffToNow" will be set, the attributes "timestamp_begin" respectively "timestamp_end" will be deleted if they were set before.
The setting of "timestamp_begin" respectively "timestamp_end" causes the deletion of attribute "timeDiffToNow" if it was set before as well.
timeDiffToNow - the begin of data selection will be set to the timestamp "<current time> -
<timeDiffToNow>" dynamically (e.g. if set to 86400, the last 24 hours are considered by data
selection). The time period will be calculated dynamically at execution time.
Examples for input format:
attr <Name> timeDiffToNow 86400
# the start time is set to "current time - 86400 seconds"
attr <Name> timeDiffToNow d:2 h:3 m:2 s:10
# the start time is set to "current time - 2 days 3 hours 2 minutes 10 seconds"
attr <Name> timeDiffToNow m:600
# the start time is set to "current time - 600 minutes" gesetzt
attr <Name> timeDiffToNow h:2.5
# the start time is set to "current time - 2,5 hours"
timeOlderThan - the end of data selection will be set to the timestamp "<aktuelle Zeit> -
<timeOlderThan>" dynamically. Always the datasets up to timestamp
"<current time> - <timeOlderThan>" will be considered (e.g. if set to
86400, all datasets older than one day are considered). The time period will be calculated dynamically at
execution time.
The valid input format for attribute "timeOlderThan" is identical to attribute "timeDiffToNow".
timeout - set the timeout-value for Blocking-Call Routines in background in seconds (default 86400)
userExitFn - provides an interface to execute user specific program code.
To activate the interfaace at first you should implement the subroutine which will be
called by the interface in your 99_myUtls.pm as shown in by the example:
sub UserFunction {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
...
# e.g. output transfered data
Log3 $name, 1, "UserExitFn $name called - transfer parameter are Reading: $reading, Value: $value " ;
...
return;
}
The interface activation takes place by setting the subroutine name in the attribute.
Optional you may set a Reading:Value combination (Regex) as argument. If no Regex is
specified, all value combinations will be evaluated as "true" (related to .*:.*).
Example:
attr userExitFn UserFunction .*:.*
# "UserFunction" is the name of subroutine in 99_myUtils.pm.
The interface works generally without and independent from Events.
If the attribute is set, after every reading generation the Regex will be evaluated.
If the evaluation was "true", set subroutine will be called.
For further processing following parameters will be forwarded to the function:
- $name - the name of the DbRep-Device
- $reading - the name of the created reading
- $value - the value of the reading
Readings
Regarding to the selected operation the reasults will be shown as readings. At the beginning of a new operation all old readings will be deleted to avoid
that unsuitable or invalid readings would remain.
In addition the following readings will be created:
- state - contains the current state of evaluation. If warnings are occured (state = Warning) compare Readings
"diff_overrun_limit_<diffLimit>" and "less_data_in_period"
- errortext - description about the reason of an error state
- background_processing_time - the processing time spent for operations in background/forked operation
- sql_processing_time - the processing time wasted for all sql-statements used for an operation
- diff_overrun_limit_<diffLimit> - contains a list of pairs of datasets which have overrun the threshold (<diffLimit>)
of calculated difference each other determined by attribute "diffAccept" (default=20).
- less_data_in_period - contains a list of time periods within only one dataset was found. The difference calculation considers
the last value of the aggregation period before the current one. Valid for function "diffValue".
- SqlResult - result of the last executed sqlCmd-command. The formatting can be specified
by attribute "sqlResultFormat"
- sqlCmd - contains the last executed sqlCmd-command
DbRep Agent - automatic change of device names in databases and DbRep-definitions after FHEM "rename" command
By the attribute "role" the role of DbRep-device will be configured. The standard role is "Client". If the role has changed to "Agent", the DbRep device
react automatically on renaming devices in your FHEM installation. The DbRep device is now called DbRep-Agent.
By the DbRep-Agent the following features are activated when a FHEM-device has being renamed:
- in the database connected to the DbRep-Agent (Internal Database) dataset containing the old device name will be searched and renamed to the
to the new device name in all affected datasets.
- in the DbLog-Device assigned to the DbRep-Agent the definition will be changed to substitute the old device name by the new one. Thereby the logging of
the renamed device will be going on in the database.
- in other existing DbRep-definitions with Type "Client" a possibly set attribute "device = old device name" will be changed to "device = new device name".
Because of that, reporting definitions will be kept consistent automatically if devices are renamed in FHEM.
The following restrictions take place if a DbRep device was changed to an Agent by setting attribute "role" to "Agent". These conditions will be activated
and checked:
- within a FHEM installation only one DbRep-Agent can be configured for every defined DbLog-database. That means, if more than one DbLog-database is present,
you could define same numbers of DbRep-Agents as well as DbLog-devices are defined.
- after changing to DbRep-Agent role only the set-command "renameDevice" will be available and as well as a reduced set of module specific attributes will be
permitted. If a DbRep-device of privious type "Client" has changed an Agent, furthermore not permitted attributes will be deleted if set.
All activities like database changes and changes of other DbRep-definitions will be logged in FHEM Logfile with verbose=3. In order that the renameDevice
function don't running into timeout set the timeout attribute to an appropriate value, especially if there are databases with huge datasets to evaluate.
As well as all the other database operations of this module, the autorename operation will be executed nonblocking.
Example of definition of a DbRep-device as an Agent:
define Rep.Agent DbRep LogDB
attr Rep.Agent devStateIcon connected:10px-kreis-gelb .*disconnect:10px-kreis-rot .*done:10px-kreis-gruen
attr Rep.Agent icon security
attr Rep.Agent role Agent
attr Rep.Agent room DbLog
attr Rep.Agent showproctime 1
attr Rep.Agent stateFormat { ReadingsVal("$name","state", undef) eq "running" ? "renaming" : ReadingsVal("$name","state", undef). " »; ProcTime: ".ReadingsVal("$name","sql_processing_time", undef)." sec"}
attr Rep.Agent timeout 86400
Note:
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
is operating in asynchronous mode to avoid FHEMWEB from blocking.
=end html
=begin html_DE
DbRep
Zweck des Moduls ist es, den Inhalt von DbLog-Datenbanken nach bestimmten Kriterien zu durchsuchen, zu managen, das Ergebnis hinsichtlich verschiedener
Aggregationen auszuwerten und als Readings darzustellen. Die Abgrenzung der zu berücksichtigenden Datenbankinhalte erfolgt durch die Angabe von Device, Reading und
die Zeitgrenzen für Auswertungsbeginn bzw. Auswertungsende.
Alle Datenbankoperationen werden nichtblockierend ausgeführt. Die Ausführungszeit der (SQL)-Hintergrundoperationen kann optional ebenfalls als Reading bereitgestellt
werden (siehe Attribute).
Alle vorhandenen Readings werden vor einer neuen Operation gelöscht. Durch das Attribut "readingPreventFromDel" kann eine Komma separierte Liste von Readings
angegeben werden die nicht gelöscht werden sollen.
Aktuell werden folgende Operationen unterstützt:
- Selektion aller Datensätze innerhalb einstellbarer Zeitgrenzen.
- Darstellung der Datensätze einer Device/Reading-Kombination innerhalb einstellbarer Zeitgrenzen.
- Selektion der Datensätze unter Verwendung von dynamisch berechneter Zeitgrenzen zum Ausführungszeitpunkt.
- Berechnung der Anzahl von Datensätzen einer Device/Reading-Kombination unter Berücksichtigung von Zeitgrenzen
und verschiedenen Aggregationen.
- Die Berechnung von Summen-, Differenz-, Maximum-, Minimum- und Durchschnittswerten numerischer Readings
in Zeitgrenzen und verschiedenen Aggregationen.
- Speichern von Summen-, Differenz- , Maximum- , Minimum- und Durchschnittswertberechnungen in der Datenbank
- Löschung von Datensätzen. Die Eingrenzung der Löschung kann durch Device und/oder Reading sowie fixer oder
dynamisch berechneter Zeitgrenzen zum Ausführungszeitpunkt erfolgen.
- Export von Datensätzen in ein File im CSV-Format
- Import von Datensätzen aus File im CSV-Format
- Umbenennen von Device-Namen in Datenbanksätzen
- automatisches Umbenennen von Device-Namen in Datenbanksätzen und DbRep-Definitionen nach FHEM "rename"
Befehl (siehe DbRep-Agent)
- Ausführen von beliebigen Benutzer spezifischen SQL-Kommandos
- Backups der FHEM-Datenbank im laufenden Betrieb erstellen (MySQL, SQLite)
- senden des Dumpfiles zu einem FTP-Server nach dem Backup
- Restore von SQLite-Dumps und MySQL serverSide-Backups
- Optimierung der angeschlossenen Datenbank (optimizeTables, vacuum)
- Ausgabe der existierenden Datenbankprozesse (MySQL)
- leeren der current-Tabelle
- Auffüllen der current-Tabelle mit einem (einstellbaren) Extrakt der history-Tabelle
- Bereinigung sequentiell aufeinander folgender Datensätze (sequentielle Dublettenbereinigung)
Zur Aktivierung der Funktion "Autorename" wird dem definierten DbRep-Device mit dem Attribut "role" die Rolle "Agent" zugewiesen. Die Standardrolle nach Definition
ist "Client". Mehr ist dazu im Abschnitt DbRep-Agent beschrieben.
DbRep stellt dem Nutzer einen UserExit zur Verfügung. Über diese Schnittstelle kann der Nutzer in Abhängigkeit von
frei definierbaren Reading/Value-Kombinationen (Regex) eigenen Code zur Ausführung bringen. Diese Schnittstelle arbeitet
unabhängig von einer Eventgenerierung. Weitere Informationen dazu ist unter Attribut
"userExitFn" beschrieben.
FHEM-Forum:
Modul 93_DbRep - Reporting und Management von Datenbankinhalten (DbLog).
Voraussetzungen
Das Modul setzt den Einsatz einer oder mehrerer DbLog-Instanzen voraus. Es werden die Zugangsdaten dieser
Datenbankdefinition genutzt.
Es werden nur Inhalte der Tabelle "history" berücksichtigt wenn nichts anderes beschrieben ist.
Überblick welche anderen Perl-Module DbRep verwendet:
Net::FTP (nur wenn FTP-Transfer nach Datenbank-Dump genutzt wird)
Net::FTPSSL (nur wenn FTP-Transfer mit Verschlüsselung nach Datenbank-Dump genutzt wird)
POSIX
Time::HiRes
Time::Local
Scalar::Util
DBI
Blocking (FHEM-Modul)
Aus Performancegründen sollten zusätzlich folgender Index erstellt werden:
CREATE INDEX Report_Idx ON `history` (TIMESTAMP, READING) USING BTREE;
Definition
define <name> DbRep <Name der DbLog-Instanz>
(<Name der DbLog-Instanz> - es wird der Name der auszuwertenden DBLog-Datenbankdefinition angegeben nicht der Datenbankname selbst)
Set
Zur Zeit gibt es folgende Set-Kommandos. Über sie werden die Auswertungen angestoßen und definieren selbst die Auswertungsvariante.
Nach welchen Kriterien die Datenbankinhalte durchsucht werden und die Aggregation erfolgt, wird durch Attribute gesteuert.
- averageValue [display | writeToDB]
- berechnet den Durchschnittswert der Readingwerte (DB-Spalte "VALUE") in den gegebenen
Zeitgrenzen ( siehe Attribute).
Es muss das auszuwertende Reading über das Attribut "reading"
angegeben sein.
Ist keine oder die Option "display" angegeben, werden die Ergebnisse nur angezeigt. Mit
der Option "writeToDB" werden die Berechnungsergebnisse mit einem neuen Readingnamen
in der Datenbank gespeichert.
Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet.
Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
Der Timestamp der neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode
abgeleitet, sofern kein eindeutiger Zeitpunkt des Ergebnisses bestimmt werden kann.
Das Feld "EVENT" wird mit "calculated" gefüllt.
Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
avg_day_totalpac
# <Bildungsfunktion>_<Aggregation>_<Originalreading>
- cancelDump - bricht einen laufenden Datenbankdump ab.
- countEntries [history | current]
- liefert die Anzahl der Tabelleneinträge (default: history) in den gegebenen
Zeitgrenzen (siehe Attribute).
Sind die Timestamps nicht gesetzt werden alle Einträge gezählt.
Beschränkungen durch die Attribute Device bzw. Reading
gehen in die Selektion mit ein.
- delEntries - löscht alle oder die durch die Attribute device und/oder
reading definierten Datenbankeinträge. Die Eingrenzung über Timestamps erfolgt
folgendermaßen:
"timestamp_begin" gesetzt: gelöscht werden DB-Einträge ab diesem Zeitpunkt bis zum aktuellen Datum/Zeit
"timestamp_end" gesetzt : gelöscht werden DB-Einträge bis bis zu diesem Zeitpunkt
beide Timestamps gesetzt : gelöscht werden DB-Einträge zwischen diesen Zeitpunkten
Aus Sicherheitsgründen muss das Attribut "allowDeletion"
gesetzt sein um die Löschfunktion freizuschalten.
- delSeqDoublets [adviceRemain | adviceDelete | delete] - zeigt bzw. löscht aufeinander folgende identische Datensätze.
Dazu wird Device,Reading und Value ausgewertet. Nicht gelöscht werden der erste und der letzte Datensatz
einer Aggregationsperiode (z.B. hour, day, week usw.) sowie die Datensätze vor oder nach einem Wertewechsel
(Datenbankfeld VALUE).
Die Attribute zur Aggregation,Zeit-,Device- und Reading-Abgrenzung werden dabei
berücksichtigt. Ist das Attribut "aggregation" nicht oder auf "no" gesetzt, wird als Standard die Aggregation
"day" verwendet. Für Datensätze mit numerischen Werten kann mit dem Attribut
"seqDoubletsVariance" eine Abweichung eingestellt werden, bis zu der aufeinander folgende numerische Werte als
identisch angesehen und gelöscht werden sollen.
adviceRemain | : simuliert die nach der Operation in der DB verbleibenden Datensätze (es wird nichts gelöscht !) |
adviceDelete | : simuliert die zu löschenden Datensätze (es wird nichts gelöscht !) |
delete | : löscht die sequentiellen Dubletten (siehe Beispiel) |
Aus Sicherheitsgründen muss das Attribut "allowDeletion" für die "delete" Option
gesetzt sein.
Die Anzahl der anzuzeigenden Datensätze der Kommandos "delSeqDoublets adviceDelete", "delSeqDoublets adviceRemain" ist
zunächst begrenzt (default 1000) und kann durch das Attribut "limit" angepasst werden.
Die Einstellung von "limit" hat keinen Einfluss auf die "delSeqDoublets delete" Funktion, sondern beeinflusst NUR die
Anzeige der Daten.
Beispiel - die nach Verwendung der delete-Option in der DB verbleibenden Datensätze sind fett
gekennzeichnet:
2017-11-25_00-00-05__eg.az.fridge_Pwr__power 0
2017-11-25_00-02-26__eg.az.fridge_Pwr__power 0
2017-11-25_00-04-33__eg.az.fridge_Pwr__power 0
2017-11-25_01-06-10__eg.az.fridge_Pwr__power 0
2017-11-25_01-08-21__eg.az.fridge_Pwr__power 0
2017-11-25_01-08-59__eg.az.fridge_Pwr__power 60.32
2017-11-25_01-11-21__eg.az.fridge_Pwr__power 56.26
2017-11-25_01-27-54__eg.az.fridge_Pwr__power 6.19
2017-11-25_01-28-51__eg.az.fridge_Pwr__power 0
2017-11-25_01-31-00__eg.az.fridge_Pwr__power 0
2017-11-25_01-33-59__eg.az.fridge_Pwr__power 0
2017-11-25_02-39-29__eg.az.fridge_Pwr__power 0
2017-11-25_02-41-18__eg.az.fridge_Pwr__power 105.28
2017-11-25_02-41-26__eg.az.fridge_Pwr__power 61.52
2017-11-25_03-00-06__eg.az.fridge_Pwr__power 47.46
2017-11-25_03-00-33__eg.az.fridge_Pwr__power 0
2017-11-25_03-02-07__eg.az.fridge_Pwr__power 0
2017-11-25_23-37-42__eg.az.fridge_Pwr__power 0
2017-11-25_23-40-10__eg.az.fridge_Pwr__power 0
2017-11-25_23-42-24__eg.az.fridge_Pwr__power 1
2017-11-25_23-42-24__eg.az.fridge_Pwr__power 1
2017-11-25_23-45-27__eg.az.fridge_Pwr__power 1
2017-11-25_23-47-07__eg.az.fridge_Pwr__power 0
2017-11-25_23-55-27__eg.az.fridge_Pwr__power 0
2017-11-25_23-48-15__eg.az.fridge_Pwr__power 0
2017-11-25_23-50-21__eg.az.fridge_Pwr__power 59.1
2017-11-25_23-55-14__eg.az.fridge_Pwr__power 52.31
2017-11-25_23-58-09__eg.az.fridge_Pwr__power 51.73
- deviceRename - benennt den Namen eines Device innerhalb der angeschlossenen Datenbank (Internal
DATABASE) um.
Der Gerätename wird immer in der gesamten Datenbank umgesetzt. Eventuell gesetzte
Zeitgrenzen oder Beschränkungen durch die Attribute Device bzw.
Reading werden nicht berücksichtigt.
Eingabeformat: set <name> deviceRename <alter Devicename>,<neuer Devicename>
# Die Anzahl der umbenannten Device-Datensätze wird im Reading "device_renamed" ausgegeben.
# Wird der umzubenennende Gerätename in der Datenbank nicht gefunden, wird eine WARNUNG im Reading "device_not_renamed" ausgegeben.
# Entsprechende Einträge erfolgen auch im Logfile mit verbose=3
Hinweis:
Obwohl die Funktion selbst non-blocking ausgelegt ist, sollte das zugeordnete DbLog-Device
im asynchronen Modus betrieben werden um ein Blockieren von FHEMWEB zu vermeiden (Tabellen-Lock).
diffValue [display | writeToDB]
- berechnet den Differenzwert eines Readingwertes (DB-Spalte "Value") in den Zeitgrenzen (Attribute) "timestamp_begin", "timestamp_end" bzw "timeDiffToNow / timeOlderThan".
Es muss das auszuwertende Reading im Attribut "reading" angegeben sein.
Diese Funktion ist z.B. zur Auswertung von Eventloggings sinnvoll, deren Werte sich fortlaufend erhöhen und keine Wertdifferenzen wegschreiben.
Es wird immer die Differenz aus dem Value-Wert des ersten verfügbaren Datensatzes und dem Value-Wert des letzten verfügbaren Datensatzes innerhalb der angegebenen
Zeitgrenzen/Aggregation gebildet, wobei ein Übertragswert der Vorperiode (Aggregation) zur darauf folgenden Aggregationsperiode
berücksichtigt wird sofern diese einen Value-Wert enhtält.
Dabei wird ein Zählerüberlauf (Neubeginn bei 0) mit berücksichtigt (vergleiche Attribut "diffAccept").
Wird in einer auszuwertenden Zeit- bzw. Aggregationsperiode nur ein Datensatz gefunden, kann die Differenz in Verbindung mit dem
Differenzübertrag der Vorperiode berechnet werden. in diesem Fall kann es zu einer logischen Ungenauigkeit in der Zuordnung der Differenz
zu der Aggregationsperiode kommen. Deswegen wird eine Warnung im "state" und das
Reading "less_data_in_period" mit einer Liste der betroffenen Perioden wird erzeugt.
Hinweis:
Im Auswertungs- bzw. Aggregationszeitraum (Tag, Woche, Monat, etc.) sollten dem Modul pro Periode mindestens ein Datensatz
zu Beginn und ein Datensatz gegen Ende des Aggregationszeitraumes zur Verfügung stehen um eine möglichst genaue Auswertung
der Differenzwerte vornehmen zu können.
Ist keine oder die Option "display" angegeben, werden die Ergebnisse nur angezeigt. Mit
der Option "writeToDB" werden die Berechnungsergebnisse mit einem neuen Readingnamen
in der Datenbank gespeichert.
Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet.
Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
Der Timestamp der neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode
abgeleitet, sofern kein eindeutiger Zeitpunkt des Ergebnisses bestimmt werden kann.
Das Feld "EVENT" wird mit "calculated" gefüllt.
Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
diff_day_totalpac
# <Bildungsfunktion>_<Aggregation>_<Originalreading>
dumpMySQL [clientSide | serverSide]
- erstellt einen Dump der angeschlossenen MySQL-Datenbank.
Abhängig von der ausgewählten Option wird der Dump auf der Client- bzw. Serverseite erstellt.
Die Varianten unterscheiden sich hinsichtlich des ausführenden Systems, des Erstellungsortes, der
Attributverwendung, des erzielten Ergebnisses und der benötigten Hardwareressourcen.
Die Option "clientSide" benötigt z.B. eine leistungsfähigere Hardware des FHEM-Servers, sichert aber alle
Tabellen inklusive eventuell angelegter Views.
Option clientSide
Der Dump wird durch den Client (FHEM-Rechner) erstellt und per default im log-Verzeichnis des Clients
gespeichert.
Das Zielverzeichnis kann mit dem Attribut "dumpDirLocal" verändert werden und muß auf
dem Client durch FHEM beschreibbar sein.
Vor dem Dump kann eine Tabellenoptimierung (Attribut "optimizeTablesBeforeDump") oder ein FHEM-Kommando
(Attribut "executeBeforeProc") optional zugeschaltet werden.
Achtung !
Um ein Blockieren von FHEM zu vermeiden, muß DbLog im asynchronen Modus betrieben werden wenn die
Tabellenoptimierung verwendet wird !
Nach dem Dump kann ebenfalls ein FHEM-Kommando (siehe Attribut "executeAfterProc") ausgeführt werden.
Über die Attribute "dumpMemlimit" und "dumpSpeed" kann das Laufzeitverhalten der
Funktion beeinflusst werden um eine Optimierung bezüglich Performance und Ressourcenbedarf zu erreichen.
Die für "dumpMySQL clientSide" relevanten Attribute sind "dumpComment", "dumpDirLocal", "dumpMemlimit",
"dumpSpeed ", "dumpFilesKeep", "executeBeforeProc", "executeAfterProc" und "optimizeTablesBeforeDump".
Nach einem erfolgreichen Dump werden alte Dumpfiles gelöscht und nur die Anzahl Files definiert durch
das Attribut "dumpFilesKeep" (default: 3) verbleibt im Zielverzeichnis "dumpDirLocal".
Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sql
Das erzeugte Dumpfile kann z.B. mit:
mysql -u <user> -p <dbname> < <filename>.sql
auf dem MySQL-Server ausgeführt werden um die Datenbank aus dem Dump wiederherzustellen.
Option serverSide
Der Dump wird durch den MySQL-Server erstellt und per default im Home-Verzeichnis des MySQL-Servers
gespeichert.
Es wird die gesamte history-Tabelle (nicht current-Tabelle) im CSV-Format ohne
Einschränkungen exportiert.
Vor dem Dump kann eine Tabellenoptimierung (Attribut "optimizeTablesBeforeDump")
optional zugeschaltet werden .
Achtung !
Um ein Blockieren von FHEM zu vermeiden, muß DbLog im asynchronen Modus betrieben werden wenn die
Tabellenoptimierung verwendet wird !
Vor und nach dem Dump kann ein FHEM-Kommando (siehe Attribute "executeBeforeProc", "executeAfterProc") ausgeführt
werden.
Die für "dumpMySQL serverSide" relevanten Attribute sind "dumpDirRemote", "dumpDirLocal",
"dumpFilesKeep", "optimizeTablesBeforeDump", "executeBeforeProc" und "executeAfterProc".
Das Zielverzeichnis kann mit dem Attribut "dumpDirRemote" verändert werden.
Es muß sich auf dem MySQL-Host gefinden und durch den MySQL-Serverprozess beschreibbar sein.
Der verwendete Datenbankuser benötigt das "FILE"-Privileg.
Hinweis:
Soll die interne Versionsverwaltung des Moduls genutzt und die Größe des erzeugten Dumpfiles
ausgegeben werden, ist das Verzeichnis "dumpDirRemote" des MySQL-Servers auf dem Client zu mounten
und im Attribut "dumpDirLocal" dem DbRep-Device bekannt zu machen.
Gleiches gilt wenn der FTP-Transfer nach dem Dump genutzt werden soll (Attribut "ftpUse" bzw. "ftpUseSSL").
Beispiel:
attr <DbRep-device> dumpDirRemote /volume1/ApplicationBackup/dumps_FHEM/
attr <DbRep-device> dumpDirLocal /sds1/backup/dumps_FHEM/
attr <DbRep-device> dumpFilesKeep 2
# Der Dump wird remote auf dem MySQL-Server im Verzeichnis '/volume1/ApplicationBackup/dumps_FHEM/'
erstellt.
# Die interne Versionsverwaltung sucht im lokal gemounteten Verzeichnis '/sds1/backup/dumps_FHEM/'
vorhandene Dumpfiles und löscht diese bis auf die zwei letzten Versionen.
Wird die interne Versionsverwaltung genutzt, werden nach einem erfolgreichen Dump alte Dumpfiles gelöscht
und nur die Anzahl "dumpFilesKeep" (default: 3) verbleibt im Zielverzeichnis "dumpDirRemote".
FHEM benötigt in diesem Fall Schreibrechte auf dem Verzeichnis "dumpDirLocal".
Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.csv
Ein Restore der Datenbank aus diesem Backup kann durch den Befehl:
set <name> <restoreMySQL> <filename>.csv
gestartet werden.
FTP Transfer nach Dump
Wenn diese Möglichkeit genutzt werden soll, ist das Attribut "ftpUse" oder
"ftpUseSSL" zu setzen. Letzteres gilt wenn eine verschlüsselte Übertragung genutzt werden soll.
Weitere Attribute sind:
ftpUse | : FTP Transfer nach dem Dump wird eingeschaltet (ohne SSL Verschlüsselung) |
ftpUser | : User zur Anmeldung am FTP-Server, default: anonymous |
ftpUseSSL | : FTP Transfer mit SSL Verschlüsselung nach dem Dump wird eingeschaltet |
ftpDebug | : Debugging des FTP Verkehrs zur Fehlersuche |
ftpDir | : Verzeichnis auf dem FTP-Server in welches das File übertragen werden soll (default: "/") |
ftpPassive | : setzen wenn passives FTP verwendet werden soll |
ftpPort | : FTP-Port, default: 21 |
ftpPwd | : Passwort des FTP-Users, default nicht gesetzt |
ftpServer | : Name oder IP-Adresse des FTP-Servers. notwendig ! |
ftpTimeout | : Timeout für die FTP-Verbindung in Sekunden (default: 30). |
dumpSQLite - erstellt einen Dump der angeschlossenen SQLite-Datenbank.
Diese Funktion nutzt die SQLite Online Backup API und ermöglicht es konsistente Backups der SQLite-DB
in laufenden Betrieb zu erstellen.
Der Dump wird per default im log-Verzeichnis des FHEM-Rechners gespeichert.
Das Zielverzeichnis kann mit dem Attribut "dumpDirLocal" verändert werden und muß
durch FHEM beschreibbar sein.
Vor dem Dump kann optional eine Tabellenoptimierung (Attribut "optimizeTablesBeforeDump")
zugeschaltet werden.
Achtung !
Um ein Blockieren von FHEM zu vermeiden, muß DbLog im asynchronen Modus betrieben werden wenn die
Tabellenoptimierung verwendet wird !
Vor und nach dem Dump kann ein FHEM-Kommando (siehe Attribute "executeBeforeProc", "executeAfterProc")
ausgeführt werden.
Die für diese Funktion relevanten Attribute sind "dumpDirLocal", "dumpFilesKeep", "executeBeforeProc",
"executeAfterProc" und "optimizeTablesBeforeDump".
Nach einem erfolgreichen Dump werden alte Dumpfiles gelöscht und nur die Anzahl Files definiert durch das
Attribut "dumpFilesKeep" (default: 3) verbleibt im Zielverzeichnis "dumpDirLocal".
Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sqlitebkp
Die Datenbank kann mit "set <DbRep-device> restoreSQLite <Filename>" wiederhergestellt
werden.
Das erstellte Dumpfile kann auf einen FTP-Server übertragen werden. Siehe dazu die Erläuterungen
unter "dumpMySQL".
exportToFile - exportiert DB-Einträge im CSV-Format in den gegebenen Zeitgrenzen.
Einschränkungen durch die Attribute Device bzw. Reading gehen in die Selektion mit ein.
Der Filename wird durch das Attribut "expimpfile" bestimmt.
Durch das Attribut "aggregation" wird der Export der Datensätze in Zeitscheiben der angegebenen Aggregation
vorgenommen. Ist z.B. "aggregation = month" gesetzt, werden die Daten in monatlichen Paketen selektiert und in
das Exportfile geschrieben. Dadurch wird die Hauptspeicherverwendung optimiert wenn sehr große Datenmengen
exportiert werden sollen und vermeidet den "died prematurely" Abbruchfehler.
fetchrows [history|current]
- liefert alle Tabelleneinträge (default: history)
in den gegebenen Zeitgrenzen (siehe Attribute).
Eine evtl. gesetzte Aggregation wird nicht berücksichtigt.
Die Leserichtung in der Datenbank kann durch das Attribut
"fetchRoute" bestimmt werden.
Hinweis:
Auch wenn das Modul bezüglich der Datenbankabfrage nichtblockierend arbeitet, kann eine
zu große Ergebnismenge (Anzahl Zeilen bzw. Readings) die Browsersesssion bzw. FHEMWEB
blockieren. Aus diesem Grund wird die Ergebnismenge mit dem
Attribut "limit" begrenzt. Bei Bedarf kann dieses Attribut
geändert werden falls eine Anpassung der Selektionsbedingungen nicht möglich oder
gewünscht ist.
insert - Manuelles Einfügen eines Datensatzes in die Tabelle "history". Obligatorisch sind Eingabewerte für Datum, Zeit und Value.
Die Werte für die DB-Felder Type bzw. Event werden mit "manual" gefüllt, sowie die Werte für Device, Reading aus den gesetzten Attributen genommen.
Eingabeformat: Datum,Zeit,Value,[Unit]
# Unit ist optional, Attribute "reading" und "device" müssen gesetzt sein
# Soll "Value=0" eingefügt werden, ist "Value = 0.0" zu verwenden.
Beispiel: 2016-08-01,23:00:09,TestValue,TestUnit
# Es sind KEINE Leerzeichen im Feldwert erlaubt !
Hinweis:
Bei der Eingabe ist darauf zu achten dass im beabsichtigten Aggregationszeitraum (Tag, Woche, Monat, etc.) MINDESTENS zwei
Datensätze für die Funktion diffValue zur Verfügung stehen. Ansonsten kann keine Differenz berechnet werden und diffValue
gibt in diesem Fall "0" in der betroffenen Periode aus !
importFromFile - importiert Datensätze im CSV-Format aus einem File in die Datenbank. Der Filename wird
durch das Attribut "expimpfile" bestimmt.
Datensatzformat: "TIMESTAMP","DEVICE","TYPE","EVENT","READING","VALUE","UNIT"
# Die Felder "TIMESTAMP","DEVICE","TYPE","EVENT","READING" und "VALUE" müssen gesetzt sein. Das Feld "UNIT" ist optional.
Der Fileinhalt wird als Transaktion importiert, d.h. es wird der Inhalt des gesamten Files oder, im Fehlerfall, kein Datensatz des Files importiert.
Wird eine umfangreiche Datei mit vielen Datensätzen importiert sollte KEIN verbose=5 gesetzt werden. Es würden in diesem Fall sehr viele Sätze in
das Logfile geschrieben werden was FHEM blockieren oder überlasten könnte.
Beispiel: "2016-09-25 08:53:56","STP_5000","SMAUTILS","etotal: 11859.573","etotal","11859.573",""
maxValue [display | writeToDB]
- berechnet den Maximalwert eines Readingwertes (DB-Spalte "VALUE") in den Zeitgrenzen
(Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan".
Es muss das auszuwertende Reading über das Attribut "reading"
angegeben sein.
Die Auswertung enthält den Zeitstempel des ermittelten Maximumwertes innerhalb der
Aggregation bzw. Zeitgrenzen.
Im Reading wird der Zeitstempel des letzten Auftretens vom Maximalwert ausgegeben
falls dieser Wert im Intervall mehrfach erreicht wird.
Ist keine oder die Option "display" angegeben, werden die Ergebnisse nur angezeigt. Mit
der Option "writeToDB" werden die Berechnungsergebnisse mit einem neuen Readingnamen
in der Datenbank gespeichert.
Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet.
Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
Der Timestamp der neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode
abgeleitet, sofern kein eindeutiger Zeitpunkt des Ergebnisses bestimmt werden kann.
Das Feld "EVENT" wird mit "calculated" gefüllt.
Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
max_day_totalpac
# <Bildungsfunktion>_<Aggregation>_<Originalreading>
minValue [display | writeToDB]
- berechnet den Minimalwert eines Readingwertes (DB-Spalte "VALUE") in den Zeitgrenzen
(Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan".
Es muss das auszuwertende Reading über das Attribut "reading"
angegeben sein.
Die Auswertung enthält den Zeitstempel des ermittelten Minimumwertes innerhalb der
Aggregation bzw. Zeitgrenzen.
Im Reading wird der Zeitstempel des ersten Auftretens vom Minimalwert ausgegeben
falls dieser Wert im Intervall mehrfach erreicht wird.
Ist keine oder die Option "display" angegeben, werden die Ergebnisse nur angezeigt. Mit
der Option "writeToDB" werden die Berechnungsergebnisse mit einem neuen Readingnamen
in der Datenbank gespeichert.
Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet.
Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
Der Timestamp der neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode
abgeleitet, sofern kein eindeutiger Zeitpunkt des Ergebnisses bestimmt werden kann.
Das Feld "EVENT" wird mit "calculated" gefüllt.
Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
min_day_totalpac
# <Bildungsfunktion>_<Aggregation>_<Originalreading>
optimizeTables - optimiert die Tabellen in der angeschlossenen Datenbank (MySQL).
Vor und nach der Optimierung kann ein FHEM-Kommando ausgeführt werden.
(siehe Attribute "executeBeforeProc", "executeAfterProc")
Hinweis:
Obwohl die Funktion selbst non-blocking ausgelegt ist, muß das zugeordnete DbLog-Device
im asynchronen Modus betrieben werden um ein Blockieren von FHEMWEB zu vermeiden.
readingRename - benennt den Namen eines Readings innerhalb der angeschlossenen Datenbank (siehe Internal DATABASE) um.
Der Readingname wird immer in der gesamten Datenbank umgesetzt. Eventuell
gesetzte Zeitgrenzen oder Beschränkungen durch die Attribute
Device bzw. Reading werden nicht berücksichtigt.
Eingabeformat: set <name> readingRename <alter Readingname>,<neuer Readingname>
# Die Anzahl der umbenannten Device-Datensätze wird im Reading "reading_renamed"
ausgegeben.
# Wird der umzubenennende Readingname in der Datenbank nicht gefunden, wird eine
WARNUNG im Reading "reading_not_renamed" ausgegeben.
# Entsprechende Einträge erfolgen auch im Logfile mit verbose=3.
Hinweis:
Obwohl die Funktion selbst non-blocking ausgelegt ist, sollte das zugeordnete DbLog-Device
im asynchronen Modus betrieben werden um ein Blockieren von FHEMWEB zu vermeiden (Tabellen-Lock).
restoreMySQL <File>.csv - importiert den Inhalt der history-Tabelle aus einem serverSide-Backup.
Die Funktion stellt über eine Drop-Down Liste eine Dateiauswahl für den Restore zur Verfügung.
Dazu ist das Verzeichnis "dumpDirRemote" des MySQL-Servers auf dem Client zu mounten
und im Attribut "dumpDirLocal" dem DbRep-Device bekannt zu machen.
Es werden alle Files mit der Endung "csv" und deren Name mit der
verbundenen Datenbank beginnt (siehe Internal DATABASE), aufgelistet .
restoreSQLite <File>.sqlitebkp - stellt das Backup einer SQLite-Datenbank wieder her.
Die Funktion stellt über eine Drop-Down Liste die für den Restore zur Verfügung stehenden Dateien
zur Verfügung. Die aktuell in der Zieldatenbank enthaltenen Daten werden gelöscht bzw.
überschrieben.
Es werden alle Files mit der Endung "sqlitebkp" und deren Name mit dem Namen der
verbundenen Datenbank beginnt, aufgelistet .
sqlCmd - führt ein beliebiges Benutzer spezifisches Kommando aus.
Enthält dieses Kommando eine Delete-Operation, muss zur Sicherheit das
Attribut "allowDeletion" gesetzt sein.
Bei der Ausführung dieses Kommandos werden keine Einschränkungen durch gesetzte Attribute
device und/oder reading berücksichtigt.
Sollen die im Modul gesetzten Attribute "timestamp_begin" bzw.
"timestamp_end" im Statement berücksichtigt werden, können die Platzhalter
"§timestamp_begin§" bzw. "§timestamp_end§" dafür verwendet werden.
Beispiele für Statements:
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-01-06 00:00:00" group by DEVICE having count(*) > 800
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-05-06 00:00:00" group by DEVICE
- set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= §timestamp_begin§ group by DEVICE
- set <name> sqlCmd select * from history where DEVICE like "Te%t" order by `TIMESTAMP` desc
- set <name> sqlCmd select * from history where `TIMESTAMP` > "2017-05-09 18:03:00" order by `TIMESTAMP` desc
- set <name> sqlCmd select * from current order by `TIMESTAMP` desc
- set <name> sqlCmd select sum(VALUE) as 'Einspeisung am 04.05.2017', count(*) as 'Anzahl' FROM history where `READING` = "Einspeisung_WirkP_Zaehler_Diff" and TIMESTAMP between '2017-05-04' AND '2017-05-05'
- set <name> sqlCmd delete from current
- set <name> sqlCmd delete from history where TIMESTAMP < "2016-05-06 00:00:00"
- set <name> sqlCmd update history set VALUE='TestVa$$ue$' WHERE VALUE='TestValue'
- set <name> sqlCmd select * from history where DEVICE = "Test"
- set <name> sqlCmd insert into history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ('2017-05-09 17:00:14','Test','manuell','manuell','Tes§e','TestValue','°C')
Das Ergebnis des Statements wird im Reading "SqlResult" dargestellt.
Die Ergebnis-Formatierung kann durch das Attribut "sqlResultFormat" ausgewählt, sowie der verwendete
Feldtrenner durch das Attribut "sqlResultFieldSep" festgelegt werden.
Hinweis:
Auch wenn das Modul bezüglich der Datenbankabfrage nichtblockierend arbeitet, kann eine
zu große Ergebnismenge (Anzahl Zeilen bzw. Readings) die Browsersesssion bzw. FHEMWEB
blockieren. Wenn man sich unsicher ist, sollte man vorsorglich dem Statement ein Limit
hinzufügen.
sumValue [display | writeToDB]
- berechnet die Summenwerte eines Readingwertes (DB-Spalte "VALUE") in den Zeitgrenzen
(Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan".
Es muss das auszuwertende Reading im Attribut "reading"
angegeben sein. Diese Funktion ist sinnvoll wenn fortlaufend Wertedifferenzen eines
Readings in die Datenbank geschrieben werden.
Ist keine oder die Option "display" angegeben, werden die Ergebnisse nur angezeigt. Mit
der Option "writeToDB" werden die Berechnungsergebnisse mit einem neuen Readingnamen
in der Datenbank gespeichert.
Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet.
Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
Der Timestamp der neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode
abgeleitet, sofern kein eindeutiger Zeitpunkt des Ergebnisses bestimmt werden kann.
Das Feld "EVENT" wird mit "calculated" gefüllt.
Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
sum_day_totalpac
# <Bildungsfunktion>_<Aggregation>_<Originalreading>
tableCurrentFillup - Die current-Tabelle wird mit einem Extrakt der history-Tabelle aufgefüllt.
Die Attribute zur Zeiteinschränkung bzw. device, reading werden ausgewertet.
Dadurch kann der Inhalt des Extrakts beeinflusst werden. Im zugehörigen DbLog-Device sollte sollte das Attribut
"DbLogType=SampleFill/History" gesetzt sein.
tableCurrentPurge - löscht den Inhalt der current-Tabelle. Es werden keine Limitierungen, z.B. durch die Attribute "timestamp_begin",
"timestamp_end", device, reading, usw. , ausgewertet.
vacuum - optimiert die Tabellen in der angeschlossenen Datenbank (SQLite, PostgreSQL).
Vor und nach der Optimierung kann ein FHEM-Kommando ausgeführt werden.
(siehe Attribute "executeBeforeProc", "executeAfterProc")
Hinweis:
Obwohl die Funktion selbst non-blocking ausgelegt ist, muß das zugeordnete DbLog-Device
im asynchronen Modus betrieben werden um ein Blockieren von FHEM zu vermeiden.
Für alle Auswertungsvarianten (Ausnahme sqlCmd,deviceRename,readingRename) gilt:
Zusätzlich zu dem auszuwertenden Reading kann das Device mit angegeben werden um das Reporting nach diesen Kriterien einzuschränken.
Sind keine Zeitgrenzen-Attribute angegeben aber Aggregation ist gesetzt, wird '1970-01-01 01:00:00' und das aktuelle Datum/Zeit als
Zeitgrenze genutzt. Sind weder Zeitgrenzen-Attribute noch Aggregation angegeben, wird die Datenselektion ohne Timestamp-Einschränkungen
ausgeführt.
Hinweis:
In der Detailansicht kann ein Browserrefresh nötig sein um die Operationsergebnisse zu sehen sobald im DeviceOverview "state = done" angezeigt wird.
Get
Die Get-Kommandos von DbRep dienen dazu eine Reihe von Metadaten der verwendeten Datenbankinstanz abzufragen.
Dies sind zum Beispiel eingestellte Serverparameter, Servervariablen, Datenbankstatus- und Tabelleninformationen. Die verfügbaren get-Funktionen
sind von dem verwendeten Datenbanktyp abhängig. So ist für SQLite z.Zt. nur "svrinfo" verfügbar. Die Funktionen liefern nativ sehr viele Ausgabewerte,
die über über funktionsspezifische Attribute abgrenzbar sind. Der Filter ist als kommaseparierte Liste anzuwenden.
Dabei kann SQL-Wildcard (%) verwendet werden.
Hinweis:
Nach der Ausführung einer get-Funktion in der Detailsicht einen Browserrefresh durchführen um die Ergebnisse zu sehen !
- blockinginfo - Listet die aktuell systemweit laufenden Hintergrundprozesse (BlockingCalls) mit ihren Informationen auf.
Zu lange Zeichenketten (z.B. Argumente) werden gekürzt ausgeschrieben.
- dbstatus - Listet globale Informationen zum MySQL Serverstatus (z.B. Informationen zum Cache, Threads, Bufferpools, etc. ).
Es werden zunächst alle verfügbaren Informationen berichtet. Mit dem Attribut "showStatus" kann die
Ergebnismenge eingeschränkt werden, um nur gewünschte Ergebnisse abzurufen. Detailinformationen zur Bedeutung der einzelnen Readings
sind hier verfügbar.
Bespiel
get <name> dbstatus
attr <name> showStatus %uptime%,%qcache%
# Es werden nur Readings erzeugt die im Namen "uptime" und "qcache" enthalten
- dbvars - Zeigt die globalen Werte der MySQL Systemvariablen. Enthalten sind zum Beispiel Angaben zum InnoDB-Home, dem Datafile-Pfad,
Memory- und Cache-Parameter, usw. Die Ausgabe listet zunächst alle verfügbaren Informationen auf. Mit dem
Attribut "showVariables" kann die Ergebnismenge eingeschränkt werden um nur gewünschte Ergebnisse
abzurufen. Weitere Informationen zur Bedeutung der ausgegebenen Variablen sind
hier verfügbar.
Bespiel
get <name> dbvars
attr <name> showVariables %version%,%query_cache%
# Es werden nur Readings erzeugt die im Namen "version" und "query_cache" enthalten
- procinfo - Listet die existierenden Datenbank-Prozesse in einer Tabelle auf (nur MySQL).
Typischerweise werden nur die Prozesse des Verbindungsusers (angegeben in DbLog-Konfiguration)
ausgegeben. Sollen alle Prozesse angezeigt werden, ist dem User das globale Recht "PROCESS"
einzuräumen.
Für bestimmte SQL-Statements wird seit MariaDB 5.3 ein Fortschrittsreporting (Spalte "PROGRESS")
ausgegeben. Zum Beispiel kann der Abarbeitungsgrad bei der Indexerstellung verfolgt werden.
Weitere Informationen sind
hier verfügbar.
- svrinfo - allgemeine Datenbankserver-Informationen wie z.B. die DBMS-Version, Serveradresse und Port usw. Die Menge der Listenelemente
ist vom Datenbanktyp abhängig. Mit dem Attribut "showSvrInfo" kann die Ergebnismenge eingeschränkt werden.
Weitere Erläuterungen zu den gelieferten Informationen sind
hier zu finden.
Bespiel
get <name> svrinfo
attr <name> showSvrInfo %SQL_CATALOG_TERM%,%NAME%
# Es werden nur Readings erzeugt die im Namen "SQL_CATALOG_TERM" und "NAME" enthalten
tableinfo - ruft Tabelleninformationen aus der mit dem DbRep-Device verbundenen Datenbank ab (MySQL).
Es werden per default alle in der verbundenen Datenbank angelegten Tabellen ausgewertet.
Mit dem Attribut "showTableInfo" können die Ergebnisse eingeschränkt werden. Erläuterungen zu den erzeugten
Readings sind hier zu finden.
Bespiel
get <name> tableinfo
attr <name> showTableInfo current,history
# Es werden nur Information der Tabellen "current" und "history" angezeigt
Attribute
Über die modulspezifischen Attribute wird die Abgrenzung der Auswertung und die Aggregation der Werte gesteuert.
Hinweis zur SQL-Wildcard Verwendung:
Innerhalb der Attribut-Werte für "device" und "reading" kann SQL-Wildcards "%" angegeben werden.
Dabei wird "%" als Platzhalter für beliebig viele Zeichen verwendet.
Das Zeichen "_" wird nicht als SQL-Wildcard supported.
Dies gilt für alle Funktionen ausser "insert", "importFromFile" und "deviceRename".
Die Funktion "insert" erlaubt nicht, dass die genannten Attribute das Wildcard "%" enthalten. Character "_" wird als normales Zeichen gewertet.
In Ergebnis-Readings wird das Wildcardzeichen "%" durch "/" ersetzt um die Regeln für erlaubte Zeichen in Readings einzuhalten.
- aggregation - Zusammenfassung der Device/Reading-Selektionen in Stunden,Tages,Kalenderwochen,Kalendermonaten oder "no". Liefert z.B. die Anzahl der DB-Einträge am Tag (countEntries), Summation von Differenzwerten eines Readings (sumValue), usw. Mit Aggregation "no" (default) erfolgt keine Zusammenfassung in einem Zeitraum sondern die Ausgabe ergibt alle Werte eines Device/Readings zwischen den definierten Zeiträumen.
- allowDeletion - schaltet die Löschfunktion des Moduls frei
- device - Abgrenzung der DB-Selektionen auf ein bestimmtes Device.
Es können Geräte-Spezifikationen (devspec)
angegeben werden.
Innerhalb von Geräte-Spezifikationen wird SQL-Wildcard (%) als normales ASCII-Zeichen gewertet.
Die Devicenamen werden vor der Selektion aus der Geräte-Spezifikationen und den aktuell in FHEM
vorhandenen Devices abgeleitet.
Beispiele:
attr <Name> device TYPE=DbRep
attr <Name> device MySTP_5000
attr <Name> device SMA.*,MySTP.*
attr <Name> device SMA_Energymeter,MySTP_5000
attr <Name> device %5000
- diffAccept - gilt für Funktion diffValue. diffAccept legt fest bis zu welchem Schwellenwert eine berechnete positive Werte-Differenz
zwischen zwei unmittelbar aufeinander folgenden Datensätzen akzeptiert werden soll (Standard ist 20).
Damit werden fehlerhafte DB-Einträge mit einem unverhältnismäßig hohen Differenzwert von der Berechnung ausgeschlossen und
verfälschen nicht das Ergebnis. Sollten Schwellenwertüberschreitungen vorkommen, wird das Reading "diff_overrun_limit_<diffLimit>"
erstellt. (<diffLimit> wird dabei durch den aktuellen Attributwert ersetzt)
Es enthält eine Liste der relevanten Wertepaare. Mit verbose 3 werden diese Datensätze ebenfalls im Logfile protokolliert.
Beispiel Ausgabe im Logfile beim Überschreiten von diffAccept=10:
DbRep Rep.STP5000.etotal -> data ignored while calc diffValue due to threshold overrun (diffAccept = 10):
2016-04-09 08:50:50 0.0340 -> 2016-04-09 12:42:01 13.3440
# Der erste Datensatz mit einem Wert von 0.0340 ist untypisch gering zum nächsten Wert 13.3440 und führt zu einem zu hohen
Differenzwert.
# Es ist zu entscheiden ob der Datensatz gelöscht, ignoriert, oder das Attribut diffAccept angepasst werden sollte.
- disable - deaktiviert das Modul
- dumpComment - User-Kommentar. Er wird im Kopf des durch den Befehl "dumpMyQL clientSide" erzeugten Dumpfiles
eingetragen.
- dumpDirLocal - Zielverzeichnis für die Erstellung von Dumps mit "dumpMySQL clientSide".
default: "{global}{modpath}/log/" auf dem FHEM-Server.
Ebenfalls werden in diesem Verzeichnis alte Backup-Files durch die interne Versionsverwaltung von
"dumpMySQL" gesucht und gelöscht wenn die gefundene Anzahl den Attributwert "dumpFilesKeep"
überschreitet. Das Attribut dient auch dazu ein lokal gemountetes Verzeichnis "dumpDirRemote"
DbRep bekannt zu machen.
- dumpDirRemote - Zielverzeichnis für die Erstellung von Dumps mit "dumpMySQL serverSide".
default: das Home-Dir des MySQL-Servers auf dem MySQL-Host
- dumpMemlimit - erlaubter Speicherverbrauch für SQL-Script zur Generierungszeit (default: 100000 Zeichen).
Bitte den Parameter anpassen, falls es zu Speicherengpässen und damit verbundenen Performanceproblemen
kommen sollte.
- dumpSpeed - Anzahl der abgerufenen Zeilen aus der Quelldatenbank (default: 10000) pro Select durch "dumpMySQL ClientSide".
Dieser Parameter hat direkten Einfluß auf die Laufzeit und den Ressourcenverbrauch zur Laufzeit.
- dumpFilesKeep - Es wird die angegeben Anzahl Dumpfiles im Dumpdir gelassen (default: 3). Sind mehr (ältere) Dumpfiles
vorhanden, werden diese gelöscht nachdem ein neuer Dump erfolgreich erstellt wurde. Das globale
Attribut "archivesort" wird berücksichtigt.
- executeAfterProc - Es kann ein FHEM-Kommando angegeben werden welches nach dem Dump ausgeführt werden soll.
Funktionen sind in {} einzuschließen.
Beispiel:
attr <DbRep-device> executeAfterProc set og_gz_westfenster off;
attr <DbRep-device> executeAfterProc {adump ("<DbRep-device>")}
# "adump" ist eine in 99_myUtils definierte Funktion.
sub adump {
my ($name) = @_;
my $hash = $defs{$name};
# die eigene Funktion, z.B.
Log3($name, 3, "DbRep $name -> Dump ist beendet");
return;
}
- executeBeforeProc - Es kann ein FHEM-Kommando angegeben werden welches vor dem Dump ausgeführt werden soll.
Funktionen sind in {} einzuschließen.
Beispiel:
attr <DbRep-device> executeBeforeProc set og_gz_westfenster on;
attr <DbRep-device> executeBeforeProc {bdump ("<DbRep-device>")}
# "bdump" ist eine in 99_myUtils definierte Funktion.
sub bdump {
my ($name) = @_;
my $hash = $defs{$name};
# die eigene Funktion, z.B.
Log3($name, 3, "DbRep $name -> Dump startet");
return;
}
- expimpfile - Pfad/Dateiname für Export/Import in/aus einem File.
- fetchRoute [descent | ascent] - bestimmt die Leserichtung des fetchrows-Befehl.
descent - die Datensätze werden absteigend gelesen (default). Wird
die durch das Attribut "limit" festgelegte Anzahl der Datensätze
überschritten, werden die neuesten x Datensätze angezeigt.
ascent - die Datensätze werden aufsteigend gelesen. Wird
die durch das Attribut "limit" festgelegte Anzahl der Datensätze
überschritten, werden die ältesten x Datensätze angezeigt.
- ftpUse - FTP Transfer nach dem Dump wird eingeschaltet (ohne SSL Verschlüsselung). Das erzeugte
Datenbank Backupfile wird non-blocking zum angegebenen FTP-Server (Attribut "ftpServer")
übertragen.
- ftpUseSSL - FTP Transfer mit SSL Verschlüsselung nach dem Dump wird eingeschaltet. Das erzeugte
Datenbank Backupfile wird non-blocking zum angegebenen FTP-Server (Attribut "ftpServer")
übertragen.
- ftpUser - User zur Anmeldung am FTP-Server, default: "anonymous".
- ftpDebug - Debugging der FTP Kommunikation zur Fehlersuche.
- ftpDir - Verzeichnis des FTP-Servers in welches das File übertragen werden soll (default: "/").
- ftpPassive - setzen wenn passives FTP verwendet werden soll
- ftpPort - FTP-Port, default: 21
- ftpPwd - Passwort des FTP-Users, default nicht gesetzt
- ftpServer - Name oder IP-Adresse des FTP-Servers. notwendig !
- ftpTimeout - Timeout für die FTP-Verbindung in Sekunden (default: 30).
- limit - begrenzt die Anzahl der resultierenden Datensätze im select-Statement von "fetchrows", bzw. der anzuzeigenden Datensätze
der Kommandos "delSeqDoublets adviceDelete", "delSeqDoublets adviceRemain" (default 1000).
Diese Limitierung soll eine Überlastung der Browsersession und ein
blockieren von FHEMWEB verhindern. Bei Bedarf entsprechend ändern bzw. die
Selektionskriterien (Zeitraum der Auswertung) anpassen.
- optimizeTablesBeforeDump - wenn "1", wird vor dem Datenbankdump eine Tabellenoptimierung ausgeführt (default: 0).
Dadurch verlängert sich die Laufzeit des Dump.
Hinweis
Die Tabellenoptimierung führt zur Sperrung der Tabellen und damit zur Blockierung von
FHEM falls DbLog nicht im asynchronen Modus (DbLog-Attribut "asyncMode") betrieben wird !
- reading - Abgrenzung der DB-Selektionen auf ein bestimmtes oder mehrere Readings.
Mehrere Readings werden als Komma separierte Liste angegeben.
SQL Wildcard (%) wird in einer Liste als normales ASCII-Zeichen gewertet.
Beispiele:
attr <Name> reading etotal
attr <Name> reading et%
attr <Name> reading etotal,etoday
- readingNameMap - der Name des ausgewerteten Readings wird mit diesem String für die Anzeige überschrieben
- readingPreventFromDel - Komma separierte Liste von Readings die vor einer neuen Operation nicht gelöscht
werden sollen
- role - die Rolle des DbRep-Device. Standard ist "Client". Die Rolle "Agent" ist im Abschnitt
DbRep-Agent beschrieben.
- seqDoubletsVariance - akzeptierte Abweichung (+/-) für das Kommando "set <Name> delSeqDoublets".
Der Wert des Attributs beschreibt die Abweichung bis zu der aufeinanderfolgende numerische Werte (VALUE) von
Datensätze als gleich angesehen und gelöscht werden sollen. "seqDoubletsVariance" ist ein absoluter Zahlenwert,
der sowohl als positive als auch negative Abweichung verwendet wird.
Beispiele:
attr <Name> seqDoubletsVariance 0.0014
attr <Name> seqDoubletsVariance 1.45
- showproctime - wenn gesetzt, zeigt das Reading "sql_processing_time" die benötigte Abarbeitungszeit (in Sekunden)
für die SQL-Ausführung der durchgeführten Funktion. Dabei wird nicht ein einzelnes
SQl-Statement, sondern die Summe aller notwendigen SQL-Abfragen innerhalb der jeweiligen
Funktion betrachtet.
- showStatus - grenzt die Ergebnismenge des Befehls "get ... dbstatus" ein. Es können SQL-Wildcard (%) verwendet werden.
Bespiel: attr ... showStatus %uptime%,%qcache%
# Es werden nur Readings erzeugt die im Namen "uptime" und "qcache" enthalten
- showVariables - grenzt die Ergebnismenge des Befehls "get ... dbvars" ein. Es können SQL-Wildcard (%) verwendet werden.
Bespiel: attr ... showVariables %version%,%query_cache%
# Es werden nur Readings erzeugt die im Namen "version" und "query_cache" enthalten
- showSvrInfo - grenzt die Ergebnismenge des Befehls "get ... svrinfo" ein. Es können SQL-Wildcard (%) verwendet werden.
Bespiel: attr ... showSvrInfo %SQL_CATALOG_TERM%,%NAME%
# Es werden nur Readings erzeugt die im Namen "SQL_CATALOG_TERM" und "NAME" enthalten
- showTableInfo - grenzt die Ergebnismenge des Befehls "get ... tableinfo" ein. Es können SQL-Wildcard (%) verwendet werden.
Bespiel: attr ... showTableInfo current,history
# Es werden nur Information der Tabellen "current" und "history" angezeigt
- sqlResultFieldSep - legt den verwendeten Feldseparator (default: "|") im Ergebnis des Kommandos "set ... sqlCmd" fest.
- sqlResultFormat - legt die Formatierung des Ergebnisses des Kommandos "set ... sqlCmd" fest.
Mögliche Optionen sind:
separated - die Ergebniszeilen werden als einzelne Readings fortlaufend
generiert. (default)
mline - das Ergebnis wird als Mehrzeiler im Reading
SqlResult dargestellt.
sline - das Ergebnis wird als Singleline im Reading
SqlResult dargestellt. Satztrenner ist"]|[".
table - das Ergebnis wird als Tabelle im Reading
SqlResult dargestellt.
json - erzeugt das Reading SqlResult als
JSON-kodierten Hash.
Jedes Hash-Element (Ergebnissatz) setzt sich aus der laufenden Nummer
des Datensatzes (Key) und dessen Wert zusammen.
Die Weiterverarbeitung des Ergebnisses kann z.B. mit der folgenden userExitFn in 99_myUtils.pm erfolgen:
sub resfromjson {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
if ($reading eq "SqlResult") {
# nur Reading SqlResult enthält JSON-kodierte Daten
my $data = decode_json($value);
foreach my $k (keys(%$data)) {
# ab hier eigene Verarbeitung für jedes Hash-Element
# z.B. Ausgabe jedes Element welches "Cam" enthält
my $ke = $data->{$k};
if($ke =~ m/Cam/i) {
my ($res1,$res2) = split("\\|", $ke);
Log3($name, 1, "$name - extract element $k by userExitFn: ".$res1." ".$res2);
}
}
}
return;
}
timeYearPeriod - Mit Hilfe dieses Attributes wird eine jährliche Zeitperiode für die Datenbankselektion bestimmt.
Die Zeitgrenzen werden zur Ausführungszeit dynamisch berechnet. Es wird immer eine Jahresperiode
bestimmt. Eine unterjährige Angabe ist nicht möglich.
Dieses Attribut ist vor allem dazu gedacht Auswertungen synchron zu einer Abrechnungsperiode, z.B. der eines
Energie- oder Gaslieferanten, anzufertigen.
Beispiel:
attr <DbRep-device> timeYearPeriod 06-25 06-24
# wertet die Datenbank in den Zeitgrenzen 25. Juni AAAA bis 24. Juni BBBB aus.
# Das Jahr AAAA bzw. BBBB wird in Abhängigkeit des aktuellen Datums errechnet.
# Ist das aktuelle Datum >= 25. Juni und =< 31. Dezember, dann ist AAAA = aktuelles Jahr und BBBB = aktuelles Jahr+1
# Ist das aktuelle Datum >= 01. Januar und =< 24. Juni, dann ist AAAA = aktuelles Jahr-1 und BBBB = aktuelles Jahr
timestamp_begin - der zeitliche Beginn für die Datenselektion (*)
timestamp_end - das zeitliche Ende für die Datenselektion. Wenn nicht gesetzt wird immer die aktuelle
Datum/Zeit-Kombi für das Ende der Selektion eingesetzt. (*)
(*) Das Format von Timestamp ist wie in DbLog "YYYY-MM-DD HH:MM:SS". Für die Attribute "timestamp_begin", "timestamp_end"
kann ebenso eine der folgenden Eingaben verwendet werden. Dabei wird das timestamp-Attribut dynamisch belegt:
current_year_begin : entspricht "<aktuelles Jahr>-01-01 00:00:00"
current_year_end : entspricht "<aktuelles Jahr>-12-31 23:59:59"
previous_year_begin : entspricht "<vorheriges Jahr>-01-01 00:00:00"
previous_year_end : entspricht "<vorheriges Jahr>-12-31 23:59:59"
current_month_begin : entspricht "<aktueller Monat erster Tag> 00:00:00"
current_month_end : entspricht "<aktueller Monat letzter Tag> 23:59:59"
previous_month_begin : entspricht "<Vormonat erster Tag> 00:00:00"
previous_month_end : entspricht "<Vormonat letzter Tag> 23:59:59"
current_week_begin : entspricht "<erster Tag der akt. Woche> 00:00:00"
current_week_end : entspricht "<letzter Tag der akt. Woche> 23:59:59"
previous_week_begin : entspricht "<erster Tag Vorwoche> 00:00:00"
previous_week_end : entspricht "<letzter Tag Vorwoche> 23:59:59"
current_day_begin : entspricht "<aktueller Tag> 00:00:00"
current_day_end : entspricht "<aktueller Tag> 23:59:59"
previous_day_begin : entspricht "<Vortag> 00:00:00"
previous_day_end : entspricht "<Vortag> 23:59:59"
current_hour_begin : entspricht "<aktuelle Stunde>:00:00"
current_hour_end : entspricht "<aktuelle Stunde>:59:59"
previous_hour_begin : entspricht "<vorherige Stunde>:00:00"
previous_hour_end : entspricht "<vorherige Stunde>:59:59"
Natürlich sollte man immer darauf achten dass "timestamp_begin" < "timestamp_end" ist.
Beispiel:
attr <DbRep-device> timestamp_begin current_year_begin
attr <DbRep-device> timestamp_end current_year_end
# Wertet die Datenbank in den Zeitgrenzen des aktuellen Jahres aus.
Hinweis
Wird das Attribut "timeDiffToNow" gesetzt, werden die eventuell gesetzten anderen Zeit-Attribute
("timestamp_begin","timestamp_end","timeYearPeriod") gelöscht.
Das Setzen von "timestamp_begin" bzw. "timestamp_end" bedingt die Löschung von anderen Zeit-Attribute falls sie vorher gesetzt waren.
timeDiffToNow - der Selektionsbeginn wird auf den Zeitpunkt "<aktuelle Zeit> - <timeDiffToNow>"
gesetzt (z.b. werden die letzten 24 Stunden in die Selektion eingehen wenn das Attribut auf "86400" gesetzt
wurde). Die Timestampermittlung erfolgt dynamisch zum Ausführungszeitpunkt.
Eingabeformat Beispiel:
attr <Name> timeDiffToNow 86400
# die Startzeit wird auf "aktuelle Zeit - 86400 Sekunden" gesetzt
attr <Name> timeDiffToNow d:2 h:3 m:2 s:10
# die Startzeit wird auf "aktuelle Zeit - 2 Tage 3 Stunden 2 Minuten 10 Sekunden" gesetzt
attr <Name> timeDiffToNow m:600
# die Startzeit wird auf "aktuelle Zeit - 600 Minuten" gesetzt
attr <Name> timeDiffToNow h:2.5
# die Startzeit wird auf "aktuelle Zeit - 2,5 Stunden" gesetzt
timeOlderThan - das Selektionsende wird auf den Zeitpunkt "<aktuelle Zeit> - <timeOlderThan>"
gesetzt. Dadurch werden alle Datensätze bis zu dem Zeitpunkt "<aktuelle
Zeit> - <timeOlderThan>" berücksichtigt (z.b. wenn auf 86400 gesetzt, werden alle
Datensätze die älter als ein Tag sind berücksichtigt). Die Timestampermittlung erfolgt
dynamisch zum Ausführungszeitpunkt.
Es gelten die gleichen Eingabeformate wie für das Attribut "timeDiffToNow".
timeout - das Attribut setzt den Timeout-Wert für die Blocking-Call Routinen in Sekunden
(Default: 86400)
userExitFn - stellt eine Schnittstelle zur Ausführung eigenen Usercodes zur Verfügung.
Um die Schnittstelle zu aktivieren, wird zunächst die aufzurufende Subroutine in
99_myUtls.pm nach folgendem Muster erstellt:
sub UserFunction {
my ($name,$reading,$value) = @_;
my $hash = $defs{$name};
...
# z.B. übergebene Daten loggen
Log3 $name, 1, "UserExitFn $name called - transfer parameter are Reading: $reading, Value: $value " ;
...
return;
}
Die Aktivierung der Schnittstelle erfogt durch Setzen des Funktionsnames im Attribut.
Optional kann ein Reading:Value Regex als Argument angegeben werden. Wird kein Regex
angegeben, werden alle Wertekombinationen als "wahr" gewertet (entspricht .*:.*).
Beispiel:
attr userExitFn UserFunction .*:.*
# "UserFunction" ist die Subroutine in 99_myUtils.pm.
Grundsätzlich arbeitet die Schnittstelle OHNE Eventgenerierung bzw. benötigt zur Funktion keinen
Event. Sofern das Attribut gesetzt ist, erfolgt Die Regexprüfung NACH der Erstellung eines
Readings. Ist die Prüfung WAHR, wird die angegebene Funktion aufgerufen.
Zur Weiterverarbeitung werden der aufgerufenenen Funktion folgende Variablen übergeben:
- $name - der Name des DbRep-Devices
- $reading - der Namen des erstellen Readings
- $value - der Wert des Readings
Readings
Abhängig von der ausgeführten DB-Operation werden die Ergebnisse in entsprechenden Readings dargestellt. Zu Beginn einer neuen Operation
werden alle alten Readings einer vorangegangenen Operation gelöscht um den Verbleib unpassender bzw. ungültiger Readings zu vermeiden.
Zusätzlich werden folgende Readings erzeugt (Auswahl):
- state - enthält den aktuellen Status der Auswertung. Wenn Warnungen auftraten (state = Warning) vergleiche Readings
"diff_overrun_limit_<diffLimit>" und "less_data_in_period"
- errortext - Grund eines Fehlerstatus
- background_processing_time - die gesamte Prozesszeit die im Hintergrund/Blockingcall verbraucht wird
- diff_overrun_limit_<diffLimit> - enthält eine Liste der Wertepaare die eine durch das Attribut "diffAccept" festgelegte Differenz
<diffLimit> (Standard: 20) überschreiten. Gilt für Funktion "diffValue".
- less_data_in_period - enthält eine Liste der Zeitperioden in denen nur ein einziger Datensatz gefunden wurde. Die
Differenzberechnung berücksichtigt den letzten Wert der Vorperiode. Gilt für Funktion "diffValue".
- sql_processing_time - der Anteil der Prozesszeit die für alle SQL-Statements der ausgeführten
Operation verbraucht wird
- SqlResult - Ergebnis des letzten sqlCmd-Kommandos. Die Formatierung erfolgt entsprechend
des Attributes "sqlResultFormat"
- sqlCmd - das letzte ausgeführte sqlCmd-Kommando
DbRep Agent - automatisches Ändern von Device-Namen in Datenbanken und DbRep-Definitionen nach FHEM "rename" Kommando
Mit dem Attribut "role" wird die Rolle des DbRep-Device festgelegt. Die Standardrolle ist "Client". Mit der Änderung der Rolle in "Agent" wird das Device
veranlasst auf Umbenennungen von Geräten in der FHEM Installation zu reagieren.
Durch den DbRep-Agenten werden folgende Features aktiviert wenn ein Gerät in FHEM mit "rename" umbenannt wird:
- in der dem DbRep-Agenten zugeordneten Datenbank (Internal Database) wird nach Datensätzen mit dem alten Gerätenamen gesucht und dieser Gerätename in
allen betroffenen Datensätzen in den neuen Namen geändert.
- in dem DbRep-Agenten zugeordneten DbLog-Device wird in der Definition das alte durch das umbenannte Device ersetzt. Dadurch erfolgt ein weiteres Logging
des umbenannten Device in der Datenbank.
- in den existierenden DbRep-Definitionen vom Typ "Client" wird ein evtl. gesetztes Attribut "device = alter Devicename" in "device = neuer Devicename"
geändert. Dadurch werden Auswertungsdefinitionen bei Geräteumbenennungen automatisch konstistent gehalten.
Mit der Änderung in einen Agenten sind folgende Restriktionen verbunden die mit dem Setzen des Attributes "role = Agent" eingeschaltet
und geprüft werden:
- es kann nur einen Agenten pro Datenbank in der FHEM-Installation geben. Ist mehr als eine Datenbank mit DbLog definiert, können
ebenso viele DbRep-Agenten eingerichtet werden
- mit der Umwandlung in einen Agenten wird nur noch das Set-Komando "renameDevice" verfügbar sein sowie nur ein eingeschränkter Satz von DbRep-spezifischen
Attributen zugelassen. Wird ein DbRep-Device vom bisherigen Typ "Client" in einen Agenten geändert, werden evtl. gesetzte und nun nicht mehr zugelassene
Attribute glöscht.
Die Aktivitäten wie Datenbankänderungen bzw. Änderungen an anderen DbRep-Definitionen werden im Logfile mit verbose=3 protokolliert. Damit die renameDevice-Funktion
bei großen Datenbanken nicht in ein timeout läuft, sollte das Attribut "timeout" entsprechend dimensioniert werden. Wie alle Datenbankoperationen des Moduls
wird auch das Autorename nonblocking ausgeführt.
Beispiel für die Definition eines DbRep-Device als Agent:
define Rep.Agent DbRep LogDB
attr Rep.Agent devStateIcon connected:10px-kreis-gelb .*disconnect:10px-kreis-rot .*done:10px-kreis-gruen
attr Rep.Agent icon security
attr Rep.Agent role Agent
attr Rep.Agent room DbLog
attr Rep.Agent showproctime 1
attr Rep.Agent stateFormat { ReadingsVal("$name","state", undef) eq "running" ? "renaming" : ReadingsVal("$name","state", undef). " »; ProcTime: ".ReadingsVal("$name","sql_processing_time", undef)." sec"}
attr Rep.Agent timeout 86400
Hinweis:
Obwohl die Funktion selbst non-blocking ausgelegt ist, sollte das zugeordnete DbLog-Device
im asynchronen Modus betrieben werden um ein Blockieren von FHEMWEB zu vermeiden (Tabellen-Lock).
=end html_DE
=cut