diff --git a/fhem/contrib/DS_Starter/93_DbRep.pm b/fhem/contrib/DS_Starter/93_DbRep.pm index 218b40ce3..80058c58c 100644 --- a/fhem/contrib/DS_Starter/93_DbRep.pm +++ b/fhem/contrib/DS_Starter/93_DbRep.pm @@ -57,7 +57,7 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch'; # Version History intern our %DbRep_vNotesIntern = ( - "8.40.7" => "03.09.2020 consider attr timeout in function DbRep_dbValue (blocking function) ", + "8.40.7" => "03.09.2020 rename getter dbValue to sqlCmdBlocking, consider attr timeout in function DbRep_sqlCmdBlocking (blocking function), commandRef revised ", "8.40.6" => "27.08.2020 commandRef revised ", "8.40.5" => "29.07.2020 fix crash if delEntries startet without any time limits, Forum:#113202 ", "8.40.4" => "23.07.2020 new aggregation value 'minute', some fixes ", @@ -103,7 +103,7 @@ our %DbRep_vNotesIntern = ( "8.25.0" => "01.09.2019 make SQL Wildcard (\%) possible as placeholder in a device list: https://forum.fhem.de/index.php/topic,101756.0.html ". "sub DbRep_modAssociatedWith changed ", "8.24.0" => "24.08.2019 devices marked as \"Associated With\" if possible, fhem.pl 20069 2019-08-27 08:36:02Z is needed ", - "8.23.1" => "26.08.2019 fix add newline at the end of DbRep_dbValue result, Forum: #103295 ", + "8.23.1" => "26.08.2019 fix add newline at the end of DbRep_sqlCmdBlocking result, Forum: #103295 ", "8.23.0" => "24.08.2019 prepared for devices marked as \"Associated With\" if possible ", "8.22.0" => "23.08.2019 new attr fetchValueFn. When fetching the database content, manipulate the VALUE-field before create reading ", "8.21.2" => "14.08.2019 commandRef revised ", @@ -128,7 +128,7 @@ our %DbRep_vNotesIntern = ( "8.11.1" => "25.01.2019 fix sort of versionNotes ", "8.11.0" => "24.01.2019 command exportToFile or attribute \"expimpfile\" accepts option \"MAXLINES=\" ", "8.10.1" => "23.01.2019 change DbRep_charfilter to eliminate \xc2", - "8.10.0" => "19.01.2019 sqlCmd, dbValue may input SQL session variables, Forum:#96082 ", + "8.10.0" => "19.01.2019 sqlCmd, sqlCmdBlocking may input SQL session variables, Forum:#96082 ", "8.9.10" => "18.01.2019 fix warnings Malformed UTF-8 character during importFromFile, Forum:#96056 ", "8.9.9" => "06.01.2019 diffval_DoParse: 'ORDER BY TIMESTAMP' added to statements Forum:https://forum.fhem.de/index.php/topic,53584.msg882082.html#msg882082", "1.0.0" => "19.05.2016 Initial" @@ -136,6 +136,9 @@ our %DbRep_vNotesIntern = ( # Version History extern: our %DbRep_vNotesExtern = ( + "8.40.7" => "03.09.2020 The get Command \"dbValue\" has been renamed to \"sqlCmdBlocking\. You can use \"dbValue\" furthermore in your scripts, but it is ". + "deprecated and will be removed soon. Please change your scripts to use \"sqlCmdBlocking\" instead. ", + "8.40.4" => "23.07.2020 The new aggregation type 'minute' is now available. ", "8.40.0" => "30.03.2020 The option 'writeToDBInTime' is provided for function 'sumValue' and 'averageValue'. ". "A new attribute 'autoForward' is implemented. Now it is possible to transfer the results from the DbRep-Device to another one. ". "Please see also this (german) Wiki article ", @@ -147,7 +150,7 @@ our %DbRep_vNotesExtern = ( "written at every begin and also at every end of specified aggregation period. ", "8.30.0" => "14.11.2019 A new command \"set adminCredentials\" and \"get storedCredentials\" ist provided. ". "Use it to store a database priviledged user. This user DbRep can utilize for several operations which are need more (administative) ". - "user rights (e.g. index, sqlCmd). ", + "user rights (e.g. index, sqlCmd). ", "8.29.0" => "08.11.2019 add option FullDay for timeDiffToNow and timeOlderThan, Forum: https://forum.fhem.de/index.php/topic,53584.msg991139.html#msg991139 ", "8.28.0" => "30.09.2019 seqDoubletsVariance - separate specification of positive and negative variance possible, Forum: https://forum.fhem.de/index.php/topic,53584.msg959963.html#msg959963 ", "8.25.0" => "29.08.2019 If a list of devices in attribute \"device\" contains a SQL wildcard (\%), this wildcard is now " @@ -351,34 +354,34 @@ sub DbRep_Initialize { "averageCalcForm:avgArithmeticMean,avgDailyMeanGWS,avgTimeWeightMean ". "countEntriesDetail:1,0 ". "device " . - "dumpComment ". + "dumpComment ". "dumpCompress:1,0 ". - "dumpDirLocal ". - "dumpDirRemote ". - "dumpMemlimit ". - "dumpSpeed ". - "dumpFilesKeep:0,1,2,3,4,5,6,7,8,9,10 ". - "executeBeforeProc ". - "executeAfterProc ". + "dumpDirLocal ". + "dumpDirRemote ". + "dumpMemlimit ". + "dumpSpeed ". + "dumpFilesKeep:0,1,2,3,4,5,6,7,8,9,10 ". + "executeBeforeProc ". + "executeAfterProc ". "expimpfile ". "fastStart:1,0 ". - "fetchRoute:ascent,descent ". + "fetchRoute:ascent,descent ". "fetchMarkDuplicates:red,blue,brown,green,orange ". "fetchValueFn:textField-long ". - "ftpDebug:1,0 ". - "ftpDir ". + "ftpDebug:1,0 ". + "ftpDir ". "ftpDumpFilesKeep:1,2,3,4,5,6,7,8,9,10 ". - "ftpPassive:1,0 ". - "ftpPwd ". - "ftpPort ". - "ftpServer ". - "ftpTimeout ". - "ftpUse:1,0 ". - "ftpUser ". - "ftpUseSSL:1,0 ". - "diffAccept ". - "limit ". - "optimizeTablesBeforeDump:1,0 ". + "ftpPassive:1,0 ". + "ftpPwd ". + "ftpPort ". + "ftpServer ". + "ftpTimeout ". + "ftpUse:1,0 ". + "ftpUser ". + "ftpUseSSL:1,0 ". + "diffAccept ". + "limit ". + "optimizeTablesBeforeDump:1,0 ". "readingNameMap ". "readingPreventFromDel ". "role:Client,Agent ". @@ -390,16 +393,16 @@ sub DbRep_Initialize { "showTableInfo ". "sqlCmdHistoryLength:0,5,10,15,20,25,30,35,40,45,50 ". "sqlCmdVars ". - "sqlResultFormat:separated,mline,sline,table,json ". - "sqlResultFieldSep:|,:,\/ ". - "timeYearPeriod ". + "sqlResultFormat:separated,mline,sline,table,json ". + "sqlResultFieldSep:|,:,\/ ". + "timeYearPeriod ". "timestamp_begin ". "timestamp_end ". "timeDiffToNow ". "timeOlderThan ". "timeout ". "useAdminCredentials:1,0 ". - "userExitFn ". + "userExitFn ". "valueFilter ". $readingFnAttributes; @@ -492,7 +495,7 @@ sub DbRep_Set { my (@bkps,$dir); $dir = AttrVal($name, "dumpDirLocal", "./"); # 'dumpDirRemote' (Backup-Verz. auf dem MySQL-Server) muß gemountet sein und in 'dumpDirLocal' eingetragen sein $dir = $dir."/" unless($dir =~ m/\/$/); - + opendir(DIR,$dir); if ($dbmodel =~ /MYSQL/) { $dbname = $hash->{DATABASE}; @@ -521,9 +524,9 @@ sub DbRep_Set { (($hash->{ROLE} ne "Agent")?"changeValue ":""). (($hash->{ROLE} ne "Agent")?"delDoublets:adviceDelete,delete ":""). (($hash->{ROLE} ne "Agent")?"delEntries ":""). - (($hash->{ROLE} ne "Agent")?"delSeqDoublets:adviceRemain,adviceDelete,delete ":""). + (($hash->{ROLE} ne "Agent")?"delSeqDoublets:adviceRemain,adviceDelete,delete ":""). "deviceRename ". - (($hash->{ROLE} ne "Agent")?"readingRename ":""). + (($hash->{ROLE} ne "Agent")?"readingRename ":""). (($hash->{ROLE} ne "Agent")?"exportToFile ":""). (($hash->{ROLE} ne "Agent")?"importFromFile ":""). (($hash->{ROLE} ne "Agent")?"maxValue:display,writeToDB,deleteOther ":""). @@ -538,14 +541,14 @@ sub DbRep_Set { (($hash->{ROLE} ne "Agent" && $hl)?"sqlCmdHistory:".$hl." ":""). (($hash->{ROLE} ne "Agent")?"sqlSpecial:50mostFreqLogsLast2days,allDevCount,allDevReadCount,recentReadingsOfDevice".(($dbmodel eq "MYSQL")?",readingsDifferenceByTimeDelta":"")." ":""). (($hash->{ROLE} ne "Agent")?"syncStandby ":""). - (($hash->{ROLE} ne "Agent")?"tableCurrentFillup:noArg ":""). - (($hash->{ROLE} ne "Agent")?"tableCurrentPurge:noArg ":""). - (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"dumpMySQL:clientSide,serverSide ":""). + (($hash->{ROLE} ne "Agent")?"tableCurrentFillup:noArg ":""). + (($hash->{ROLE} ne "Agent")?"tableCurrentPurge:noArg ":""). + (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"dumpMySQL:clientSide,serverSide ":""). (($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/)?"dumpSQLite:noArg ":""). (($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/)?"repairSQLite ":""). - (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"optimizeTables:noArg ":""). - (($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE|POSTGRESQL/)?"vacuum:noArg ":""). - (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"restoreMySQL:".$cj." ":""). + (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"optimizeTables:noArg ":""). + (($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE|POSTGRESQL/)?"vacuum:noArg ":""). + (($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/)?"restoreMySQL:".$cj." ":""). (($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/)?"restoreSQLite:".$cj." ":""). (($hash->{ROLE} ne "Agent")?"countEntries:history,current ":""); @@ -559,17 +562,17 @@ sub DbRep_Set { if ($opt eq "dumpMySQL" && $hash->{ROLE} ne "Agent") { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; - if ($prop eq "serverSide") { + if ($prop eq "serverSide") { Log3 ($name, 3, "DbRep $name - ################################################################"); Log3 ($name, 3, "DbRep $name - ### New database serverSide dump ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); - } else { + } else { Log3 ($name, 3, "DbRep $name - ################################################################"); Log3 ($name, 3, "DbRep $name - ### New database clientSide dump ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); - } + } DbRep_beforeproc($hash, "dump"); - DbRep_Main($hash,$opt,$prop); + DbRep_Main($hash,$opt,$prop); return; } @@ -579,7 +582,7 @@ sub DbRep_Set { Log3 ($name, 3, "DbRep $name - ### New SQLite dump ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); DbRep_beforeproc($hash, "dump"); - DbRep_Main($hash,$opt,$prop); + DbRep_Main($hash,$opt,$prop); return; } @@ -598,7 +601,7 @@ sub DbRep_Set { CommandSet(undef,"$dbl reopen $prop"); DbRep_beforeproc($hash, "repair"); - DbRep_Main($hash,$opt); + DbRep_Main($hash,$opt); return; } @@ -608,7 +611,7 @@ sub DbRep_Set { Log3 ($name, 3, "DbRep $name - ### New database Restore/Recovery ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); DbRep_beforeproc($hash, "restore"); - DbRep_Main($hash,$opt,$prop); + DbRep_Main($hash,$opt,$prop); return; } @@ -617,8 +620,8 @@ sub DbRep_Set { Log3 ($name, 3, "DbRep $name - ################################################################"); Log3 ($name, 3, "DbRep $name - ### New optimize table / vacuum execution ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); - DbRep_beforeproc($hash, "optimize"); - DbRep_Main($hash,$opt); + DbRep_beforeproc($hash, "optimize"); + DbRep_Main($hash,$opt); return; } @@ -627,7 +630,7 @@ sub DbRep_Set { if ($prop =~ /delete/ && !AttrVal($hash->{NAME}, "allowDeletion", 0)) { return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; } - DbRep_beforeproc($hash, "delDoublets"); + DbRep_beforeproc($hash, "delDoublets"); DbRep_Main($hash,$opt,$prop); return; } @@ -644,7 +647,7 @@ sub DbRep_Set { Log3 ($name, 3, "DbRep $name - ################################################################"); Log3 ($name, 3, "DbRep $name - ### new reduceLog run ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); - DbRep_beforeproc($hash, "reduceLog"); + DbRep_beforeproc($hash, "reduceLog"); DbRep_Main($hash,$opt); return; } @@ -668,24 +671,24 @@ sub DbRep_Set { if ($opt eq "cancelDump" && $hash->{ROLE} ne "Agent") { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; BlockingKill($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); - Log3 ($name, 3, "DbRep $name -> running Dump has been canceled"); - ReadingsSingleUpdateValue ($hash, "state", "Dump canceled", 1); + Log3 ($name, 3, "DbRep $name -> running Dump has been canceled"); + ReadingsSingleUpdateValue ($hash, "state", "Dump canceled", 1); return; } if ($opt eq "cancelRepair" && $hash->{ROLE} ne "Agent") { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; BlockingKill($hash->{HELPER}{RUNNING_REPAIR}); - Log3 ($name, 3, "DbRep $name -> running Repair has been canceled"); - ReadingsSingleUpdateValue ($hash, "state", "Repair canceled", 1); + Log3 ($name, 3, "DbRep $name -> running Repair has been canceled"); + ReadingsSingleUpdateValue ($hash, "state", "Repair canceled", 1); return; } if ($opt eq "cancelRestore" && $hash->{ROLE} ne "Agent") { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; BlockingKill($hash->{HELPER}{RUNNING_RESTORE}); - Log3 ($name, 3, "DbRep $name -> running Restore has been canceled"); - ReadingsSingleUpdateValue ($hash, "state", "Restore canceled", 1); + Log3 ($name, 3, "DbRep $name -> running Restore has been canceled"); + ReadingsSingleUpdateValue ($hash, "state", "Restore canceled", 1); return; } @@ -700,22 +703,22 @@ sub DbRep_Set { Log3 ($name, 3, "DbRep $name - ################################################################"); Log3 ($name, 3, "DbRep $name - ### New Index operation ###"); Log3 ($name, 3, "DbRep $name - ################################################################"); - + # Befehl vor Procedure ausführen DbRep_beforeproc ($hash, "index"); - DbRep_Main ($hash,$opt,$prop); + DbRep_Main ($hash,$opt,$prop); return; } if ($opt eq "adminCredentials" && $hash->{ROLE} ne "Agent") { return "Credentials are incomplete, use username password" if (!$prop || !$prop1); my $success = DbRep_setcredentials($hash,"adminCredentials",$prop,$prop1); - - if($success) { - return "Username and password for database root access saved successfully"; - } else { - return "Error while saving username / password - see logfile for details"; - } + + if($success) { + return "Username and password for database root access saved successfully"; + } else { + return "Error while saving username / password - see logfile for details"; + } } ####################################################################################################### @@ -724,8 +727,8 @@ sub DbRep_Set { if ($dbloghash->{HELPER}{REOPEN_RUNS} && $opt !~ /\?/) { my $ro = $dbloghash->{HELPER}{REOPEN_RUNS_UNTIL}; Log3 ($name, 3, "DbRep $name - connection $dblogdevice to db $dbname is closed until $ro - $opt postponed"); - ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); - return; + ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); + return; } ####################################################################################################### @@ -762,10 +765,10 @@ sub DbRep_Set { if (!AttrVal($hash->{NAME}, "allowDeletion", undef)) { return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; } - delete $hash->{HELPER}{DELENTRIES}; + delete $hash->{HELPER}{DELENTRIES}; shift @a; shift @a; - $hash->{HELPER}{DELENTRIES} = \@a if(@a); + $hash->{HELPER}{DELENTRIES} = \@a if(@a); DbRep_beforeproc($hash, "delEntries"); DbRep_Main($hash,$opt); @@ -778,7 +781,7 @@ sub DbRep_Set { if (!$olddev || !$newdev) {return "Both entries \"old device name\", \"new device name\" are needed. Use \"set $name deviceRename olddevname,newdevname\" ";} $hash->{HELPER}{OLDDEV} = $olddev; $hash->{HELPER}{NEWDEV} = $newdev; - $hash->{HELPER}{RENMODE} = "devren"; + $hash->{HELPER}{RENMODE} = "devren"; DbRep_Main($hash,$opt); } elsif ($opt eq "readingRename") { @@ -790,7 +793,7 @@ sub DbRep_Set { if (!$oldread || !$newread) {return "Both entries \"old reading name\", \"new reading name\" are needed. Use \"set $name readingRename oldreadingname,newreadingname\" ";} $hash->{HELPER}{OLDREAD} = $oldread; $hash->{HELPER}{NEWREAD} = $newread; - $hash->{HELPER}{RENMODE} = "readren"; + $hash->{HELPER}{RENMODE} = "readren"; DbRep_Main($hash,$opt); } elsif ($opt eq "insert" && $hash->{ROLE} ne "Agent") { @@ -872,8 +875,8 @@ sub DbRep_Set { shift @cmd; shift @cmd; $sqlcmd = join(" ", @cmd); @cmd = split(/\s/, $sqlcmd); - $sqlcmd = join(" ", @cmd); - # $sqlcmd =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; # V8.36.0 20.03.2020 + $sqlcmd = join(" ", @cmd); + # $sqlcmd =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; # V8.36.0 20.03.2020 } if($opt eq "sqlCmdHistory") { $prop =~ s/§/_ESC_ECS_/g; @@ -889,12 +892,12 @@ sub DbRep_Set { } } $hash->{LASTCMD} = $sqlcmd?"$opt $sqlcmd":"$opt"; - if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($hash->{NAME}, "allowDeletion", undef)) { + if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($hash->{NAME}, "allowDeletion", undef)) { return "Attribute 'allowDeletion = 1' is needed for command '$sqlcmd'. Use it with care !"; } DbRep_beforeproc($hash, "sqlCmd"); DbRep_Main($hash,$opt,$sqlcmd); - + } elsif ($opt =~ /changeValue/) { shift @a; shift @a; @@ -923,14 +926,14 @@ sub DbRep_Set { $hash->{HELPER}{RENMODE} = "changeval"; DbRep_beforeproc($hash, "changeval"); DbRep_Main($hash,$opt); - + } elsif ($opt =~ m/syncStandby/ && $hash->{ROLE} ne "Agent") { unless($prop) {return "A DbLog-device (standby) is needed to sync. Use \"set $name syncStandby \" ";} if(!exists($defs{$prop}) || $defs{$prop}->{TYPE} ne "DbLog") { return "The device \"$prop\" doesn't exist or is not a DbLog-device. "; } $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; - DbRep_beforeproc($hash, "syncStandby"); + DbRep_beforeproc($hash, "syncStandby"); DbRep_Main($hash,$opt,$prop); } else { @@ -958,13 +961,13 @@ sub DbRep_Get { my $getlist = "Unknown argument $opt, choose one of ". "svrinfo:noArg ". - "blockinginfo:noArg ". + "blockinginfo:noArg ". "minTimestamp:noArg ". (($dbmodel =~ /MYSQL/)?"storedCredentials:noArg ":""). - "dbValue:textField-long ". + "sqlCmdBlocking:textField-long ". (($dbmodel eq "MYSQL")?"dbstatus:noArg ":""). (($dbmodel eq "MYSQL")?"tableinfo:noArg ":""). - (($dbmodel eq "MYSQL")?"procinfo:noArg ":""). + (($dbmodel eq "MYSQL")?"procinfo:noArg ":""). (($dbmodel eq "MYSQL")?"dbvars:noArg ":""). "versionNotes " ; @@ -974,15 +977,15 @@ sub DbRep_Get { if ($dbloghash->{HELPER}{REOPEN_RUNS} && $opt !~ /\?|procinfo|blockinginfo/) { my $ro = $dbloghash->{HELPER}{REOPEN_RUNS_UNTIL}; Log3 ($name, 3, "DbRep $name - connection $dblogdevice to db $dbname is closed until $ro - $opt postponed"); - ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); - return; + ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); + return; } if ($opt =~ /dbvars|dbstatus|tableinfo|procinfo/) { return "Dump is running - try again later !" if($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; return "The operation \"$opt\" isn't available with database type $dbmodel" if ($dbmodel ne 'MYSQL'); - ReadingsSingleUpdateValue ($hash, "state", "running", 1); + ReadingsSingleUpdateValue ($hash, "state", "running", 1); DbRep_delread($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen $hash->{HELPER}{RUNNING_PID} = BlockingCall("dbmeta_DoParse", "$name|$opt", "dbmeta_ParseDone", $to, "DbRep_ParseAborted", $hash); @@ -998,7 +1001,7 @@ sub DbRep_Get { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; DbRep_delread($hash); ReadingsSingleUpdateValue ($hash, "state", "running", 1); - DbRep_getblockinginfo($hash); + DbRep_getblockinginfo($hash); } elsif ($opt eq "minTimestamp") { return "Dump is running - try again later !" if($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); @@ -1006,21 +1009,30 @@ sub DbRep_Get { DbRep_delread($hash); ReadingsSingleUpdateValue ($hash, "state", "running", 1); $hash->{HELPER}{IDRETRIES} = 3; # Anzahl wie oft versucht wird initiale Daten zu holen - $prop = $prop?$prop:''; - DbRep_firstconnect("$name|$opt|$prop|"); + $prop = $prop?$prop:''; + DbRep_firstconnect("$name|$opt|$prop|"); - } elsif ($opt =~ /dbValue/) { - return "get \"$opt\" needs at least an argument" if ( @a < 3 ); - my @cmd = @a; + } elsif ($opt =~ /sqlCmdBlocking|dbValue/) { + return qq{get "$opt" needs at least an argument} if ( @a < 3 ); + + if($opt eq "dbValue") { + Log3($name, 1, qq{$name - WARNING - the command "dbValue" is deprecated and will be removed soon. Please use "sqlCmdBlocking" instead.}); + } + + my @cmd = @a; shift @cmd; shift @cmd; - my $sqlcmd = join(" ",@cmd); - $sqlcmd =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; - $hash->{LASTCMD} = $sqlcmd?"$opt $sqlcmd":"$opt"; - if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($hash->{NAME}, "allowDeletion", undef)) { + + my $sqlcmd = join " ", @cmd; + $sqlcmd =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; + $hash->{LASTCMD} = $sqlcmd ? "$opt $sqlcmd" : "$opt"; + + if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($name, "allowDeletion", undef)) { return "Attribute 'allowDeletion = 1' is needed for command '$sqlcmd'. Use it with care !"; } - my ($err,$ret) = DbRep_dbValue($name,$sqlcmd); - return $err?$err:$ret; + + ReadingsSingleUpdateValue ($hash, "state", "running", 1); + + return DbRep_sqlCmdBlocking($name,$sqlcmd); } elsif ($opt eq "storedCredentials") { # Credentials abrufen @@ -1047,14 +1059,14 @@ sub DbRep_Get { ; } elsif ($opt =~ /versionNotes/) { - my $header = "Module release information
"; + my $header = "Module release information
"; my $header1 = "Helpful hints
"; - my %hs; + my %hs; - # Ausgabetabelle erstellen - my ($ret,$val0,$val1); + # Ausgabetabelle erstellen + my ($ret,$val0,$val1); my $i = 0; - + $ret = ""; # Hints @@ -1094,7 +1106,7 @@ sub DbRep_Get { $ret .= ""; $ret .= ""; } - + # Notes if(!$prop || $prop =~ /rel/) { $ret .= sprintf("
$header
"); @@ -1119,10 +1131,10 @@ sub DbRep_Get { $ret .= ""; $ret .= "
"; } - + $ret .= ""; - - return $ret; + + return $ret; } else { return "$getlist"; @@ -1149,38 +1161,38 @@ sub DbRep_Attr { my @agentnoattr = qw(aggregation allowDeletion autoForward - dumpDirLocal + dumpDirLocal reading readingNameMap readingPreventFromDel device - diffAccept - executeBeforeProc - executeAfterProc + diffAccept + executeBeforeProc + executeAfterProc expimpfile fastStart - ftpUse - ftpUser - ftpUseSSL - ftpDebug - ftpDir - ftpPassive - ftpPort - ftpPwd - ftpServer - ftpTimeout - dumpMemlimit - dumpComment - dumpSpeed - optimizeTablesBeforeDump + ftpUse + ftpUser + ftpUseSSL + ftpDebug + ftpDir + ftpPassive + ftpPort + ftpPwd + ftpServer + ftpTimeout + dumpMemlimit + dumpComment + dumpSpeed + optimizeTablesBeforeDump seqDoubletsVariance sqlCmdHistoryLength - timeYearPeriod + timeYearPeriod timestamp_begin timestamp_end timeDiffToNow timeOlderThan - sqlResultFormat + sqlResultFormat useAdminCredentials ); @@ -1190,7 +1202,7 @@ sub DbRep_Attr { } $do = 0 if($cmd eq "del"); my $val = ($do == 1 ? "disabled" : "initialized"); - ReadingsSingleUpdateValue ($hash, "state", $val, 1); + ReadingsSingleUpdateValue ($hash, "state", $val, 1); if ($do == 1) { my $dbh = $hash->{DBH}; $dbh->disconnect() if($dbh); @@ -1237,16 +1249,16 @@ sub DbRep_Attr { DbRep_setCmdFile($name."_sqlCmdList","",$hash); # Löschen der sql History Liste im DbRep-Keyfile } } - - if ($aName eq "userExitFn") { + + if ($aName eq "userExitFn") { if($cmd eq "set") { if(!$aVal) {return "Usage of $aName is wrong. The function has to be specified as \" [reading:value]\" ";} - my @a = split(/ /,$aVal,2); + my @a = split(/ /,$aVal,2); $hash->{HELPER}{USEREXITFN} = $a[0]; - $hash->{HELPER}{UEFN_REGEXP} = $a[1] if($a[1]); + $hash->{HELPER}{UEFN_REGEXP} = $a[1] if($a[1]); } else { delete $hash->{HELPER}{USEREXITFN} if($hash->{HELPER}{USEREXITFN}); - delete $hash->{HELPER}{UEFN_REGEXP} if($hash->{HELPER}{UEFN_REGEXP}); + delete $hash->{HELPER}{UEFN_REGEXP} if($hash->{HELPER}{UEFN_REGEXP}); } } @@ -1282,7 +1294,7 @@ sub DbRep_Attr { } if ($cmd eq "set") { - if ($aName =~ /valueFilter/) { + if ($aName =~ /valueFilter/) { eval { "Hallo" =~ m/$aVal/ }; return "Bad regexp: $@" if($@); } @@ -1302,7 +1314,7 @@ sub DbRep_Attr { } } - if ($aName =~ /seqDoubletsVariance/) { + if ($aName =~ /seqDoubletsVariance/) { my $edge = ""; if($aVal =~ /EDGE=/) { ($aVal,$edge) = split("EDGE=", $aVal); @@ -1315,24 +1327,24 @@ sub DbRep_Attr { unless (looks_like_number($varpos) && looks_like_number($varneg)) { return " The Value of $aName is not valid. Only figures are allowed (except \"EDGE\") !";} } - if ($aName eq "timeYearPeriod") { - # 06-01 02-28 + if ($aName eq "timeYearPeriod") { + # 06-01 02-28 unless ($aVal =~ /^(\d{2})-(\d{2}) (\d{2})-(\d{2})$/ ) - { return "The Value of \"$aName\" isn't valid. Set the account period as \"MM-DD MM-DD\".";} + { return "The Value of \"$aName\" isn't valid. Set the account period as \"MM-DD MM-DD\".";} my ($mm1, $dd1, $mm2, $dd2) = ($aVal =~ /^(\d{2})-(\d{2}) (\d{2})-(\d{2})$/); - my (undef,undef,undef,$mday,$mon,$year1,undef,undef,undef) = localtime(time); # Istzeit Ableitung - my $year2 = $year1; + my (undef,undef,undef,$mday,$mon,$year1,undef,undef,undef) = localtime(time); # Istzeit Ableitung + my $year2 = $year1; # a b c d # 06-01 02-28 , wenn c < a && $mon < a -> Jahr(a)-1, sonst Jahr(c)+1 - my $c = ($mon+1).$mday; - my $e = $mm2.$dd2; + my $c = ($mon+1).$mday; + my $e = $mm2.$dd2; if ($mm2 <= $mm1 && $c <= $e) { - $year1--; - } else { - $year2++; - } + $year1--; + } else { + $year2++; + } eval { my $t1 = timelocal(00, 00, 00, $dd1, $mm1-1, $year1-1900); - my $t2 = timelocal(00, 00, 00, $dd2, $mm2-1, $year2-1900); }; + my $t2 = timelocal(00, 00, 00, $dd2, $mm2-1, $year2-1900); }; if ($@) { my @l = split (/at/, $@); return " The Value of $aName is out of range - $l[0]"; @@ -1351,7 +1363,7 @@ sub DbRep_Attr { delete($attr{$name}{timeYearPeriod}) if ($attr{$name}{timeYearPeriod}); return undef; } - $aVal = DbRep_formatpicker($aVal); + $aVal = DbRep_formatpicker($aVal); unless ($aVal =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/) {return " The Value of $aName is not valid. Use format YYYY-MM-DD HH:MM:SS or one of \"current_[year|month|day|hour]_begin\",\"current_[year|month|day|hour]_end\", \"previous_[year|month|day|hour]_begin\", \"previous_[year|month|day|hour]_end\" !";} @@ -1367,41 +1379,41 @@ sub DbRep_Attr { delete($attr{$name}{timeOlderThan}) if ($attr{$name}{timeOlderThan}); delete($attr{$name}{timeYearPeriod}) if ($attr{$name}{timeYearPeriod}); } - if ($aName =~ /ftpTimeout|timeout|diffAccept/) { + if ($aName =~ /ftpTimeout|timeout|diffAccept/) { unless ($aVal =~ /^[0-9]+$/) { return " The Value of $aName is not valid. Use only figures 0-9 without decimal places !";} } - if ($aName eq "readingNameMap") { + if ($aName eq "readingNameMap") { unless ($aVal =~ m/^[A-Za-z\d_\.-]+$/) { return " Unsupported character in $aName found. Use only A-Z a-z _ . -";} } - if ($aName eq "timeDiffToNow") { + if ($aName eq "timeDiffToNow") { unless ($aVal =~ /^[0-9]+$/ || $aVal =~ /^\s*[ydhms]:([\d]+)\s*/ && $aVal !~ /.*,.*/ ) - { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"y:1 d:10 h:6 m:12 s:20\". Refer to commandref !";} + { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"y:1 d:10 h:6 m:12 s:20\". Refer to commandref !";} delete($attr{$name}{timestamp_begin}) if ($attr{$name}{timestamp_begin}); delete($attr{$name}{timestamp_end}) if ($attr{$name}{timestamp_end}); delete($attr{$name}{timeYearPeriod}) if ($attr{$name}{timeYearPeriod}); } - if ($aName eq "timeOlderThan") { + if ($aName eq "timeOlderThan") { unless ($aVal =~ /^[0-9]+$/ || $aVal =~ /^\s*[ydhms]:([\d]+)\s*/ && $aVal !~ /.*,.*/ ) - { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"y:1 d:10 h:6 m:12 s:20\". Refer to commandref !";} + { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"y:1 d:10 h:6 m:12 s:20\". Refer to commandref !";} delete($attr{$name}{timestamp_begin}) if ($attr{$name}{timestamp_begin}); delete($attr{$name}{timestamp_end}) if ($attr{$name}{timestamp_end}); delete($attr{$name}{timeYearPeriod}) if ($attr{$name}{timeYearPeriod}); } - if ($aName eq "dumpMemlimit" || $aName eq "dumpSpeed") { + if ($aName eq "dumpMemlimit" || $aName eq "dumpSpeed") { unless ($aVal =~ /^[0-9]+$/) { return "The Value of $aName is not valid. Use only figures 0-9 without decimal places.";} - my $dml = AttrVal($name, "dumpMemlimit", 100000); - my $ds = AttrVal($name, "dumpSpeed", 10000); - if($aName eq "dumpMemlimit") { - unless($aVal >= (10 * $ds)) {return "The Value of $aName has to be at least '10 x dumpSpeed' ! ";} - } - if($aName eq "dumpSpeed") { - unless($aVal <= ($dml / 10)) {return "The Value of $aName mustn't be greater than 'dumpMemlimit / 10' ! ";} - } + my $dml = AttrVal($name, "dumpMemlimit", 100000); + my $ds = AttrVal($name, "dumpSpeed", 10000); + if($aName eq "dumpMemlimit") { + unless($aVal >= (10 * $ds)) {return "The Value of $aName has to be at least '10 x dumpSpeed' ! ";} + } + if($aName eq "dumpSpeed") { + unless($aVal <= ($dml / 10)) {return "The Value of $aName mustn't be greater than 'dumpMemlimit / 10' ! ";} + } } - if ($aName eq "ftpUse") { + if ($aName eq "ftpUse") { delete($attr{$name}{ftpUseSSL}); } - if ($aName eq "ftpUseSSL") { + if ($aName eq "ftpUseSSL") { delete($attr{$name}{ftpUse}); } @@ -1411,14 +1423,14 @@ sub DbRep_Attr { "Make shure you have set them with command \"set $name adminCredentials \" before. ";} } - if ($aName eq "reading" || $aName eq "device") { + if ($aName eq "reading" || $aName eq "device") { if ($aVal !~ m/,/ && $dbmodel && $dbmodel ne 'SQLITE') { my $attrname = uc($aName); - my $mlen = $hash->{HELPER}{DBREPCOL}{$attrname}?$hash->{HELPER}{DBREPCOL}{$attrname}:$dbrep_col{$attrname}; - return "Length of \"$aName\" is too big. Maximum length for database type $dbmodel is $mlen" if(length($aVal) > $mlen); + my $mlen = $hash->{HELPER}{DBREPCOL}{$attrname}?$hash->{HELPER}{DBREPCOL}{$attrname}:$dbrep_col{$attrname}; + return "Length of \"$aName\" is too big. Maximum length for database type $dbmodel is $mlen" if(length($aVal) > $mlen); } } - } + } return; } @@ -1452,7 +1464,7 @@ sub DbRep_Notify { } if ($own_hash->{ROLE} eq "Agent") { - # wenn Rolle "Agent" Verbeitung von RENAMED Events + # wenn Rolle "Agent" Verbeitung von RENAMED Events next if ($event !~ /RENAMED/); my $strucChanged; @@ -1472,7 +1484,7 @@ sub DbRep_Notify { Log3 ($myName, 4, "DbRep Agent $myName - Evt RENAMED rec - old device: $evl[1], new device: $evl[2] -> start deviceRename in DB: $own_hash->{DATABASE} "); $own_hash->{HELPER}{OLDDEV} = $evl[1]; $own_hash->{HELPER}{NEWDEV} = $evl[2]; - $own_hash->{HELPER}{RENMODE} = "devren"; + $own_hash->{HELPER}{RENMODE} = "devren"; DbRep_Main($own_hash,"deviceRename"); # die Attribute "device" in allen DbRep-Devices mit der Datenbank = DB des Agenten von alten Device in neues Device ändern @@ -1576,12 +1588,12 @@ sub DbRep_firstconnect { } # DB Struktur aus DbLog Instanz übernehmen $hash->{HELPER}{DBREPCOL}{COLSET} = $dbloghash->{HELPER}{COLSET}; - $hash->{HELPER}{DBREPCOL}{DEVICE} = $dbloghash->{HELPER}{DEVICECOL}; - $hash->{HELPER}{DBREPCOL}{TYPE} = $dbloghash->{HELPER}{TYPECOL}; - $hash->{HELPER}{DBREPCOL}{EVENT} = $dbloghash->{HELPER}{EVENTCOL}; - $hash->{HELPER}{DBREPCOL}{READING} = $dbloghash->{HELPER}{READINGCOL}; - $hash->{HELPER}{DBREPCOL}{VALUE} = $dbloghash->{HELPER}{VALUECOL}; - $hash->{HELPER}{DBREPCOL}{UNIT} = $dbloghash->{HELPER}{UNITCOL}; + $hash->{HELPER}{DBREPCOL}{DEVICE} = $dbloghash->{HELPER}{DEVICECOL}; + $hash->{HELPER}{DBREPCOL}{TYPE} = $dbloghash->{HELPER}{TYPECOL}; + $hash->{HELPER}{DBREPCOL}{EVENT} = $dbloghash->{HELPER}{EVENTCOL}; + $hash->{HELPER}{DBREPCOL}{READING} = $dbloghash->{HELPER}{READINGCOL}; + $hash->{HELPER}{DBREPCOL}{VALUE} = $dbloghash->{HELPER}{VALUECOL}; + $hash->{HELPER}{DBREPCOL}{UNIT} = $dbloghash->{HELPER}{UNITCOL}; # DB Strukturelemente abrufen Log3 ($name, 3, "DbRep $name - Connectiontest to database $dbconn with user $dbuser") if($hash->{LASTCMD} ne "minTimestamp"); @@ -1617,8 +1629,8 @@ sub DbRep_getInitData { ($err,$dbh) = DbRep_dbConnect($name,0); if ($err) { - $err = encode_base64($err,""); - return "$name|''|''|$err"; + $err = encode_base64($err,""); + return "$name|''|''|$err"; } # SQL-Startzeit @@ -1793,7 +1805,7 @@ sub DbRep_dbConnect { } else { $err = "Can't use admin credentials for database access, see logfile !"; Log3 ($name, 2, "DbRep $name - ERROR - admin credentials are needed for database operation, but are not set or can't read it"); - return $err; + return $err; } } @@ -1842,19 +1854,19 @@ sub DbRep_Main { # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen DbRep_delread($hash); - if ($opt =~ /dumpMySQL|dumpSQLite/) { + if ($opt =~ /dumpMySQL|dumpSQLite/) { BlockingKill($hash->{HELPER}{RUNNING_BACKUP_CLIENT}) if (exists($hash->{HELPER}{RUNNING_BACKUP_CLIENT})); BlockingKill($hash->{HELPER}{RUNNING_BCKPREST_SERVER}) if (exists($hash->{HELPER}{RUNNING_BCKPREST_SERVER})); - BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); + BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); if($dbmodel =~ /MYSQL/) { - if ($prop eq "serverSide") { - $hash->{HELPER}{RUNNING_BCKPREST_SERVER} = BlockingCall("mysql_DoDumpServerSide", "$name", "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "serverSide Dump is running - be patient and see Logfile !", 1); - } else { - $hash->{HELPER}{RUNNING_BACKUP_CLIENT} = BlockingCall("mysql_DoDumpClientSide", "$name", "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "clientSide Dump is running - be patient and see Logfile !", 1); - } + if ($prop eq "serverSide") { + $hash->{HELPER}{RUNNING_BCKPREST_SERVER} = BlockingCall("mysql_DoDumpServerSide", "$name", "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); + ReadingsSingleUpdateValue ($hash, "state", "serverSide Dump is running - be patient and see Logfile !", 1); + } else { + $hash->{HELPER}{RUNNING_BACKUP_CLIENT} = BlockingCall("mysql_DoDumpClientSide", "$name", "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); + ReadingsSingleUpdateValue ($hash, "state", "clientSide Dump is running - be patient and see Logfile !", 1); + } } if($dbmodel =~ /SQLITE/) { $hash->{HELPER}{RUNNING_BACKUP_CLIENT} = BlockingCall("DbRep_sqliteDoDump", "$name", "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); @@ -1863,13 +1875,13 @@ sub DbRep_Main { return; } - if ($opt =~ /restoreMySQL/) { + if ($opt =~ /restoreMySQL/) { BlockingKill($hash->{HELPER}{RUNNING_RESTORE}) if (exists($hash->{HELPER}{RUNNING_RESTORE})); BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); if($prop =~ /csv/) { $hash->{HELPER}{RUNNING_RESTORE} = BlockingCall("mysql_RestoreServerSide", "$name|$prop", "DbRep_restoreDone", $to, "DbRep_restoreAborted", $hash); - } elsif ($prop =~ /sql/) { + } elsif ($prop =~ /sql/) { $hash->{HELPER}{RUNNING_RESTORE} = BlockingCall("mysql_RestoreClientSide", "$name|$prop", "DbRep_restoreDone", $to, "DbRep_restoreAborted", $hash); } else { ReadingsSingleUpdateValue ($hash, "state", "restore database error - unknown fileextension \"$prop\"", 1); @@ -1879,39 +1891,39 @@ sub DbRep_Main { return; } - if ($opt =~ /restoreSQLite/) { + if ($opt =~ /restoreSQLite/) { BlockingKill($hash->{HELPER}{RUNNING_RESTORE}) if (exists($hash->{HELPER}{RUNNING_RESTORE})); BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); $hash->{HELPER}{RUNNING_RESTORE} = BlockingCall("DbRep_sqliteRestore", "$name|$prop", "DbRep_restoreDone", $to, "DbRep_restoreAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "restore database is running - be patient and see Logfile !", 1); + ReadingsSingleUpdateValue ($hash, "state", "restore database is running - be patient and see Logfile !", 1); return; } - if ($opt =~ /optimizeTables|vacuum/) { + if ($opt =~ /optimizeTables|vacuum/) { BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); BlockingKill($hash->{HELPER}{RUNNING_RESTORE}) if (exists($hash->{HELPER}{RUNNING_RESTORE})); $hash->{HELPER}{RUNNING_OPTIMIZE} = BlockingCall("DbRep_optimizeTables", "$name", "DbRep_OptimizeDone", $to, "DbRep_OptimizeAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "optimize tables is running - be patient and see Logfile !", 1); + ReadingsSingleUpdateValue ($hash, "state", "optimize tables is running - be patient and see Logfile !", 1); return; } - if ($opt =~ /repairSQLite/) { + if ($opt =~ /repairSQLite/) { BlockingKill($hash->{HELPER}{RUNNING_BACKUP_CLIENT}) if (exists($hash->{HELPER}{RUNNING_BACKUP_CLIENT})); BlockingKill($hash->{HELPER}{RUNNING_OPTIMIZE}) if (exists($hash->{HELPER}{RUNNING_OPTIMIZE})); BlockingKill($hash->{HELPER}{RUNNING_REPAIR}) if (exists($hash->{HELPER}{RUNNING_REPAIR})); $hash->{HELPER}{RUNNING_REPAIR} = BlockingCall("DbRep_sqliteRepair", "$name", "DbRep_RepairDone", $to, "DbRep_RepairAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "repair database is running - be patient and see Logfile !", 1); + ReadingsSingleUpdateValue ($hash, "state", "repair database is running - be patient and see Logfile !", 1); return; } - if ($opt =~ /index/) { + if ($opt =~ /index/) { if (exists($hash->{HELPER}{RUNNING_INDEX})) { Log3 ($name, 3, "DbRep $name - WARNING - old process $hash->{HELPER}{RUNNING_INDEX}{pid} will be killed now to start a new index operation"); BlockingKill($hash->{HELPER}{RUNNING_INDEX}); } Log3 ($name, 3, "DbRep $name - Command: $opt $prop"); $hash->{HELPER}{RUNNING_INDEX} = BlockingCall("DbRep_Index", "$name|$prop", "DbRep_IndexDone", $to, "DbRep_IndexAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "index operation in database is running - be patient and see Logfile !", 1); + ReadingsSingleUpdateValue ($hash, "state", "index operation in database is running - be patient and see Logfile !", 1); $hash->{HELPER}{RUNNING_INDEX}{loglevel} = 5 if($hash->{HELPER}{RUNNING_INDEX}); # Forum #77057 return; } @@ -1959,11 +1971,11 @@ sub DbRep_Main { ############################# if ($opt eq "sumValue") { $hash->{HELPER}{RUNNING_PID} = BlockingCall("sumval_DoParse", "$name§$device§$reading§$prop§$ts", "sumval_ParseDone", $to, "DbRep_ParseAborted", $hash); - + } elsif ($opt =~ m/countEntries/) { my $table = $prop; $hash->{HELPER}{RUNNING_PID} = BlockingCall("count_DoParse", "$name§$table§$device§$reading§$ts", "count_ParseDone", $to, "DbRep_ParseAborted", $hash); - + } elsif ($opt eq "averageValue") { Log3 ($name, 4, "DbRep $name - averageValue calculation sceme: ".AttrVal($name,"averageCalcForm","avgArithmeticMean")); $hash->{HELPER}{RUNNING_PID} = BlockingCall("averval_DoParse", "$name§$device§$reading§$prop§$ts", "averval_ParseDone", $to, "DbRep_ParseAborted", $hash); @@ -2022,13 +2034,13 @@ sub DbRep_Main { $hash->{HELPER}{RUNNING_PID} = BlockingCall("diffval_DoParse", "$name§$device§$reading§$prop§$ts", "diffval_ParseDone", $to, "DbRep_ParseAborted", $hash); } elsif ($opt eq "insert") { - # Daten auf maximale Länge (entsprechend der Feldlänge in DbLog) beschneiden wenn nicht SQLite - if ($dbmodel ne 'SQLITE') { - $hash->{HELPER}{I_DEVICE} = substr($hash->{HELPER}{I_DEVICE},0, $hash->{HELPER}{DBREPCOL}{DEVICE}); - $hash->{HELPER}{I_READING} = substr($hash->{HELPER}{I_READING},0, $hash->{HELPER}{DBREPCOL}{READING}); - $hash->{HELPER}{I_VALUE} = substr($hash->{HELPER}{I_VALUE},0, $hash->{HELPER}{DBREPCOL}{VALUE}); - $hash->{HELPER}{I_UNIT} = substr($hash->{HELPER}{I_UNIT},0, $hash->{HELPER}{DBREPCOL}{UNIT}) if($hash->{HELPER}{I_UNIT}); - } + # Daten auf maximale Länge (entsprechend der Feldlänge in DbLog) beschneiden wenn nicht SQLite + if ($dbmodel ne 'SQLITE') { + $hash->{HELPER}{I_DEVICE} = substr($hash->{HELPER}{I_DEVICE},0, $hash->{HELPER}{DBREPCOL}{DEVICE}); + $hash->{HELPER}{I_READING} = substr($hash->{HELPER}{I_READING},0, $hash->{HELPER}{DBREPCOL}{READING}); + $hash->{HELPER}{I_VALUE} = substr($hash->{HELPER}{I_VALUE},0, $hash->{HELPER}{DBREPCOL}{VALUE}); + $hash->{HELPER}{I_UNIT} = substr($hash->{HELPER}{I_UNIT},0, $hash->{HELPER}{DBREPCOL}{UNIT}) if($hash->{HELPER}{I_UNIT}); + } $hash->{HELPER}{RUNNING_PID} = BlockingCall("insert_Push", "$name", "insert_Done", $to, "DbRep_ParseAborted", $hash); } elsif ($opt =~ /deviceRename|readingRename/) { @@ -2104,11 +2116,11 @@ sub DbRep_Main { my $nthants = timelocal($sec1, $min1, $hh1, $dd1, $mm1-1, $yyyy1-1900); my $othants = timelocal($sec2, $min2, $hh2, $dd2, $mm2-1, $yyyy2-1900); if($nthants > $othants) { - ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The (days newer than) option must be greater than the (older than) one !", 1); + ReadingsSingleUpdateValue ($hash, "state", "Error - Wrong time limits. The (days newer than) option must be greater than the (older than) one !", 1); return; - } + } $hash->{HELPER}{RUNNING_REDUCELOG} = BlockingCall("DbRep_reduceLog", "$name|$device|$reading|$runtime_string_first|$runtime_string_next", "DbRep_reduceLogDone", $to, "DbRep_reduceLogAborted", $hash); - ReadingsSingleUpdateValue ($hash, "state", "reduceLog database is running - be patient and see Logfile !", 1); + ReadingsSingleUpdateValue ($hash, "state", "reduceLog database is running - be patient and see Logfile !", 1); $hash->{HELPER}{RUNNING_REDUCELOG}{loglevel} = 5 if($hash->{HELPER}{RUNNING_REDUCELOG}); # Forum #77057 return; } @@ -2148,138 +2160,138 @@ sub DbRep_createTimeArray { if ( my $tap = AttrVal($name, "timeYearPeriod", undef)) { # a b c d # 06-01 02-28 , wenn c < a && $mon < a -> Jahr(a)-1, sonst Jahr(c)+1 - my $ybp = $year+1900; + my $ybp = $year+1900; my $yep = $year+1900; - $tap =~ qr/^(\d{2})-(\d{2}) (\d{2})-(\d{2})$/p; - my $mbp = $1; - my $dbp = $2; - my $mep = $3; - my $dep = $4; - my $c = ($mon+1).$mday; - my $e = $mep.$dep; + $tap =~ qr/^(\d{2})-(\d{2}) (\d{2})-(\d{2})$/p; + my $mbp = $1; + my $dbp = $2; + my $mep = $3; + my $dep = $4; + my $c = ($mon+1).$mday; + my $e = $mep.$dep; if ($mep <= $mbp && $c <= $e) { - $ybp--; - } else { - $yep++; - } - $tsbegin = "$ybp-$mbp-$dbp 00:00:00"; - $tsend = "$yep-$mep-$dep 23:59:59"; + $ybp--; + } else { + $yep++; + } + $tsbegin = "$ybp-$mbp-$dbp 00:00:00"; + $tsend = "$yep-$mep-$dep 23:59:59"; } if (AttrVal($name,"timestamp_begin","") eq "current_year_begin" || AttrVal($name,"timestamp_end","") eq "current_year_begin") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year)) if(AttrVal($name,"timestamp_begin","") eq "current_year_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year)) if(AttrVal($name,"timestamp_end","") eq "current_year_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year)) if(AttrVal($name,"timestamp_end","") eq "current_year_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "current_year_end" || AttrVal($name, "timestamp_end", "") eq "current_year_end") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year)) if(AttrVal($name,"timestamp_begin","") eq "current_year_end"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year)) if(AttrVal($name,"timestamp_end","") eq "current_year_end"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year)) if(AttrVal($name,"timestamp_end","") eq "current_year_end"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_year_begin" || AttrVal($name, "timestamp_end", "") eq "previous_year_begin") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year-1)) if(AttrVal($name, "timestamp_begin", "") eq "previous_year_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year-1)) if(AttrVal($name, "timestamp_end", "") eq "previous_year_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,0,$year-1)) if(AttrVal($name, "timestamp_end", "") eq "previous_year_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_year_end" || AttrVal($name, "timestamp_end", "") eq "previous_year_end") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year-1)) if(AttrVal($name, "timestamp_begin", "") eq "previous_year_end"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year-1)) if(AttrVal($name, "timestamp_end", "") eq "previous_year_end"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,31,11,$year-1)) if(AttrVal($name, "timestamp_end", "") eq "previous_year_end"); } if (AttrVal($name, "timestamp_begin", "") eq "current_month_begin" || AttrVal($name, "timestamp_end", "") eq "current_month_begin") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_month_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_month_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_month_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "current_month_end" || AttrVal($name, "timestamp_end", "") eq "current_month_end") { $dim = $mon-1?30+(($mon+1)*3%7<4):28+!($year%4||$year%400*!($year%100)); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_month_end"); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_month_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_month_end"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_month_begin" || AttrVal($name, "timestamp_end", "") eq "previous_month_begin") { $ryear = ($mon-1<0)?$year-1:$year; - $rmon = ($mon-1<0)?11:$mon-1; + $rmon = ($mon-1<0)?11:$mon-1; $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_month_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_month_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,1,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_month_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_month_end" || AttrVal($name, "timestamp_end", "") eq "previous_month_end") { $ryear = ($mon-1<0)?$year-1:$year; - $rmon = ($mon-1<0)?11:$mon-1; - $dim = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_month_end"); + $rmon = ($mon-1<0)?11:$mon-1; + $dim = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_month_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$dim,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_month_end"); } if (AttrVal($name, "timestamp_begin", "") eq "current_week_begin" || AttrVal($name, "timestamp_end", "") eq "current_week_begin") { - $tsub = 0 if($wday == 1); # wenn Start am "Mo" keine Korrektur - $tsub = 86400 if($wday == 2); # wenn Start am "Di" dann Korrektur -1 Tage - $tsub = 172800 if($wday == 3); # wenn Start am "Mi" dann Korrektur -2 Tage - $tsub = 259200 if($wday == 4); # wenn Start am "Do" dann Korrektur -3 Tage - $tsub = 345600 if($wday == 5); # wenn Start am "Fr" dann Korrektur -4 Tage - $tsub = 432000 if($wday == 6); # wenn Start am "Sa" dann Korrektur -5 Tage - $tsub = 518400 if($wday == 0); # wenn Start am "So" dann Korrektur -6 Tage - ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "current_week_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "current_week_begin"); + $tsub = 0 if($wday == 1); # wenn Start am "Mo" keine Korrektur + $tsub = 86400 if($wday == 2); # wenn Start am "Di" dann Korrektur -1 Tage + $tsub = 172800 if($wday == 3); # wenn Start am "Mi" dann Korrektur -2 Tage + $tsub = 259200 if($wday == 4); # wenn Start am "Do" dann Korrektur -3 Tage + $tsub = 345600 if($wday == 5); # wenn Start am "Fr" dann Korrektur -4 Tage + $tsub = 432000 if($wday == 6); # wenn Start am "Sa" dann Korrektur -5 Tage + $tsub = 518400 if($wday == 0); # wenn Start am "So" dann Korrektur -6 Tage + ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "current_week_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "current_week_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "current_week_end" || AttrVal($name, "timestamp_end", "") eq "current_week_end") { - $tadd = 518400 if($wday == 1); # wenn Start am "Mo" dann Korrektur +6 Tage - $tadd = 432000 if($wday == 2); # wenn Start am "Di" dann Korrektur +5 Tage - $tadd = 345600 if($wday == 3); # wenn Start am "Mi" dann Korrektur +4 Tage - $tadd = 259200 if($wday == 4); # wenn Start am "Do" dann Korrektur +3 Tage - $tadd = 172800 if($wday == 5); # wenn Start am "Fr" dann Korrektur +2 Tage - $tadd = 86400 if($wday == 6); # wenn Start am "Sa" dann Korrektur +1 Tage - $tadd = 0 if($wday == 0); # wenn Start am "So" keine Korrektur - ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time+$tadd); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "current_week_end"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "current_week_end"); + $tadd = 518400 if($wday == 1); # wenn Start am "Mo" dann Korrektur +6 Tage + $tadd = 432000 if($wday == 2); # wenn Start am "Di" dann Korrektur +5 Tage + $tadd = 345600 if($wday == 3); # wenn Start am "Mi" dann Korrektur +4 Tage + $tadd = 259200 if($wday == 4); # wenn Start am "Do" dann Korrektur +3 Tage + $tadd = 172800 if($wday == 5); # wenn Start am "Fr" dann Korrektur +2 Tage + $tadd = 86400 if($wday == 6); # wenn Start am "Sa" dann Korrektur +1 Tage + $tadd = 0 if($wday == 0); # wenn Start am "So" keine Korrektur + ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time+$tadd); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "current_week_end"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "current_week_end"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_week_begin" || AttrVal($name, "timestamp_end", "") eq "previous_week_begin") { - $tsub = 604800 if($wday == 1); # wenn Start am "Mo" dann Korrektur -7 Tage - $tsub = 691200 if($wday == 2); # wenn Start am "Di" dann Korrektur -8 Tage - $tsub = 777600 if($wday == 3); # wenn Start am "Mi" dann Korrektur -9 Tage - $tsub = 864000 if($wday == 4); # wenn Start am "Do" dann Korrektur -10 Tage - $tsub = 950400 if($wday == 5); # wenn Start am "Fr" dann Korrektur -11 Tage - $tsub = 1036800 if($wday == 6); # wenn Start am "Sa" dann Korrektur -12 Tage - $tsub = 1123200 if($wday == 0); # wenn Start am "So" dann Korrektur -13 Tage - ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_week_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_week_begin"); + $tsub = 604800 if($wday == 1); # wenn Start am "Mo" dann Korrektur -7 Tage + $tsub = 691200 if($wday == 2); # wenn Start am "Di" dann Korrektur -8 Tage + $tsub = 777600 if($wday == 3); # wenn Start am "Mi" dann Korrektur -9 Tage + $tsub = 864000 if($wday == 4); # wenn Start am "Do" dann Korrektur -10 Tage + $tsub = 950400 if($wday == 5); # wenn Start am "Fr" dann Korrektur -11 Tage + $tsub = 1036800 if($wday == 6); # wenn Start am "Sa" dann Korrektur -12 Tage + $tsub = 1123200 if($wday == 0); # wenn Start am "So" dann Korrektur -13 Tage + ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_week_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_week_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_week_end" || AttrVal($name, "timestamp_end", "") eq "previous_week_end") { - $tsub = 86400 if($wday == 1); # wenn Start am "Mo" dann Korrektur -1 Tage - $tsub = 172800 if($wday == 2); # wenn Start am "Di" dann Korrektur -2 Tage - $tsub = 259200 if($wday == 3); # wenn Start am "Mi" dann Korrektur -3 Tage - $tsub = 345600 if($wday == 4); # wenn Start am "Do" dann Korrektur -4 Tage - $tsub = 432000 if($wday == 5); # wenn Start am "Fr" dann Korrektur -5 Tage - $tsub = 518400 if($wday == 6); # wenn Start am "Sa" dann Korrektur -6 Tage - $tsub = 604800 if($wday == 0); # wenn Start am "So" dann Korrektur -7 Tage - ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_week_end"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_week_end"); + $tsub = 86400 if($wday == 1); # wenn Start am "Mo" dann Korrektur -1 Tage + $tsub = 172800 if($wday == 2); # wenn Start am "Di" dann Korrektur -2 Tage + $tsub = 259200 if($wday == 3); # wenn Start am "Mi" dann Korrektur -3 Tage + $tsub = 345600 if($wday == 4); # wenn Start am "Do" dann Korrektur -4 Tage + $tsub = 432000 if($wday == 5); # wenn Start am "Fr" dann Korrektur -5 Tage + $tsub = 518400 if($wday == 6); # wenn Start am "Sa" dann Korrektur -6 Tage + $tsub = 604800 if($wday == 0); # wenn Start am "So" dann Korrektur -7 Tage + ($rsec,$rmin,$rhour,$rmday,$rmon,$ryear) = localtime(time-$tsub); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_week_end"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_week_end"); } if (AttrVal($name, "timestamp_begin", "") eq "current_day_begin" || AttrVal($name, "timestamp_end", "") eq "current_day_begin") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$mday,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_day_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$mday,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_day_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$mday,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_day_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "current_day_end" || @@ -2290,34 +2302,34 @@ sub DbRep_createTimeArray { if (AttrVal($name, "timestamp_begin", "") eq "previous_day_begin" || AttrVal($name, "timestamp_end", "") eq "previous_day_begin") { - $rmday = $mday-1; - $rmon = $mon; - $ryear = $year; - if($rmday<1) { - $rmon--; - if ($rmon<0) { - $rmon=11; - $ryear--; - } + $rmday = $mday-1; + $rmon = $mon; + $ryear = $year; + if($rmday<1) { + $rmon--; + if ($rmon<0) { + $rmon=11; + $ryear--; + } $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) - } + } $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_day_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_day_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,0,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_day_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_day_end" || AttrVal($name, "timestamp_end", "") eq "previous_day_end") { - $rmday = $mday-1; - $rmon = $mon; - $ryear = $year; - if($rmday<1) { - $rmon--; - if ($rmon<0) { - $rmon=11; - $ryear--; - } + $rmday = $mday-1; + $rmon = $mon; + $ryear = $year; + if($rmday<1) { + $rmon--; + if ($rmon<0) { + $rmon=11; + $ryear--; + } $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) - } + } $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_day_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,23,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_day_end"); } @@ -2325,56 +2337,56 @@ sub DbRep_createTimeArray { if (AttrVal($name, "timestamp_begin", "") eq "current_hour_begin" || AttrVal($name, "timestamp_end", "") eq "current_hour_begin") { $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_hour_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_hour_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_hour_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "current_hour_end" || AttrVal($name, "timestamp_end", "") eq "current_hour_end") { - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_hour_end"); + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_begin", "") eq "current_hour_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$hour,$mday,$mon,$year)) if(AttrVal($name, "timestamp_end", "") eq "current_hour_end"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_hour_begin" || AttrVal($name, "timestamp_end", "") eq "previous_hour_begin") { $rhour = $hour-1; - $rmday = $mday; - $rmon = $mon; - $ryear = $year; - if($rhour<0) { - $rhour = 23; - $rmday = $mday-1; - if($rmday<1) { - $rmon--; - if ($rmon<0) { - $rmon=11; - $ryear--; - } - $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) - } - } + $rmday = $mday; + $rmon = $mon; + $ryear = $year; + if($rhour<0) { + $rhour = 23; + $rmday = $mday-1; + if($rmday<1) { + $rmon--; + if ($rmon<0) { + $rmon=11; + $ryear--; + } + $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) + } + } $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_hour_begin"); - $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_begin"); + $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(0,0,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_begin"); } if (AttrVal($name, "timestamp_begin", "") eq "previous_hour_end" || AttrVal($name, "timestamp_end", "") eq "previous_hour_end") { $rhour = $hour-1; - $rmday = $mday; - $rmon = $mon; - $ryear = $year; - if($rhour<0) { - $rhour = 23; - $rmday = $mday-1; - if($rmday<1) { - $rmon--; - if ($rmon<0) { - $rmon=11; - $ryear--; - } - $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) - } - } - $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_hour_end"); + $rmday = $mday; + $rmon = $mon; + $ryear = $year; + if($rhour<0) { + $rhour = 23; + $rmday = $mday-1; + if($rmday<1) { + $rmon--; + if ($rmon<0) { + $rmon=11; + $ryear--; + } + $rmday = $rmon-1?30+(($rmon+1)*3%7<4):28+!($ryear%4||$ryear%400*!($ryear%100)); # Achtung: Monat als 1...12 (statt 0...11) + } + } + $tsbegin = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_begin", "") eq "previous_hour_end"); $tsend = strftime "%Y-%m-%d %T",localtime(timelocal(59,59,$rhour,$rmday,$rmon,$ryear)) if(AttrVal($name, "timestamp_end", "") eq "previous_hour_end"); } @@ -2400,7 +2412,7 @@ sub DbRep_createTimeArray { if($fdopt) { # FullDay Option ist gesetzt my $tbs = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin); $tbs =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/; - $epoch_seconds_begin = timelocal(00, 00, 00, $3, $2-1, $1-1900); + $epoch_seconds_begin = timelocal(00, 00, 00, $3, $2-1, $1-1900); } my $tsbegin_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_begin); @@ -2420,7 +2432,7 @@ sub DbRep_createTimeArray { if($fdopt) { # FullDay Option ist gesetzt my $tes = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end); $tes =~ /^(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)$/; - $epoch_seconds_end = timelocal(59, 59, 23, $3, $2-1, $1-1900); + $epoch_seconds_end = timelocal(59, 59, 23, $3, $2-1, $1-1900); } my $tsend_string = strftime "%Y-%m-%d %H:%M:%S", localtime($epoch_seconds_end); @@ -2815,7 +2827,7 @@ sub averval_DoParse { $selspec = "TIMESTAMP,VALUE"; $qlf = "avgtwm"; } - + # SQL-Startzeit my $st = [gettimeofday]; @@ -2832,21 +2844,21 @@ sub averval_DoParse { # if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); - } else { - $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); - } + } else { + $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; - if ($@) { + }; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|$device|$reading|''|$err|''"; } - + my @line = $sth->fetchrow_array(); Log3 ($name, 5, "DbRep $name - SQL result: $line[0]") if($line[0]); @@ -2885,13 +2897,13 @@ sub averval_DoParse { my $bsel = $bdate." ".sprintf("%02d",$i).":00:00"; my $esel = ($i<23)?$bdate." ".sprintf("%02d",$i).":59:59":$runtime_string_next; - $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$bsel'","'$esel'",$addon); + $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$bsel'","'$esel'",$addon); Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; - if ($@) { + }; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; @@ -2899,7 +2911,7 @@ sub averval_DoParse { } my $val = $sth->fetchrow_array(); Log3 ($name, 5, "DbRep $name - SQL result: $val") if($val); - $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren + $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren if(defined($val) && looks_like_number($val)) { $sum += $val; $t01 = $val if($val && $i == 00); # Wert f. Stunde 01 ist zw. letzter Wert vor 01 @@ -2959,7 +2971,7 @@ sub averval_DoParse { eval { $tf = ($dbh->selectrow_array($sqlf))[0]; $tl = ($dbh->selectrow_array($sqll))[0]; }; - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; @@ -2976,14 +2988,14 @@ sub averval_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); - } else { - $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); - } + } else { + $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -2995,7 +3007,7 @@ sub averval_DoParse { foreach my $twmrow (@twm_array) { ($tn,$val) = split("_ESC_",$twmrow); - $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren + $val = DbRep_numval ($val); # nichtnumerische Zeichen eliminieren my ($yyyyt1, $mmt1, $ddt1, $hht1, $mint1, $sect1) = ($tn =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/); $tn = timelocal($sect1, $mint1, $hht1, $ddt1, $mmt1-1, $yyyyt1-1900); if(!$to) { @@ -3124,7 +3136,7 @@ sub averval_ParseDone { $reading_runtime_string = $rsf.$ds.$rds."AVG".$acf."__".$runtime_string; } if($acf eq "DMGWS") { - ReadingsBulkUpdateValue ($hash, $reading_runtime_string, looks_like_number($c)?sprintf("%.1f",$c):$c); + ReadingsBulkUpdateValue ($hash, $reading_runtime_string, looks_like_number($c)?sprintf("%.1f",$c):$c); } else { ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c?sprintf("%.4f",$c):"-"); } @@ -3203,14 +3215,14 @@ sub count_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); - } else { - $sql = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,undef,undef,$addon); - } + } else { + $sql = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,undef,undef,$addon); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -3307,7 +3319,7 @@ sub count_ParseDone { } } - ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c?$c:"-"); + ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c?$c:"-"); } ReadingsBulkUpdateTimeState($hash,$brt,$rt,"done"); @@ -3366,14 +3378,14 @@ sub maxval_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,"'$runtime_string_first'","'$runtime_string_next'","ORDER BY TIMESTAMP"); - } else { - $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,undef,undef,"ORDER BY TIMESTAMP"); - } + } else { + $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,undef,undef,"ORDER BY TIMESTAMP"); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -3614,14 +3626,14 @@ sub minval_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,"'$runtime_string_first'","'$runtime_string_next'","ORDER BY TIMESTAMP"); - } else { - $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,undef,undef,"ORDER BY TIMESTAMP"); - } + } else { + $sql = DbRep_createSelectSql($hash,"history","VALUE,TIMESTAMP",$device,$reading,undef,undef,"ORDER BY TIMESTAMP"); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -3801,7 +3813,7 @@ sub minval_ParseDone { $reading_runtime_string = $rsf.$ds.$rds."MIN__".$k[0]; } my $rv = $k[1]; - + ReadingsBulkUpdateValue ($hash, $reading_runtime_string, defined($rv)?sprintf("%.4f",$rv):"-"); } @@ -3870,59 +3882,59 @@ sub diffval_DoParse { my $runtime_string_next = $a[2]; $runtime_string = encode_base64($runtime_string,""); - if($dbmodel eq "MYSQL") { - eval {$dbh->do("set \@V:= 0, \@diff:= 0, \@diffTotal:= 0, \@RB:= 1;");}; # @\RB = Resetbit wenn neues Selektionsintervall beginnt + if($dbmodel eq "MYSQL") { + eval {$dbh->do("set \@V:= 0, \@diff:= 0, \@diffTotal:= 0, \@RB:= 1;");}; # @\RB = Resetbit wenn neues Selektionsintervall beginnt } - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|$device|$reading|''|''|''|$err|''"; } - + if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",'ORDER BY TIMESTAMP'); - } else { - $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,'ORDER BY TIMESTAMP'); - } + } else { + $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,'ORDER BY TIMESTAMP'); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|$device|$reading|''|''|''|$err|''"; - } else { - if($dbmodel eq "MYSQL") { - @array = map { $runtime_string." ".$_ -> [0]." ".$_ -> [1]." ".$_ -> [2]."\n" } @{ $sth->fetchall_arrayref() }; + } else { + if($dbmodel eq "MYSQL") { + @array = map { $runtime_string." ".$_ -> [0]." ".$_ -> [1]." ".$_ -> [2]."\n" } @{ $sth->fetchall_arrayref() }; } else { - @array = map { $runtime_string." ".$_ -> [0]." ".$_ -> [1]."\n" } @{ $sth->fetchall_arrayref() }; + @array = map { $runtime_string." ".$_ -> [0]." ".$_ -> [1]."\n" } @{ $sth->fetchall_arrayref() }; - if (@array) { - my @sp; - my $dse = 0; - my $vold; - my @sqlite_array; + if (@array) { + my @sp; + my $dse = 0; + my $vold; + my @sqlite_array; foreach my $row (@array) { @sp = split("[ \t][ \t]*", $row, 4); my $runtime_string = $sp[0]; - my $timestamp = $sp[2]?$sp[1]." ".$sp[2]:$sp[1]; + my $timestamp = $sp[2]?$sp[1]." ".$sp[2]:$sp[1]; my $vnew = $sp[3]; - $vnew =~ tr/\n//d; + $vnew =~ tr/\n//d; - $dse = ($vold && (($vnew-$vold) > 0))?($vnew-$vold):0; - @sp = $runtime_string." ".$timestamp." ".$vnew." ".$dse."\n"; - $vold = $vnew; + $dse = ($vold && (($vnew-$vold) > 0))?($vnew-$vold):0; + @sp = $runtime_string." ".$timestamp." ".$vnew." ".$dse."\n"; + $vold = $vnew; push(@sqlite_array, @sp); } - @array = @sqlite_array; - } - } - + @array = @sqlite_array; + } + } + if(!@array) { my $aval = AttrVal($name, "aggregation", ""); if($aval eq "hour") { @@ -3986,49 +3998,49 @@ sub diffval_DoParse { Log3 ($name, 5, "DbRep $name - Runtimestring: $runtime_string, DEVICE: $device, READING: $reading, \nTIMESTAMP: $timestamp, VALUE: $value, DIFF: $diff"); - # String ignorierter Zeilen erzeugen - $diff_current = $timestamp." ".$diff; - if($diff > $difflimit) { - $rejectstr .= $diff_before." -> ".$diff_current."\n"; - } - $diff_before = $diff_current; - - # Ergebnishash erzeugen + # String ignorierter Zeilen erzeugen + $diff_current = $timestamp." ".$diff; + if($diff > $difflimit) { + $rejectstr .= $diff_before." -> ".$diff_current."\n"; + } + $diff_before = $diff_current; + + # Ergebnishash erzeugen if ($runtime_string eq $lastruntimestring) { if ($i == 1) { - $diff_total = $diff?$diff:0 if($diff <= $difflimit); - $rh{$runtime_string} = $runtime_string."|".$diff_total."|".$timestamp; + $diff_total = $diff?$diff:0 if($diff <= $difflimit); + $rh{$runtime_string} = $runtime_string."|".$diff_total."|".$timestamp; $ch{$runtime_string} = 1 if($value); $lval = $value; - $rslval = $runtime_string; + $rslval = $runtime_string; } if ($diff) { - if($diff <= $difflimit) { + if($diff <= $difflimit) { $diff_total = $diff_total+$diff; - } + } $rh{$runtime_string} = $runtime_string."|".$diff_total."|".$timestamp; $ch{$runtime_string}++ if($value && $i > 1); $lval = $value; - $rslval = $runtime_string; + $rslval = $runtime_string; } } else { # neuer Zeitabschnitt beginnt, ersten Value-Wert erfassen und Übertragsdifferenz bilden $lastruntimestring = $runtime_string; $i = 1; - - $uediff = $value - $lval if($value > $lval); + + $uediff = $value - $lval if($value > $lval); $diff = $uediff; - $lval = $value if($value); # Übetrag über Perioden mit value = 0 hinweg ! + $lval = $value if($value); # Übetrag über Perioden mit value = 0 hinweg ! $rslval = $runtime_string; - Log3 ($name, 4, "DbRep $name - balance difference of $uediff between $rslval and $runtime_string"); - - + Log3 ($name, 4, "DbRep $name - balance difference of $uediff between $rslval and $runtime_string"); + + $diff_total = $diff?$diff:0 if($diff <= $difflimit); $rh{$runtime_string} = $runtime_string."|".$diff_total."|".$timestamp; - $ch{$runtime_string} = 1 if($value); + $ch{$runtime_string} = 1 if($value); - $uediff = 0; + $uediff = 0; } $i++; } @@ -4046,7 +4058,7 @@ sub diffval_DoParse { foreach my $key (sort(keys%{$ncp})) { Log3 ($name, 3, $key) ; } - $ncps = join('§', %$ncp); + $ncps = join('§', %$ncp); $ncpslist = encode_base64($ncps,""); } @@ -4145,7 +4157,7 @@ sub diffval_ParseDone { foreach my $key (sort(keys(%rh))) { my @k = split("\\|",$rh{$key}); my $rts = $k[2]."__"; - $rts =~ s/:/-/g; # substituieren unsupported characters -> siehe fhem.pl + $rts =~ s/:/-/g; # substituieren unsupported characters -> siehe fhem.pl if (AttrVal($hash->{NAME}, "readingNameMap", "")) { $reading_runtime_string = $rts.AttrVal($hash->{NAME}, "readingNameMap", "")."__".$k[0]; @@ -4215,7 +4227,7 @@ sub sumval_DoParse { } else { $selspec = "SUM(VALUE)"; } - + # SQL-Startzeit my $st = [gettimeofday]; @@ -4229,26 +4241,26 @@ sub sumval_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",''); - } else { + } else { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,''); - } + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; - if ($@) { + }; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|$device|$reading|''|$err|''"; } - + # DB-Abfrage -> Ergebnis in @arr aufnehmen my @line = $sth->fetchrow_array(); Log3 ($name, 5, "DbRep $name - SQL result: $line[0]") if($line[0]); - + if(AttrVal($name, "aggregation", "") eq "hour") { @rsf = split(/[ :]/,$runtime_string_first); @rsn = split(/[ :]/,$runtime_string_next); @@ -4346,7 +4358,7 @@ sub sumval_ParseDone { $reading_runtime_string = $rsf.$ds.$rds."SUM__".$runtime_string; } - ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c?sprintf("%.4f",$c):"-"); + ReadingsBulkUpdateValue ($hash, $reading_runtime_string, $c?sprintf("%.4f",$c):"-"); } ReadingsBulkUpdateValue ($hash, "db_lines_processed", $irowdone) if($hash->{LASTCMD} =~ /writeToDB/); @@ -4539,7 +4551,7 @@ sub insert_Push { if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect(); + $dbh->disconnect(); return "$name|''|''|$err"; } @@ -4657,33 +4669,33 @@ sub currentfillup_Push { # SQL zusammenstellen für DB-Operation if ($usepkc && $dbloghash->{MODEL} eq 'MYSQL') { $selspec = "INSERT IGNORE INTO current (TIMESTAMP,DEVICE,READING) SELECT timestamp,device,reading FROM history where"; - $addon = "group by timestamp,device,reading"; - + $addon = "group by timestamp,device,reading"; + } elsif ($usepkc && $dbloghash->{MODEL} eq 'SQLITE') { $selspec = "INSERT OR IGNORE INTO current (TIMESTAMP,DEVICE,READING) SELECT timestamp,device,reading FROM history where"; - $addon = "group by timestamp,device,reading"; + $addon = "group by timestamp,device,reading"; } elsif ($usepkc && $dbloghash->{MODEL} eq 'POSTGRESQL') { $selspec = "INSERT INTO current (DEVICE,TIMESTAMP,READING) SELECT device, (array_agg(timestamp ORDER BY reading ASC))[1], reading FROM history where"; - $addon = "group by device,reading ON CONFLICT ($pkc) DO NOTHING"; + $addon = "group by device,reading ON CONFLICT ($pkc) DO NOTHING"; } else { if($dbloghash->{MODEL} ne 'POSTGRESQL') { - # MySQL und SQLite + # MySQL und SQLite $selspec = "INSERT INTO current (TIMESTAMP,DEVICE,READING) SELECT timestamp,device,reading FROM history where"; - $addon = "group by device,reading"; - } else { - # PostgreSQL + $addon = "group by device,reading"; + } else { + # PostgreSQL $selspec = "INSERT INTO current (DEVICE,TIMESTAMP,READING) SELECT device, (array_agg(timestamp ORDER BY reading ASC))[1], reading FROM history where"; - $addon = "group by device,reading"; - } + $addon = "group by device,reading"; + } } # SQL-Statement zusammenstellen if ($IsTimeSet || $IsAggrSet) { - $sql = DbRep_createCommonSql($hash,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); + $sql = DbRep_createCommonSql($hash,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); } else { - $sql = DbRep_createCommonSql($hash,$selspec,$device,$reading,undef,undef,$addon); + $sql = DbRep_createCommonSql($hash,$selspec,$device,$reading,undef,undef,$addon); } # Log SQL Statement @@ -4693,7 +4705,7 @@ sub currentfillup_Push { if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect(); + $dbh->disconnect(); return "$name|''|''|$err|''|''"; } @@ -4810,35 +4822,35 @@ sub change_Push { if ($renmode eq "devren") { $old = delete $hash->{HELPER}{OLDDEV}; $new = delete $hash->{HELPER}{NEWDEV}; - - # SQL zusammenstellen für DB-Operation + + # SQL zusammenstellen für DB-Operation Log3 ($name, 5, "DbRep $name -> Rename old device name \"$old\" to new device name \"$new\" in database $dblogname "); - - # prepare DB operation - $old =~ s/'/''/g; # escape ' with '' - $new =~ s/'/''/g; # escape ' with '' - $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,DEVICE='$new' WHERE DEVICE='$old'; "; - Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); - $sth = $dbh->prepare($sql) ; + + # prepare DB operation + $old =~ s/'/''/g; # escape ' with '' + $new =~ s/'/''/g; # escape ' with '' + $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,DEVICE='$new' WHERE DEVICE='$old'; "; + Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); + $sth = $dbh->prepare($sql) ; } elsif ($renmode eq "readren") { $old = delete $hash->{HELPER}{OLDREAD}; ($dev,$old) = split(":",$old,2) if($old =~ /:/); # Wert besteht aus [device]:old_readingname, device ist optional $new = delete $hash->{HELPER}{NEWREAD}; - - # SQL zusammenstellen für DB-Operation + + # SQL zusammenstellen für DB-Operation Log3 ($name, 5, "DbRep $name -> Rename old reading name \"".($dev?"$dev:$old":"$old")."\" to new reading name \"$new\" in database $dblogname "); - - # prepare DB operation - $old =~ s/'/''/g; # escape ' with '' - $new =~ s/'/''/g; # escape ' with '' + + # prepare DB operation + $old =~ s/'/''/g; # escape ' with '' + $new =~ s/'/''/g; # escape ' with '' if($dev) { $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,READING='$new' WHERE DEVICE='$dev' AND READING='$old'; "; } else { - $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,READING='$new' WHERE READING='$old'; "; + $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,READING='$new' WHERE READING='$old'; "; } - Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); - $sth = $dbh->prepare($sql) ; + Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); + $sth = $dbh->prepare($sql) ; } @@ -4849,9 +4861,9 @@ sub change_Push { eval { $sth->execute(); }; if ($@) { $err = encode_base64($@,""); - my $m = ($renmode eq "devren")?"device":"reading"; + my $m = ($renmode eq "devren")?"device":"reading"; Log3 ($name, 2, "DbRep $name - Failed to rename old $m name \"$old\" to new $m name \"$new\": $@"); - $dbh->rollback() if(!$dbh->{AutoCommit}); + $dbh->rollback() if(!$dbh->{AutoCommit}); $dbh->disconnect(); return "$name|''|''|$err"; } else { @@ -4916,12 +4928,12 @@ sub changeval_Push { $old = delete $hash->{HELPER}{OLDVAL}; $new = delete $hash->{HELPER}{NEWVAL}; - # SQL zusammenstellen für DB-Operation + # SQL zusammenstellen für DB-Operation Log3 ($name, 5, "DbRep $name -> Change old value \"$old\" to new value \"$new\" in database $dblogname "); - - # prepare DB operation - $old =~ s/'/''/g; # escape ' with '' - $new =~ s/'/''/g; # escape ' with '' + + # prepare DB operation + $old =~ s/'/''/g; # escape ' with '' + $new =~ s/'/''/g; # escape ' with '' # SQL zusammenstellen für DB-Update my $addon = $old =~ /%/?"WHERE VALUE LIKE '$old'":"WHERE VALUE='$old'"; @@ -4931,8 +4943,8 @@ sub changeval_Push { } else { $sql = DbRep_createCommonSql($hash,$selspec,$device,$reading,undef,undef,''); } - Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); - $sth = $dbh->prepare($sql) ; + Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); + $sth = $dbh->prepare($sql) ; $old =~ s/''/'/g; # escape back $new =~ s/''/'/g; # escape back @@ -4941,7 +4953,7 @@ sub changeval_Push { if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Failed to change old value \"$old\" to new value \"$new\": $@"); - $dbh->rollback() if(!$dbh->{AutoCommit}); + $dbh->rollback() if(!$dbh->{AutoCommit}); $dbh->disconnect(); return "$name|''|''|$err"; } else { @@ -4970,15 +4982,15 @@ sub changeval_Push { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); - } else { - $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); - } + } else { + $sql = DbRep_createSelectSql($hash,"history",$selspec,$device,$reading,undef,undef,$addon); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; - if ($@) { + }; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; @@ -4998,9 +5010,9 @@ sub changeval_Push { my $oval = $value; # Selektkriterium für Update alter Valuewert my $VALUE = $value; - my $UNIT = $unit; + my $UNIT = $unit; eval $new; - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; @@ -5008,7 +5020,7 @@ sub changeval_Push { } $value = $VALUE if(defined $VALUE); - $unit = $UNIT if(defined $UNIT); + $unit = $UNIT if(defined $UNIT); # Daten auf maximale Länge beschneiden (DbLog-Funktion !) (undef,undef,undef,undef,$value,$unit) = DbLog_cutCol($dbloghash,"1","1","1","1",$value,$unit); @@ -5017,8 +5029,8 @@ sub changeval_Push { # SQL zusammenstellen für DB-Update $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,VALUE='$value',UNIT='$unit' WHERE TIMESTAMP = '$date $time' AND DEVICE = '$device' AND READING = '$reading' AND VALUE='$oval'"; - Log3 ($name, 5, "DbRep $name - SQL execute: $sql"); - $sth = $dbh->prepare($sql) ; + Log3 ($name, 5, "DbRep $name - SQL execute: $sql"); + $sth = $dbh->prepare($sql) ; $value =~ s/''/'/g; # escape back $unit =~ s/''/'/g; # escape back @@ -5027,7 +5039,7 @@ sub changeval_Push { if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Failed to change old value \"$old\" to new value \"$new\": $@"); - $dbh->rollback() if(!$dbh->{AutoCommit}); + $dbh->rollback() if(!$dbh->{AutoCommit}); $dbh->disconnect(); return "$name|''|''|$err"; } else { @@ -5086,19 +5098,19 @@ sub change_Done { ReadingsBulkUpdateValue ($hash, "number_lines_updated", $urow); if($renmode eq "devren") { - ReadingsBulkUpdateValue ($hash, "device_renamed", "old: ".$old." to new: ".$new) if($urow != 0); + ReadingsBulkUpdateValue ($hash, "device_renamed", "old: ".$old." to new: ".$new) if($urow != 0); ReadingsBulkUpdateValue ($hash, "device_not_renamed", "Warning - old: ".$old." not found, not renamed to new: ".$new) - if($urow == 0); + if($urow == 0); } if($renmode eq "readren") { - ReadingsBulkUpdateValue ($hash, "reading_renamed", "old: ".$old." to new: ".$new) if($urow != 0); + ReadingsBulkUpdateValue ($hash, "reading_renamed", "old: ".$old." to new: ".$new) if($urow != 0); ReadingsBulkUpdateValue ($hash, "reading_not_renamed", "Warning - old: ".$old." not found, not renamed to new: ".$new) - if ($urow == 0); + if ($urow == 0); } if($renmode eq "changeval") { - ReadingsBulkUpdateValue ($hash, "value_changed", "old: ".$old." to new: ".$new) if($urow != 0); + ReadingsBulkUpdateValue ($hash, "value_changed", "old: ".$old." to new: ".$new) if($urow != 0); ReadingsBulkUpdateValue ($hash, "value_not_changed", "Warning - old: ".$old." not found, not changed to new: ".$new) - if ($urow == 0); + if ($urow == 0); } ReadingsBulkUpdateTimeState($hash,$brt,$rt,"done"); @@ -5106,12 +5118,12 @@ sub change_Done { if ($urow != 0) { Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - DEVICE renamed in \"$hash->{DATABASE}\", old: \"$old\", new: \"$new\", number: $urow ") if($renmode eq "devren"); - Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - READING renamed in \"$hash->{DATABASE}\", old: \"$old\", new: \"$new\", number: $urow ") if($renmode eq "readren"); - Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - VALUE changed in \"$hash->{DATABASE}\", old: \"$old\", new: \"$new\", number: $urow ") if($renmode eq "changeval"); + Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - READING renamed in \"$hash->{DATABASE}\", old: \"$old\", new: \"$new\", number: $urow ") if($renmode eq "readren"); + Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - VALUE changed in \"$hash->{DATABASE}\", old: \"$old\", new: \"$new\", number: $urow ") if($renmode eq "changeval"); } else { Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - WARNING - old device \"$old\" was not found in database \"$hash->{DATABASE}\" ") if($renmode eq "devren"); - Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - WARNING - old reading \"$old\" was not found in database \"$hash->{DATABASE}\" ") if($renmode eq "readren"); - Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - WARNING - old value \"$old\" not found in database \"$hash->{DATABASE}\" ") if($renmode eq "changeval"); + Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - WARNING - old reading \"$old\" was not found in database \"$hash->{DATABASE}\" ") if($renmode eq "readren"); + Log3 ($name, 3, "DbRep ".(($hash->{ROLE} eq "Agent")?"Agent ":"")."$name - WARNING - old value \"$old\" not found in database \"$hash->{DATABASE}\" ") if($renmode eq "changeval"); } return; @@ -5251,7 +5263,7 @@ sub fetchrows_ParseDone { $a[3] =~ s/:/-/g; # substituieren unsupported characters ":" -> siehe fhem.pl my $ts = $a[2]."_".$a[3]; my $val = $a[4]; - my $unt = $a[5]; + my $unt = $a[5]; $val = $unt?$val." ".$unt:$val; $nrow = $ts.$dev.$rea; @@ -5304,7 +5316,7 @@ sub fetchrows_ParseDone { } } - ReadingsBulkUpdateValue($hash, $reading_runtime_string, $val); + ReadingsBulkUpdateValue($hash, $reading_runtime_string, $val); } my $sfx = AttrVal("global", "language", "EN"); $sfx = ($sfx eq "EN" ? "" : "_$sfx"); @@ -5378,15 +5390,15 @@ sub deldoublets_DoParse { my $runtime_string_first = $a[1]; my $runtime_string_next = $a[2]; $runtime_string = encode_base64($runtime_string,""); - - # SQL-Startzeit + + # SQL-Startzeit $st = [gettimeofday]; # SQL zusammenstellen für Logausgabe - my $sql1 = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); + my $sql1 = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); - eval{$sth->execute($runtime_string_first, $runtime_string_next);}; + eval{$sth->execute($runtime_string_first, $runtime_string_next);}; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -5398,7 +5410,7 @@ sub deldoublets_DoParse { $rt = $rt+tv_interval($st); # Beginn Löschlogik, Zusammenstellen der zu löschenden DS (warping) - # Array @warp -> die zu löschenden Datensätze + # Array @warp -> die zu löschenden Datensätze my (@warp); my $i = 0; foreach my $nr (map { $_->[1]."_ESC_".$_->[2]."_ESC_".($_->[0] =~ s/ /_ESC_/r)."_ESC_".$_->[3]."_|_".($_->[4]-1) } @{$sth->fetchall_arrayref()}) { @@ -5419,7 +5431,7 @@ sub deldoublets_DoParse { $dev =~ s/'/''/g; # escape ' with '' $read =~ s/'/''/g; # escape ' with '' $val =~ s/'/''/g; # escape ' with '' - $val =~ s/\\/\\\\/g if($model eq "MYSQL"); # escape \ with \\ für MySQL + $val =~ s/\\/\\\\/g if($model eq "MYSQL"); # escape \ with \\ für MySQL $st = [gettimeofday]; if($model =~ /MYSQL|SQLITE/) { $dsql = "delete FROM $table WHERE TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val' limit $limit;"; @@ -5549,15 +5561,15 @@ sub delseqdoubl_DoParse { my $runtime_string_first = $a[1]; my $runtime_string_next = $a[2]; $runtime_string = encode_base64($runtime_string,""); - - # SQL-Startzeit + + # SQL-Startzeit $st = [gettimeofday]; # SQL zusammenstellen für Logausgabe - my $sql1 = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",''); + my $sql1 = DbRep_createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",''); Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); - eval{$sth->execute($runtime_string_first, $runtime_string_next);}; + eval{$sth->execute($runtime_string_first, $runtime_string_next);}; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -5569,13 +5581,13 @@ sub delseqdoubl_DoParse { $rt = $rt+tv_interval($st); # Beginn Löschlogik, Zusammenstellen der löschenden DS (warping) - # Array @sel -> die VERBLEIBENDEN Datensätze, @warp -> die zu löschenden Datensätze + # Array @sel -> die VERBLEIBENDEN Datensätze, @warp -> die zu löschenden Datensätze my (@sel,@warp); my ($or,$oor,$odev,$oread,$oval,$ooval,$ndev,$nread,$nval); my $i = 0; foreach my $nr (map { $_->[0]."_ESC_".$_->[1]."_ESC_".($_->[2] =~ s/ /_ESC_/r)."_ESC_".$_->[3] } @{$sth->fetchall_arrayref()}) { ($ndev,$nread,undef,undef,$nval) = split("_ESC_", $nr); # Werte des aktuellen Elements - $or = pop @sel; # das letzte Element der Liste + $or = pop @sel; # das letzte Element der Liste ($odev,$oread,undef,undef,$oval) = split("_ESC_", $or); # Value des letzten Elements if (looks_like_number($oval) && defined $varpos && defined $varneg) { # unterschiedliche Varianz +/- für numerische Werte @@ -5588,16 +5600,16 @@ sub delseqdoubl_DoParse { undef $varo; undef $varu; } - $oor = pop @sel; # das vorletzte Element der Liste - $ooval = (split '_ESC_', $oor)[-1]; # Value des vorletzten Elements - # Log3 ($name, 1, "DbRep $name - OOVAL: $ooval, OVAL: $oval, VARO: $varo, VARU: $varu"); + $oor = pop @sel; # das vorletzte Element der Liste + $ooval = (split '_ESC_', $oor)[-1]; # Value des vorletzten Elements + # Log3 ($name, 1, "DbRep $name - OOVAL: $ooval, OVAL: $oval, VARO: $varo, VARU: $varu"); if ($ndev.$nread ne $odev.$oread) { $i = 0; # neues Device/Reading in einer Periode -> ooor soll erhalten bleiben - push (@sel,$oor) if($oor); - push (@sel,$or) if($or); - push (@sel,$nr); - + push (@sel,$oor) if($oor); + push (@sel,$or) if($or); + push (@sel,$nr); + } elsif ($i>=2 && ($ooval eq $oval && $oval eq $nval) || ($i>=2 && $varo && $varu && ($ooval <= $varo) && ($varu <= $ooval) && ($nval <= $varo) && ($varu <= $nval)) ) { if ($edge =~ /negative/i && ($ooval > $oval)) { @@ -5615,34 +5627,34 @@ sub delseqdoubl_DoParse { } if ($opt =~ /delete/ && $or) { # delete Datensätze - my ($dev,$read,$date,$time,$val) = split("_ESC_", $or); - my $dt = $date." ".$time; - chomp($val); - $dev =~ s/'/''/g; # escape ' with '' - $read =~ s/'/''/g; # escape ' with '' - $val =~ s/'/''/g; # escape ' with '' - $st = [gettimeofday]; - my $dsql = "delete FROM $table where TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val';"; - my $sthd = $dbh->prepare($dsql); + my ($dev,$read,$date,$time,$val) = split("_ESC_", $or); + my $dt = $date." ".$time; + chomp($val); + $dev =~ s/'/''/g; # escape ' with '' + $read =~ s/'/''/g; # escape ' with '' + $val =~ s/'/''/g; # escape ' with '' + $st = [gettimeofday]; + my $dsql = "delete FROM $table where TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val';"; + my $sthd = $dbh->prepare($dsql); Log3 ($name, 4, "DbRep $name - SQL execute: $dsql"); - - eval {$sthd->execute();}; - if ($@) { + + eval {$sthd->execute();}; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|''|$err|''|$opt"; } - $ndel = $ndel+$sthd->rows; + $ndel = $ndel+$sthd->rows; $dbh->commit() if(!$dbh->{AutoCommit}); - - $rt = $rt+tv_interval($st); - } + + $rt = $rt+tv_interval($st); + } } else { - push (@sel,$oor) if($oor); - push (@sel,$or) if($or); - push (@sel,$nr); - } + push (@sel,$oor) if($oor); + push (@sel,$or) if($or); + push (@sel,$nr); + } $i++; } if(@sel && $opt =~ /adviceRemain/) { @@ -5731,9 +5743,9 @@ sub delseqdoubl_ParseDone { s/_E#S#C_/\|/g for @row_array; # escaped Pipe return to "|" Log3 ($name, 5, "DbRep $name - row_array decoded: @row_array"); foreach my $row (@row_array) { - last if($l >= $limit); + last if($l >= $limit); my @a = split("_ESC_", $row, 5); - my $dev = $a[0]; + my $dev = $a[0]; my $rea = $a[1]; $a[3] =~ s/:/-/g; # substituieren unsupported characters ":" -> siehe fhem.pl my $ts = $a[2]."_".$a[3]; @@ -5744,8 +5756,8 @@ sub delseqdoubl_ParseDone { } else { $reading_runtime_string = $ts."__".$dev."__".$rea; } - ReadingsBulkUpdateValue($hash, $reading_runtime_string, $val); - $l++; + ReadingsBulkUpdateValue($hash, $reading_runtime_string, $val); + $l++; } } @@ -5852,15 +5864,15 @@ sub expfile_DoParse { if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash,"history","TIMESTAMP,DEVICE,TYPE,EVENT,READING,VALUE,UNIT",$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",$addon); - } else { + } else { $sql = DbRep_createSelectSql($hash,"history","TIMESTAMP,DEVICE,TYPE,EVENT,READING,VALUE,UNIT",$device,$reading,undef,undef,$addon); - } + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; - if ($@) { + }; + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; @@ -6019,7 +6031,7 @@ sub impfile_Push { if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect(); + $dbh->disconnect(); return "$name|''|''|$err|''"; } @@ -6032,7 +6044,7 @@ sub impfile_Push { $al = $_; chomp $al; my @alarr = split("\",\"", $al); - foreach(@alarr) { + foreach(@alarr) { tr/"//d; } my $i_timestamp = DbRep_trim($alarr[0]); @@ -6172,8 +6184,8 @@ sub sqlCmd_DoParse { ($err,$dbh) = DbRep_dbConnect($name,0); if ($err) { - $err = encode_base64($err,""); - return "$name|''|$opt|$cmd|''|''|$err"; + $err = encode_base64($err,""); + return "$name|''|$opt|$cmd|''|''|$err"; } # only for this block because of warnings if details of readings are not set @@ -6278,8 +6290,8 @@ sub sqlCmd_DoParse { Log3 ($name, 4, "DbRep $name - SQL result: @line"); $row = join("$srs", @line); - # join Delimiter "§" escapen - $row =~ s/§/|°escaped°|/g; + # join Delimiter "§" escapen + $row =~ s/§/|°escaped°|/g; push(@rows, $row); # Anzahl der Datensätze @@ -6294,10 +6306,10 @@ sub sqlCmd_DoParse { $dbh->disconnect; return "$name|''|$opt|$sql|''|''|$err"; } - - push(@rows, $r); - my $com = (split(" ",$sql, 2))[0]; - Log3 ($name, 3, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com"); + + push(@rows, $r); + my $com = (split(" ",$sql, 2))[0]; + Log3 ($name, 3, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com"); } $sth->finish; @@ -6380,58 +6392,58 @@ sub sqlCmd_ParseDone { ReadingsBulkUpdateValue ($hash, "SqlResult", $rowstring); } elsif ($srf eq "table") { - my $res = ""; - my @rows = split( /§/, $rowstring ); + my $res = "
"; + my @rows = split( /§/, $rowstring ); my $row; - foreach $row ( @rows ) { - $row =~ s/\|°escaped°\|/§/g; - $row =~ s/$srs/\|/g if($srs !~ /\|/); - $row =~ s/\|/<\/td>"; } - $row .= $res."
/g; + foreach $row ( @rows ) { + $row =~ s/\|°escaped°\|/§/g; + $row =~ s/$srs/\|/g if($srs !~ /\|/); + $row =~ s/\|/<\/td>/g; $res .= "
".$row."
"; - - ReadingsBulkUpdateValue ($hash,"SqlResult", $row); - + $row .= $res.""; + + ReadingsBulkUpdateValue ($hash,"SqlResult", $row); + } elsif ($srf eq "mline") { my $res = ""; - my @rows = split( /§/, $rowstring ); + my @rows = split( /§/, $rowstring ); my $row; - foreach $row ( @rows ) { - $row =~ s/\|°escaped°\|/§/g; + foreach $row ( @rows ) { + $row =~ s/\|°escaped°\|/§/g; $res .= $row."
"; } - $row .= $res.""; - + $row .= $res.""; + ReadingsBulkUpdateValue ($hash, "SqlResult", $row ); - + } elsif ($srf eq "separated") { my @rows = split( /§/, $rowstring ); - my $bigint = @rows; - my $numd = ceil(log10($bigint)); - my $formatstr = sprintf('%%%d.%dd', $numd, $numd); + my $bigint = @rows; + my $numd = ceil(log10($bigint)); + my $formatstr = sprintf('%%%d.%dd', $numd, $numd); my $i = 0; foreach my $row ( @rows ) { $i++; $row =~ s/\|°escaped°\|/§/g; - my $fi = sprintf($formatstr, $i); - ReadingsBulkUpdateValue ($hash, "SqlResultRow_".$fi, $row); + my $fi = sprintf($formatstr, $i); + ReadingsBulkUpdateValue ($hash, "SqlResultRow_".$fi, $row); } } elsif ($srf eq "json") { my %result = (); my @rows = split( /§/, $rowstring ); - my $bigint = @rows; - my $numd = ceil(log10($bigint)); - my $formatstr = sprintf('%%%d.%dd', $numd, $numd); + my $bigint = @rows; + my $numd = ceil(log10($bigint)); + my $formatstr = sprintf('%%%d.%dd', $numd, $numd); my $i = 0; foreach my $row ( @rows ) { $i++; $row =~ s/\|°escaped°\|/§/g; - my $fi = sprintf($formatstr, $i); - $result{$fi} = $row; + my $fi = sprintf($formatstr, $i); + $result{$fi} = $row; } my $json = toJSON(\%result); # at least fhem.pl 14348 2017-05-22 20:25:06Z - ReadingsBulkUpdateValue ($hash, "SqlResult", $json); + ReadingsBulkUpdateValue ($hash, "SqlResult", $json); } ReadingsBulkUpdateTimeState($hash,$brt,$rt,$state); @@ -6515,76 +6527,76 @@ sub dbmeta_DoParse { eval {$sth->execute();}; if ($@) { - # error bei sql-execute + # error bei sql-execute $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|''|''|$err"; - } else { + } else { # kein error bei sql-execute if ($opt eq "tableinfo") { - $param = AttrVal($name, "showTableInfo", "[A-Z_]"); + $param = AttrVal($name, "showTableInfo", "[A-Z_]"); $param =~ s/,/\|/g; $param =~ tr/%//d; - while ( my $line = $sth->fetchrow_hashref()) { - - Log3 ($name, 5, "DbRep $name - SQL result: $line->{Name}, $line->{Version}, $line->{Row_format}, $line->{Rows}, $line->{Avg_row_length}, $line->{Data_length}, $line->{Max_data_length}, $line->{Index_length}, $line->{Data_free}, $line->{Auto_increment}, $line->{Create_time}, $line->{Check_time}, $line->{Collation}, $line->{Checksum}, $line->{Create_options}, $line->{Comment}"); - + while ( my $line = $sth->fetchrow_hashref()) { + + Log3 ($name, 5, "DbRep $name - SQL result: $line->{Name}, $line->{Version}, $line->{Row_format}, $line->{Rows}, $line->{Avg_row_length}, $line->{Data_length}, $line->{Max_data_length}, $line->{Index_length}, $line->{Data_free}, $line->{Auto_increment}, $line->{Create_time}, $line->{Check_time}, $line->{Collation}, $line->{Checksum}, $line->{Create_options}, $line->{Comment}"); + if($line->{Name} =~ m/($param)/i) { - push(@row_array, $line->{Name}.".engine ".$line->{Engine}) if($line->{Engine}); - push(@row_array, $line->{Name}.".version ".$line->{Version}) if($line->{Version}); - push(@row_array, $line->{Name}.".row_format ".$line->{Row_format}) if($line->{Row_format}); - push(@row_array, $line->{Name}.".number_of_rows ".$line->{Rows}) if($line->{Rows}); - push(@row_array, $line->{Name}.".avg_row_length ".$line->{Avg_row_length}) if($line->{Avg_row_length}); - push(@row_array, $line->{Name}.".data_length_MB ".sprintf("%.2f",$line->{Data_length}/1024/1024)) if($line->{Data_length}); - push(@row_array, $line->{Name}.".max_data_length_MB ".sprintf("%.2f",$line->{Max_data_length}/1024/1024)) if($line->{Max_data_length}); - push(@row_array, $line->{Name}.".index_length_MB ".sprintf("%.2f",$line->{Index_length}/1024/1024)) if($line->{Index_length}); - push(@row_array, $line->{Name}.".data_index_length_MB ".sprintf("%.2f",($line->{Data_length}+$line->{Index_length})/1024/1024)); - push(@row_array, $line->{Name}.".data_free_MB ".sprintf("%.2f",$line->{Data_free}/1024/1024)) if($line->{Data_free}); - push(@row_array, $line->{Name}.".auto_increment ".$line->{Auto_increment}) if($line->{Auto_increment}); - push(@row_array, $line->{Name}.".create_time ".$line->{Create_time}) if($line->{Create_time}); - push(@row_array, $line->{Name}.".update_time ".$line->{Update_time}) if($line->{Update_time}); - push(@row_array, $line->{Name}.".check_time ".$line->{Check_time}) if($line->{Check_time}); - push(@row_array, $line->{Name}.".collation ".$line->{Collation}) if($line->{Collation}); - push(@row_array, $line->{Name}.".checksum ".$line->{Checksum}) if($line->{Checksum}); - push(@row_array, $line->{Name}.".create_options ".$line->{Create_options}) if($line->{Create_options}); - push(@row_array, $line->{Name}.".comment ".$line->{Comment}) if($line->{Comment}); + push(@row_array, $line->{Name}.".engine ".$line->{Engine}) if($line->{Engine}); + push(@row_array, $line->{Name}.".version ".$line->{Version}) if($line->{Version}); + push(@row_array, $line->{Name}.".row_format ".$line->{Row_format}) if($line->{Row_format}); + push(@row_array, $line->{Name}.".number_of_rows ".$line->{Rows}) if($line->{Rows}); + push(@row_array, $line->{Name}.".avg_row_length ".$line->{Avg_row_length}) if($line->{Avg_row_length}); + push(@row_array, $line->{Name}.".data_length_MB ".sprintf("%.2f",$line->{Data_length}/1024/1024)) if($line->{Data_length}); + push(@row_array, $line->{Name}.".max_data_length_MB ".sprintf("%.2f",$line->{Max_data_length}/1024/1024)) if($line->{Max_data_length}); + push(@row_array, $line->{Name}.".index_length_MB ".sprintf("%.2f",$line->{Index_length}/1024/1024)) if($line->{Index_length}); + push(@row_array, $line->{Name}.".data_index_length_MB ".sprintf("%.2f",($line->{Data_length}+$line->{Index_length})/1024/1024)); + push(@row_array, $line->{Name}.".data_free_MB ".sprintf("%.2f",$line->{Data_free}/1024/1024)) if($line->{Data_free}); + push(@row_array, $line->{Name}.".auto_increment ".$line->{Auto_increment}) if($line->{Auto_increment}); + push(@row_array, $line->{Name}.".create_time ".$line->{Create_time}) if($line->{Create_time}); + push(@row_array, $line->{Name}.".update_time ".$line->{Update_time}) if($line->{Update_time}); + push(@row_array, $line->{Name}.".check_time ".$line->{Check_time}) if($line->{Check_time}); + push(@row_array, $line->{Name}.".collation ".$line->{Collation}) if($line->{Collation}); + push(@row_array, $line->{Name}.".checksum ".$line->{Checksum}) if($line->{Checksum}); + push(@row_array, $line->{Name}.".create_options ".$line->{Create_options}) if($line->{Create_options}); + push(@row_array, $line->{Name}.".comment ".$line->{Comment}) if($line->{Comment}); } - } + } } elsif ($opt eq "procinfo") { my $row; - my $res = ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; - $res .= ""; + my $res = "
IDUSERHOSTDBCMDTIME_SecSTATEINFOPROGRESS
"; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; + $res .= ""; while (my @line = $sth->fetchrow_array()) { Log3 ($name, 4, "DbRep $name - SQL result: @line"); - $row = join("|", @line); - $row =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd; - $row =~ s/\|/<\/td>"; } my $tab .= $res."
IDUSERHOSTDBCMDTIME_SecSTATEINFOPROGRESS
/g; + $row = join("|", @line); + $row =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\]^_`{|}~//cd; + $row =~ s/\|/<\/td>/g; $res .= "
".$row."
"; push(@row_array, "ProcessList ".$tab); - } else { - while (my @line = $sth->fetchrow_array()) { + } else { + while (my @line = $sth->fetchrow_array()) { Log3 ($name, 4, "DbRep $name - SQL result: @line"); my $row = join("§", @line); $row =~ s/ /_/g; @line = split("§", $row); - push(@row_array, $line[0]." ".$line[1]); - } - } - } + push(@row_array, $line[0]." ".$line[1]); + } + } + } $sth->finish; } } else { @@ -6595,13 +6607,13 @@ sub dbmeta_DoParse { if($dbmodel eq 'SQLITE') { my $sf = $dbh->sqlite_db_filename(); if ($@) { - # error bei sql-execute + # error bei sql-execute $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); $dbh->disconnect; return "$name|''|''|''|$err"; } else { - # kein error bei sql-execute + # kein error bei sql-execute my $key = "SQLITE_DB_FILENAME"; push(@row_array, $key." ".$sf) if($key =~ m/($param)/i); } @@ -6619,9 +6631,9 @@ sub dbmeta_DoParse { $dbh->disconnect; return "$name|''|''|''|$err"; } else { - if($utf8) { + if($utf8) { $info = Encode::encode_utf8($info) if($info); - } + } push(@row_array, $key." ".$info) if($key =~ m/($param)/i); } } @@ -6686,7 +6698,7 @@ sub dbmeta_ParseDone { my @a = split(" ", $row, 2); my $k = $a[0]; my $v = $a[1]; - ReadingsBulkUpdateValue ($hash, $pre.$k, $v); + ReadingsBulkUpdateValue ($hash, $pre.$k, $v); } ReadingsBulkUpdateTimeState($hash,$brt,$rt,"done"); @@ -6720,7 +6732,7 @@ sub DbRep_Index { my ($dbh,$err,$sth,$rows,@six); my ($sqldel,$sqlcre,$sqlava,$sqlallidx,$ret) = ("","","","",""); my $p = 0; - + Log3 ($name, 5, "DbRep $name -> Start DbRep_Index"); # Background-Startzeit @@ -6745,8 +6757,8 @@ sub DbRep_Index { ($err,$dbh) = DbRep_dbConnect($name,$p); if ($err) { - $err = encode_base64($err,""); - return "$name|''|''|$err"; + $err = encode_base64($err,""); + return "$name|''|''|$err"; } my ($cmd,$idx) = split("_",$cmdidx,2); @@ -6879,7 +6891,7 @@ sub DbRep_Index { $rt = $rt.",".$brt; Log3 ($name, 5, "DbRep $name -> DbRep_Index finished"); - + return "$name|$ret|$rt|''"; } @@ -6971,7 +6983,7 @@ sub DbRep_optimizeTables { # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); return "$name|''|$err|''|''"; } @@ -6988,25 +7000,25 @@ sub DbRep_optimizeTables { eval { $sth = $dbh->prepare($query); $sth->execute; - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; } while ( $value = $sth->fetchrow_hashref()) { - # verbose 5 logging - Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); + # verbose 5 logging + Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); foreach my $tk (sort(keys(%$value))) { Log3 ($name, 5, "DbRep $name - $tk: $value->{$tk}") if(defined($value->{$tk}) && $tk ne "Rows"); } - Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); - + Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); + # check for old MySQL3-Syntax Type=xxx - if (defined $value->{Type}) { + if (defined $value->{Type}) { # port old index type to index engine, so we can use the index Engine in the rest of the script $value->{Engine} = $value->{Type}; } @@ -7018,44 +7030,44 @@ sub DbRep_optimizeTables { if (@tablenames < 1) { $err = "There are no tables inside database $dbname ! It doesn't make sense to backup an empty database. Skipping this one."; - Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($@,""); - $sth->finish; - $dbh->disconnect; + Log3 ($name, 2, "DbRep $name - $err"); + $err = encode_base64($@,""); + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; } # Tabellen optimieren - $hash->{HELPER}{DBTABLES} = \%db_tables; + $hash->{HELPER}{DBTABLES} = \%db_tables; ($err,$db_MB_start,$db_MB_end) = DbRep_mysqlOptimizeTables($hash,$dbh,@tablenames); - if ($err) { - $err = encode_base64($err,""); - return "$name|''|$err|''|''"; - } + if ($err) { + $err = encode_base64($err,""); + return "$name|''|$err|''|''"; + } } if ($dbmodel =~ /SQLITE/) { - # Anfangsgröße ermitteln + # Anfangsgröße ermitteln $db_MB_start = (split(' ',qx(du -m $hash->{DATABASE})))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); Log3 ($name, 3, "DbRep $name - Size of database $dbname before optimize (MB): $db_MB_start"); $query ="VACUUM"; - Log3 ($name, 5, "DbRep $name - current query: $query "); + Log3 ($name, 5, "DbRep $name - current query: $query "); Log3 ($name, 3, "DbRep $name - VACUUM database $dbname...."); eval {$sth = $dbh->prepare($query); $r = $sth->execute(); }; - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! SQLite-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; - } - - # Endgröße ermitteln - $db_MB_end = (split(' ',qx(du -m $hash->{DATABASE})))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); - Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB_end"); + } + + # Endgröße ermitteln + $db_MB_end = (split(' ',qx(du -m $hash->{DATABASE})))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); + Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB_end"); } if ($dbmodel =~ /POSTGRESQL/) { @@ -7064,55 +7076,55 @@ sub DbRep_optimizeTables { Log3 ($name, 5, "DbRep $name - current query: $query "); eval { $sth = $dbh->prepare($query); $sth->execute; - }; + }; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! PostgreSQL-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; } - $value = $sth->fetchrow(); - $value =~ tr/MB//d; + $value = $sth->fetchrow(); + $value =~ tr/MB//d; $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 - VACUUM database $dbname...."); - $query = "vacuum history"; - - Log3 ($name, 5, "DbRep $name - current query: $query "); + $query = "vacuum history"; + + Log3 ($name, 5, "DbRep $name - current query: $query "); eval {$sth = $dbh->prepare($query); $sth->execute(); }; - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! PostgreSQL-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; - } - - # Endgröße ermitteln + } + + # Endgröße ermitteln $query = "SELECT pg_size_pretty(pg_database_size('$dbname'))"; Log3 ($name, 5, "DbRep $name - current query: $query "); eval { $sth = $dbh->prepare($query); $sth->execute; - }; + }; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! PostgreSQL-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''"; } - $value = $sth->fetchrow(); - $value =~ tr/MB//d; - $db_MB_end = sprintf("%.2f",$value); - Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB_end"); + $value = $sth->fetchrow(); + $value =~ tr/MB//d; + $db_MB_end = sprintf("%.2f",$value); + Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB_end"); } $sth->finish; @@ -7214,7 +7226,7 @@ sub mysql_DoDumpClientSide { ##################### Beginn Dump ######################## ############################################################## - + undef(%db_tables); # Startzeit ermitteln @@ -7227,12 +7239,12 @@ sub mysql_DoDumpClientSide { my $starttime = sprintf("%02d",$Monatstag).".".sprintf("%02d",$Monat).".".$Jahr." ".sprintf("%02d",$Stunden).":".sprintf("%02d",$Minuten); my $fieldlist = ""; - + # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { $e = $@; - $err = encode_base64($e,""); + $err = encode_base64($e,""); Log3 ($name, 2, "DbRep $name - $e"); return "$name|''|$err|''|''|''|''|''|''|''"; } @@ -7243,12 +7255,12 @@ sub mysql_DoDumpClientSide { ##################### Mysql-Version ermitteln ######################## eval { $sth = $dbh->prepare("SELECT VERSION()"); $sth->execute; - }; + }; if ($@) { $e = $@; $err = encode_base64($e,""); Log3 ($name, 2, "DbRep $name - $e"); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } @@ -7290,40 +7302,40 @@ sub mysql_DoDumpClientSide { if ($dbpraefix ne "") { $query.=" LIKE '$dbpraefix%'"; - Log3 ($name, 3, "DbRep $name - Searching for tables inside database $dbname with prefix $dbpraefix...."); + Log3 ($name, 3, "DbRep $name - Searching for tables inside database $dbname with prefix $dbpraefix...."); } else { - Log3 ($name, 3, "DbRep $name - Searching for tables inside database $dbname...."); + Log3 ($name, 3, "DbRep $name - Searching for tables inside database $dbname...."); } eval { $sth = $dbh->prepare($query); $sth->execute; - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } while ( $value = $sth->fetchrow_hashref()) { $value->{skip_data} = 0; #defaut -> backup data of table - - # verbose 5 logging - Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); + + # verbose 5 logging + Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); foreach my $tk (sort(keys(%$value))) { Log3 ($name, 5, "DbRep $name - $tk: $value->{$tk}") if(defined($value->{$tk}) && $tk ne "Rows"); } - Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); - - # decide if we need to skip the data while dumping (VIEWs and MEMORY) + Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); + + # decide if we need to skip the data while dumping (VIEWs and MEMORY) # check for old MySQL3-Syntax Type=xxx - if (defined $value->{Type}) { + if (defined $value->{Type}) { # port old index type to index engine, so we can use the index Engine in the rest of the script $value->{Engine} = $value->{Type}; $engine = uc($value->{Type}); - if ($engine eq "MEMORY") { + if ($engine eq "MEMORY") { $value->{skip_data} = 1; } } @@ -7332,7 +7344,7 @@ sub mysql_DoDumpClientSide { if (defined $value->{Engine}) { $engine = uc($value->{Engine}); - if ($engine eq "MEMORY") { + if ($engine eq "MEMORY") { $value->{skip_data} = 1; } } @@ -7363,20 +7375,20 @@ sub mysql_DoDumpClientSide { if (@tablenames < 1) { $err = "There are no tables inside database $dbname ! It doesn't make sense to backup an empty database. Skipping this one."; - Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($@,""); - $dbh->disconnect; + Log3 ($name, 2, "DbRep $name - $err"); + $err = encode_base64($@,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { # Tabellen optimieren vor dem Dump - $hash->{HELPER}{DBTABLES} = \%db_tables; + $hash->{HELPER}{DBTABLES} = \%db_tables; ($err,$db_MB_start,$db_MB_end) = DbRep_mysqlOptimizeTables($hash,$dbh,@tablenames); - if ($err) { - $err = encode_base64($err,""); - return "$name|''|$err|''|''|''|''|''|''|''"; - } + if ($err) { + $err = encode_base64($err,""); + return "$name|''|$err|''|''|''|''|''|''|''"; + } } # Tabelleneigenschaften für SQL-File ermitteln @@ -7385,7 +7397,7 @@ sub mysql_DoDumpClientSide { foreach $tablename (@tablenames) { my $dump_table = 1; - if ($dbpraefix ne "") { + if ($dbpraefix ne "") { if (substr($tablename,0,length($dbpraefix)) ne $dbpraefix) { # exclude table from backup because it doesn't fit to praefix $dump_table = 0; @@ -7394,37 +7406,37 @@ sub mysql_DoDumpClientSide { if ($dump_table == 1) { # how many rows - $sql_create = "SELECT count(*) FROM `$tablename`"; - eval { $sth = $dbh->prepare($sql_create); - $sth->execute; - }; + $sql_create = "SELECT count(*) FROM `$tablename`"; + eval { $sth = $dbh->prepare($sql_create); + $sth->execute; + }; if ($@) { $e = $@; - $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; + $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($e,""); - $dbh->disconnect; + $err = encode_base64($e,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } - $db_tables{$tablename}{Rows} = $sth->fetchrow; + $db_tables{$tablename}{Rows} = $sth->fetchrow; $sth->finish; - $r += $db_tables{$tablename}{Rows}; + $r += $db_tables{$tablename}{Rows}; push(@tables,$db_tables{$tablename}{Name}); # add tablename to backuped tables $t++; - if (!defined $db_tables{$tablename}{Update_time}) { + if (!defined $db_tables{$tablename}{Update_time}) { $db_tables{$tablename}{Update_time} = 0; } $st_e .= $mysql_commentstring."TABLE: $db_tables{$tablename}{Name} | Rows: $db_tables{$tablename}{Rows} | Length: ".($db_tables{$tablename}{Data_length}+$db_tables{$tablename}{Index_length})." | Engine: $db_tables{$tablename}{Engine}\n"; if($db_tables{$tablename}{Name} eq "current") { - $drc = $db_tables{$tablename}{Rows}; - } + $drc = $db_tables{$tablename}{Rows}; + } if($db_tables{$tablename}{Name} eq "history") { - $drh = $db_tables{$tablename}{Rows}; - } - } + $drh = $db_tables{$tablename}{Rows}; + } + } } $st_e .= "-- EOF TABLE-INFO"; @@ -7444,56 +7456,56 @@ sub mysql_DoDumpClientSide { ($sql_text,$first_insert,$sql_file,$backupfile,$err) = DbRep_NewDumpFilename($sql_text,$dump_path,$dbname,$time_stamp,$character_set); if ($err) { Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($err,""); + $err = encode_base64($err,""); return "$name|''|$err|''|''|''|''|''|''|''"; } else { Log3 ($name, 5, "DbRep $name - New dumpfile $sql_file has been created."); } ##################### jede einzelne Tabelle dumpen ######################## - + $totalrecords = 0; foreach $tablename (@tables) { # first get CREATE TABLE Statement if($dbpraefix eq "" || ($dbpraefix ne "" && substr($tablename,0,length($dbpraefix)) eq $dbpraefix)) { Log3 ($name, 3, "DbRep $name - Dumping table $tablename (Type ".$db_tables{$tablename}{Engine}."):"); - - $a = "\n\n$mysql_commentstring\n$mysql_commentstring"."Table structure for table `$tablename`\n$mysql_commentstring\n"; - if ($db_tables{$tablename}{Engine} ne 'VIEW' ) { + $a = "\n\n$mysql_commentstring\n$mysql_commentstring"."Table structure for table `$tablename`\n$mysql_commentstring\n"; + + if ($db_tables{$tablename}{Engine} ne 'VIEW' ) { $a .= "DROP TABLE IF EXISTS `$tablename`;\n"; } else { $a .= "DROP VIEW IF EXISTS `$tablename`;\n"; } - $sql_text .= $a; + $sql_text .= $a; $sql_create = "SHOW CREATE TABLE `$tablename`"; - - Log3 ($name, 5, "DbRep $name - current query: $sql_create "); - eval { $sth = $dbh->prepare($sql_create); - $sth->execute; - }; - if ($@) { + Log3 ($name, 5, "DbRep $name - current query: $sql_create "); + + eval { $sth = $dbh->prepare($sql_create); + $sth->execute; + }; + if ($@) { $e = $@; - $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; + $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($e,""); - $dbh->disconnect; + $err = encode_base64($e,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } - @ergebnis = $sth->fetchrow; + @ergebnis = $sth->fetchrow; $sth->finish; $a = $ergebnis[1].";\n"; - if (length($a) < 10) { + if (length($a) < 10) { $err = "Fatal error! Couldn't read CREATE-Statement of table `$tablename`! This backup might be incomplete! Check your database for errors. MySQL-Error: ".$DBI::errstr; Log3 ($name, 2, "DbRep $name - $err"); } else { $sql_text .= $a; - # verbose 5 logging + # verbose 5 logging Log3 ($name, 5, "DbRep $name - Create-SQL found:\n$a"); } @@ -7507,26 +7519,26 @@ sub mysql_DoDumpClientSide { # build fieldlist $fieldlist = "("; $sql_create = "SHOW FIELDS FROM `$tablename`"; - Log3 ($name, 5, "DbRep $name - current query: $sql_create "); + Log3 ($name, 5, "DbRep $name - current query: $sql_create "); - eval { $sth = $dbh->prepare($sql_create); - $sth->execute; - }; + eval { $sth = $dbh->prepare($sql_create); + $sth->execute; + }; if ($@) { $e = $@; - $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; + $err = "Fatal error sending Query '".$sql_create."' ! MySQL-Error: ".$e; Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($e,""); - $dbh->disconnect; + $err = encode_base64($e,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } - while (@ar = $sth->fetchrow) { + while (@ar = $sth->fetchrow) { $fieldlist .= "`".$ar[0]."`,"; } $sth->finish; - - # verbose 5 logging + + # verbose 5 logging Log3 ($name, 5, "DbRep $name - Fieldlist found: $fieldlist"); # remove trailing ',' and add ')' @@ -7534,9 +7546,9 @@ sub mysql_DoDumpClientSide { # how many rows $rct = $db_tables{$tablename}{Rows}; - Log3 ($name, 5, "DbRep $name - Number entries of table $tablename: $rct"); + Log3 ($name, 5, "DbRep $name - Number entries of table $tablename: $rct"); - # create insert Statements + # create insert Statements for (my $ttt = 0; $ttt < $rct; $ttt += $dumpspeed) { # default beginning for INSERT-String $insert = "INSERT INTO `$tablename` $fieldlist VALUES ("; @@ -7545,19 +7557,19 @@ sub mysql_DoDumpClientSide { # get rows (parts) $sql_daten = "SELECT * FROM `$tablename` LIMIT ".$ttt.",".$dumpspeed.";"; - eval { $sth = $dbh->prepare($sql_daten); - $sth->execute; - }; - if ($@) { + eval { $sth = $dbh->prepare($sql_daten); + $sth->execute; + }; + if ($@) { $e = $@; - $err = "Fatal error sending Query '".$sql_daten."' ! MySQL-Error: ".$e; + $err = "Fatal error sending Query '".$sql_daten."' ! MySQL-Error: ".$e; Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($e,""); - $dbh->disconnect; + $err = encode_base64($e,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } - while ( @ar = $sth->fetchrow) { + while ( @ar = $sth->fetchrow) { #Start the insert if($first_insert == 0) { $a = "\n$insert"; @@ -7572,9 +7584,9 @@ sub mysql_DoDumpClientSide { $a = substr($a,0, length($a)-1).");"; $sql_text .= $a; - if($memory_limit > 0 && length($sql_text) > $memory_limit) { + if($memory_limit > 0 && length($sql_text) > $memory_limit) { ($filesize,$err) = DbRep_WriteToDumpFile($sql_text,$sql_file); - # Log3 ($name, 5, "DbRep $name - Memory limit '$memory_limit' exceeded. Wrote to '$sql_file'. Filesize: '".DbRep_byteOutput($filesize)."'"); + # Log3 ($name, 5, "DbRep $name - Memory limit '$memory_limit' exceeded. Wrote to '$sql_file'. Filesize: '".DbRep_byteOutput($filesize)."'"); $sql_text = ""; } } @@ -7589,9 +7601,9 @@ sub mysql_DoDumpClientSide { if ($db_tables{$tablename}{skip_data} == 0) { Log3 ($name, 3, "DbRep $name - $rct records inserted (size of backupfile: ".DbRep_byteOutput($filesize).")") if($filesize); - $totalrecords += $rct; + $totalrecords += $rct; } else { - Log3 ($name, 3, "DbRep $name - Dumping structure of $tablename (Type ".$db_tables{$tablename}{Engine}." ) (size of backupfile: ".DbRep_byteOutput($filesize).")"); + Log3 ($name, 3, "DbRep $name - Dumping structure of $tablename (Type ".$db_tables{$tablename}{Engine}." ) (size of backupfile: ".DbRep_byteOutput($filesize).")"); } } @@ -7676,7 +7688,7 @@ sub mysql_DoDumpServerSide { # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); return "$name|''|$err|''|''|''|''|''|''|''"; } @@ -7691,24 +7703,24 @@ sub mysql_DoDumpServerSide { eval { $sth = $dbh->prepare($query); $sth->execute; - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } while ( $value = $sth->fetchrow_hashref()) { - # verbose 5 logging - Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); + # verbose 5 logging + Log3 ($name, 5, "DbRep $name - ......... Table definition found: ........."); foreach my $tk (sort(keys(%$value))) { Log3 ($name, 5, "DbRep $name - $tk: $value->{$tk}") if(defined($value->{$tk}) && $tk ne "Rows"); } - Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); - + Log3 ($name, 5, "DbRep $name - ......... Table definition END ............"); + # check for old MySQL3-Syntax Type=xxx - if (defined $value->{Type}) { + if (defined $value->{Type}) { # port old index type to index engine, so we can use the index Engine in the rest of the script $value->{Engine} = $value->{Type}; } @@ -7721,20 +7733,20 @@ sub mysql_DoDumpServerSide { if (@tablenames < 1) { $err = "There are no tables inside database $dbname ! It doesn't make sense to backup an empty database. Skipping this one."; - Log3 ($name, 2, "DbRep $name - $err"); - $err = encode_base64($@,""); - $dbh->disconnect; + Log3 ($name, 2, "DbRep $name - $err"); + $err = encode_base64($@,""); + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { # Tabellen optimieren vor dem Dump - $hash->{HELPER}{DBTABLES} = \%db_tables; + $hash->{HELPER}{DBTABLES} = \%db_tables; ($err,$db_MB_start,$db_MB_end) = DbRep_mysqlOptimizeTables($hash,$dbh,@tablenames); - if ($err) { - $err = encode_base64($err,""); - return "$name|''|$err|''|''|''|''|''|''|''"; - } + if ($err) { + $err = encode_base64($err,""); + return "$name|''|$err|''|''|''|''|''|''|''"; + } } Log3 ($name, 3, "DbRep $name - Starting dump of database '$dbname', table '$table'"); @@ -7762,7 +7774,7 @@ sub mysql_DoDumpServerSide { # error bei sql-execute $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; } @@ -7850,34 +7862,34 @@ sub DbRep_sqliteDoDump { # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { # Vacuum vor Dump - # Anfangsgröße ermitteln + # Anfangsgröße ermitteln $db_MB = (split(' ',qx(du -m $dbname)))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); Log3 ($name, 3, "DbRep $name - Size of database $dbname before optimize (MB): $db_MB"); $query ="VACUUM"; - Log3 ($name, 5, "DbRep $name - current query: $query "); + Log3 ($name, 5, "DbRep $name - current query: $query "); Log3 ($name, 3, "DbRep $name - VACUUM database $dbname...."); eval {$sth = $dbh->prepare($query); $r = $sth->execute(); }; - if ($@) { + if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! SQLite-Error: ".$@); - $sth->finish; - $dbh->disconnect; + $sth->finish; + $dbh->disconnect; return "$name|''|$err|''|''|''|''|''|''|''"; - } - - # Endgröße ermitteln - $db_MB = (split(' ',qx(du -m $dbname)))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); - Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB"); + } + + # Endgröße ermitteln + $db_MB = (split(' ',qx(du -m $dbname)))[0] if ($^O =~ m/linux/i || $^O =~ m/unix/i); + Log3 ($name, 3, "DbRep $name - Size of database $dbname after optimize (MB): $db_MB"); } $dbname = (split /[\/]/, $dbname)[-1]; @@ -8141,7 +8153,7 @@ sub DbRep_sqliteRestore { # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); return "$name|''|$err|''|''"; } @@ -8218,7 +8230,7 @@ sub mysql_RestoreServerSide { # Verbindung mit DB eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; if ($@) { - $err = encode_base64($@,""); + $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); return "$name|''|$err|''|''"; } @@ -8248,7 +8260,7 @@ sub mysql_RestoreServerSide { # error bei sql-execute $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''"; } @@ -8294,7 +8306,7 @@ sub mysql_RestoreClientSide { eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1, AutoCommit => 1 });}; if ($@) { $e = $@; - $err = encode_base64($e,""); + $err = encode_base64($e,""); Log3 ($name, 1, "DbRep $name - $e"); return "$name|''|$err|''|''"; } @@ -8354,7 +8366,7 @@ sub mysql_RestoreClientSide { Log3 ($name, 1, "DbRep $name - last query: $line"); Log3 ($name, 1, "DbRep $name - $e"); close(FH); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''"; } $line = ''; @@ -8393,7 +8405,7 @@ sub mysql_RestoreClientSide { Log3 ($name, 1, "DbRep $name - last query: $query"); Log3 ($name, 1, "DbRep $name - $e"); close(FH); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''"; } $i = 0; @@ -8419,7 +8431,7 @@ sub mysql_RestoreClientSide { Log3 ($name, 1, "DbRep $name - last query: $query"); Log3 ($name, 1, "DbRep $name - $e"); close(FH); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''"; } $i = 0; @@ -8438,7 +8450,7 @@ sub mysql_RestoreClientSide { Log3 ($name, 1, "DbRep $name - last query: $query"); Log3 ($name, 1, "DbRep $name - $e"); close(FH); - $dbh->disconnect; + $dbh->disconnect; return "$name|''|$err|''|''"; } $dbh->disconnect; @@ -8578,7 +8590,7 @@ sub DbRep_syncStandby { eval{ $sth = $dbh->prepare($sql); $sth->execute(); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); @@ -8672,7 +8684,7 @@ sub DbRep_reduceLog { my $dbpassword = $attr{"sec$dblogname"}{secret}; my @a = @{$hash->{HELPER}{REDUCELOG}}; my $rlpar = join(" ", @a); - my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0; + my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0; my ($ret,$row,$filter,$exclude,$c,$day,$hour,$lastHour,$updDate,$updHour,$average,$processingDay,$lastUpdH); my (%hourlyKnown,%averageHash,@excludeRegex,@dayRows,@averageUpd,@averageUpdD); @@ -8680,17 +8692,17 @@ sub DbRep_reduceLog { my ($dbh,$err,$brt); BlockingInformParent("DbRep_delHashValFromBlocking", [$name, "HELPER","REDUCELOG"], 1); - - # ausfiltern von optionalen Zeitangaben, z.B. 700:750 -> Rest zur Einhaltung des ursprünglichen Formats nach @a schreiben - my @b; + + # ausfiltern von optionalen Zeitangaben, z.B. 700:750 -> Rest zur Einhaltung des ursprünglichen Formats nach @a schreiben + my @b; foreach (@a) { - next if($_ =~ /\b(\d+(:\d+)?)\b/); + next if($_ =~ /\b(\d+(:\d+)?)\b/); push @b, $_; } - @a = @b; - + @a = @b; + Log3 ($name, 5, "DbRep $name -> Start DbLog_reduceLog"); - + eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1, mysql_enable_utf8 => $utf8 });}; if ($@) { @@ -8723,9 +8735,9 @@ sub DbRep_reduceLog { ."TIMESTAMP <= '$ots'".($nts?" AND TIMESTAMP >= '$nts' ":" ")."ORDER BY TIMESTAMP ASC"; } elsif ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createCommonSql($hash,$selspec,$d,$r,"'$nts'","'$ots'",$addon); - } else { - $sql = DbRep_createCommonSql($hash,$selspec,$d,$r,undef,undef,$addon); - } + } else { + $sql = DbRep_createCommonSql($hash,$selspec,$d,$r,undef,undef,$addon); + } Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); @@ -8743,20 +8755,20 @@ sub DbRep_reduceLog { (($edanz || $edevswc)? "Devs: ".($edevs?$edevs:'').($edevswc?$edevswc:'') : '').(($eranz || $erdswc) ? " Readings: ".($ereading?$ereading:'').($erdswc?$erdswc:'') : '')) )); if ($ots) { - my ($sth_del, $sth_upd, $sth_delD, $sth_updD, $sth_get); + my ($sth_del, $sth_upd, $sth_delD, $sth_updD, $sth_get); eval { $sth_del = $dbh->prepare_cached("DELETE FROM history WHERE (DEVICE=?) AND (READING=?) AND (TIMESTAMP=?) AND (VALUE=?)"); $sth_upd = $dbh->prepare_cached("UPDATE history SET TIMESTAMP=?, EVENT=?, VALUE=? WHERE (DEVICE=?) AND (READING=?) AND (TIMESTAMP=?) AND (VALUE=?)"); $sth_delD = $dbh->prepare_cached("DELETE FROM history WHERE (DEVICE=?) AND (READING=?) AND (TIMESTAMP=?)"); $sth_updD = $dbh->prepare_cached("UPDATE history SET TIMESTAMP=?, EVENT=?, VALUE=? WHERE (DEVICE=?) AND (READING=?) AND (TIMESTAMP=?)"); $sth_get = $dbh->prepare($sql); - }; + }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); return "$name|''|$err|''"; } - - eval { $sth_get->execute(); }; + + eval { $sth_get->execute(); }; if ($@) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); @@ -8782,24 +8794,24 @@ sub DbRep_reduceLog { $dbh->{RaiseError} = 1; $dbh->{PrintError} = 0; eval {$dbh->begin_work() if($dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } eval { - my $i = 0; - my $k = 1; - my $th = ($#dayRows <= 2000)?100:($#dayRows <= 30000)?1000:10000; + my $i = 0; + my $k = 1; + my $th = ($#dayRows <= 2000)?100:($#dayRows <= 30000)?1000:10000; for my $delRow (@dayRows) { if($day != 00 || $delRow->[0] !~ /$lastHour/) { Log3 ($name, 4, "DbRep $name - DELETE FROM history WHERE (DEVICE=$delRow->[1]) AND (READING=$delRow->[3]) AND (TIMESTAMP=$delRow->[0]) AND (VALUE=$delRow->[4])"); $sth_del->execute(($delRow->[1], $delRow->[3], $delRow->[0], $delRow->[4])); - $i++; - if($i == $th) { - my $prog = $k * $i; - Log3 ($name, 3, "DbRep $name - reduceLog deletion progress of day: $processingDay is: $prog"); - $i = 0; - $k++; - } + $i++; + if($i == $th) { + my $prog = $k * $i; + Log3 ($name, 3, "DbRep $name - reduceLog deletion progress of day: $processingDay is: $prog"); + $i = 0; + $k++; + } } } }; @@ -8807,13 +8819,13 @@ sub DbRep_reduceLog { $err = $@; Log3 ($name, 2, "DbRep $name - reduceLog ! FAILED ! for day $processingDay: $err"); eval {$dbh->rollback() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } $ret = 0; } else { eval {$dbh->commit() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } } @@ -8827,7 +8839,7 @@ sub DbRep_reduceLog { $dbh->{RaiseError} = 1; $dbh->{PrintError} = 0; eval {$dbh->begin_work() if($dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } eval { @@ -8842,9 +8854,9 @@ sub DbRep_reduceLog { $updateCount += $c; Log3 ($name, 3, "DbRep $name - reduceLog (hourly-average) updating $c records of day: $processingDay") if($c); # else only push to @averageUpdD - my $i = 0; - my $k = 1; - my $th = ($c <= 2000)?100:($c <= 30000)?1000:10000; + my $i = 0; + my $k = 1; + my $th = ($c <= 2000)?100:($c <= 30000)?1000:10000; for my $hourHash (@averageUpd) { for my $hourKey (keys %$hourHash) { if ($hourHash->{$hourKey}->[0]) { # true if reading is a number @@ -8855,35 +8867,35 @@ sub DbRep_reduceLog { $sum = 0; Log3 ($name, 4, "DbRep $name - UPDATE history SET TIMESTAMP=$updDate $updHour:30:00, EVENT='rl_av_h', VALUE=$average WHERE DEVICE=$hourHash->{$hourKey}->[1] AND READING=$hourHash->{$hourKey}->[3] AND TIMESTAMP=$hourHash->{$hourKey}->[0] AND VALUE=$hourHash->{$hourKey}->[4]->[0]"); $sth_upd->execute(("$updDate $updHour:30:00", 'rl_av_h', $average, $hourHash->{$hourKey}->[1], $hourHash->{$hourKey}->[3], $hourHash->{$hourKey}->[0], $hourHash->{$hourKey}->[4]->[0])); - - $i++; - if($i == $th) { - my $prog = $k * $i; - Log3 ($name, 3, "DbRep $name - reduceLog (hourly-average) updating progress of day: $processingDay is: $prog"); - $i = 0; - $k++; - } + + $i++; + if($i == $th) { + my $prog = $k * $i; + Log3 ($name, 3, "DbRep $name - reduceLog (hourly-average) updating progress of day: $processingDay is: $prog"); + $i = 0; + $k++; + } push(@averageUpdD, ["$updDate $updHour:30:00", 'rl_av_h', $average, $hourHash->{$hourKey}->[1], $hourHash->{$hourKey}->[3], $updDate]) if (defined($a[3]) && $a[3] =~ /average=day/i); } else { push(@averageUpdD, [$hourHash->{$hourKey}->[0], $hourHash->{$hourKey}->[2], $hourHash->{$hourKey}->[4]->[0], $hourHash->{$hourKey}->[1], $hourHash->{$hourKey}->[3], $updDate]) if (defined($a[3]) && $a[3] =~ /average=day/i); } - } - } + } + } } }; if ($@) { $err = $@; Log3 ($name, 2, "DbRep $name - reduceLog average=hour ! FAILED ! for day $processingDay: $err"); eval {$dbh->rollback() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } @averageUpdD = (); } else { eval {$dbh->commit() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); - } + } } $dbh->{RaiseError} = 0; $dbh->{PrintError} = 1; @@ -8894,7 +8906,7 @@ sub DbRep_reduceLog { $dbh->{RaiseError} = 1; $dbh->{PrintError} = 0; eval {$dbh->begin_work() if($dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } eval { @@ -8915,10 +8927,10 @@ sub DbRep_reduceLog { $deletedCount += $c; $updateCount += keys(%averageHash); - my ($id,$iu) = 0; - my ($kd,$ku) = 1; - my $thd = ($c <= 2000)?100:($c <= 30000)?1000:10000; - my $thu = ((keys %averageHash) <= 2000)?100:((keys %averageHash) <= 30000)?1000:10000; + my ($id,$iu) = 0; + my ($kd,$ku) = 1; + my $thd = ($c <= 2000)?100:($c <= 30000)?1000:10000; + my $thu = ((keys %averageHash) <= 2000)?100:((keys %averageHash) <= 30000)?1000:10000; Log3 ($name, 3, "DbRep $name - reduceLog (daily-average) updating ".(keys %averageHash).", deleting $c records of day: $processingDay") if(keys %averageHash); for my $reading (keys %averageHash) { $average = sprintf('%.3f', $averageHash{$reading}->{sum}/scalar(@{$averageHash{$reading}->{tedr}})); @@ -8926,36 +8938,36 @@ sub DbRep_reduceLog { for (@{$averageHash{$reading}->{tedr}}) { Log3 ($name, 5, "DbRep $name - DELETE FROM history WHERE DEVICE='$_->[2]' AND READING='$_->[3]' AND TIMESTAMP='$_->[0]'"); $sth_delD->execute(($_->[2], $_->[3], $_->[0])); - - $id++; - if($id == $thd) { - my $prog = $kd * $id; - Log3 ($name, 3, "DbRep $name - reduceLog (daily-average) deleting progress of day: $processingDay is: $prog"); - $id = 0; - $kd++; - } + + $id++; + if($id == $thd) { + my $prog = $kd * $id; + Log3 ($name, 3, "DbRep $name - reduceLog (daily-average) deleting progress of day: $processingDay is: $prog"); + $id = 0; + $kd++; + } } Log3 ($name, 4, "DbRep $name - UPDATE history SET TIMESTAMP=$averageHash{$reading}->{date} 12:00:00, EVENT='rl_av_d', VALUE=$average WHERE (DEVICE=$lastUpdH->[2]) AND (READING=$lastUpdH->[3]) AND (TIMESTAMP=$lastUpdH->[0])"); $sth_updD->execute(($averageHash{$reading}->{date}." 12:00:00", 'rl_av_d', $average, $lastUpdH->[2], $lastUpdH->[3], $lastUpdH->[0])); - - $iu++; - if($iu == $thu) { - my $prog = $ku * $id; - Log3 ($name, 3, "DbRep $name - reduceLog (daily-average) updating progress of day: $processingDay is: $prog"); - $iu = 0; - $ku++; - } - } + + $iu++; + if($iu == $thu) { + my $prog = $ku * $id; + Log3 ($name, 3, "DbRep $name - reduceLog (daily-average) updating progress of day: $processingDay is: $prog"); + $iu = 0; + $ku++; + } + } }; if ($@) { Log3 ($name, 3, "DbRep $name - reduceLog average=day ! FAILED ! for day $processingDay"); eval {$dbh->rollback() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } } else { eval {$dbh->commit() if(!$dbh->{AutoCommit});}; - if ($@) { + if ($@) { Log3 ($name, 2, "DbRep $name - DbRep_reduceLog - $@"); } } @@ -9014,10 +9026,10 @@ sub DbRep_reduceLog { return "$name|''|$err|''"; } - $dbh->disconnect(); + $dbh->disconnect(); $ret = encode_base64($ret,""); - Log3 ($name, 5, "DbRep $name -> DbRep_reduceLogNbl finished"); - + Log3 ($name, 5, "DbRep $name -> DbRep_reduceLogNbl finished"); + return "$name|$ret|0|$brt"; } @@ -9253,10 +9265,10 @@ sub DbRep_createCommonSql { if(defined $valfilter) { if ($dbmodel eq "POSTGRESQL") { - $vf = "VALUE ~ '$valfilter' AND "; - } else { - $vf = "VALUE REGEXP '$valfilter' AND "; - } + $vf = "VALUE ~ '$valfilter' AND "; + } else { + $vf = "VALUE REGEXP '$valfilter' AND "; + } } $sql = $selspec." "; @@ -9264,16 +9276,16 @@ sub DbRep_createCommonSql { $sql .= "( " if(($idanz || $idevswc) && $idevs !~ m(^%$)); if($idevswc && $idevs !~ m(^%$)) { @dwc = split(",",$idevswc); - my $i = 1; - my $len = scalar(@dwc); - foreach(@dwc) { - if($i<$len) { - $sql .= "DEVICE LIKE '$_' OR "; - } else { - $sql .= "DEVICE LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@dwc); + foreach(@dwc) { + if($i<$len) { + $sql .= "DEVICE LIKE '$_' OR "; + } else { + $sql .= "DEVICE LIKE '$_' "; + } + $i++; + } if($idanz) { $sql .= "OR "; } @@ -9284,9 +9296,9 @@ sub DbRep_createCommonSql { # excluded devices if($edevswc) { @dwc = split(",",$edevswc); - foreach(@dwc) { - $sql .= "DEVICE NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "DEVICE NOT LIKE '$_' AND "; + } } $sql .= "DEVICE != '$edevs' " if($edanz == 1 && $edanz && $edevs !~ m(^%$)); $sql .= "DEVICE NOT IN ($edevs) " if($edanz > 1); @@ -9295,16 +9307,16 @@ sub DbRep_createCommonSql { $sql .= "( " if(($iranz || $irdswc) && $ireading !~ m(^%$)); if($irdswc && $ireading !~ m(^%$)) { @rwc = split(",",$irdswc); - my $i = 1; - my $len = scalar(@rwc); - foreach(@rwc) { - if($i<$len) { - $sql .= "READING LIKE '$_' OR "; - } else { - $sql .= "READING LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@rwc); + foreach(@rwc) { + if($i<$len) { + $sql .= "READING LIKE '$_' OR "; + } else { + $sql .= "READING LIKE '$_' "; + } + $i++; + } if($iranz) { $sql .= "OR "; } @@ -9315,9 +9327,9 @@ sub DbRep_createCommonSql { # excluded readings if($erdswc) { @dwc = split(",",$erdswc); - foreach(@dwc) { - $sql .= "READING NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "READING NOT LIKE '$_' AND "; + } } $sql .= "READING != '$ereading' " if($eranz && $eranz == 1 && $ereading !~ m(\%)); $sql .= "READING NOT IN ($ereading) " if($eranz > 1); @@ -9329,10 +9341,10 @@ sub DbRep_createCommonSql { $sql .= "TIMESTAMP >= $tf AND TIMESTAMP ".($tnfull?"<=":"<")." $tn "; } else { if ($dbmodel eq "POSTGRESQL") { - $sql .= "true "; - } else { - $sql .= "1 "; - } + $sql .= "true "; + } else { + $sql .= "1 "; + } } $sql .= "$addon;"; @@ -9359,10 +9371,10 @@ sub DbRep_createSelectSql { if(defined $valfilter) { if ($dbmodel eq "POSTGRESQL") { - $vf = "VALUE ~ '$valfilter' AND "; - } else { - $vf = "VALUE REGEXP '$valfilter' AND "; - } + $vf = "VALUE ~ '$valfilter' AND "; + } else { + $vf = "VALUE REGEXP '$valfilter' AND "; + } } $sql = "SELECT $selspec FROM $table where "; @@ -9370,16 +9382,16 @@ sub DbRep_createSelectSql { $sql .= "( " if(($idanz || $idevswc) && $idevs !~ m(^%$)); if($idevswc && $idevs !~ m(^%$)) { @dwc = split(",",$idevswc); - my $i = 1; - my $len = scalar(@dwc); - foreach(@dwc) { - if($i<$len) { - $sql .= "DEVICE LIKE '$_' OR "; - } else { - $sql .= "DEVICE LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@dwc); + foreach(@dwc) { + if($i<$len) { + $sql .= "DEVICE LIKE '$_' OR "; + } else { + $sql .= "DEVICE LIKE '$_' "; + } + $i++; + } if($idanz) { $sql .= "OR "; } @@ -9390,9 +9402,9 @@ sub DbRep_createSelectSql { # excluded devices if($edevswc) { @dwc = split(",",$edevswc); - foreach(@dwc) { - $sql .= "DEVICE NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "DEVICE NOT LIKE '$_' AND "; + } } $sql .= "DEVICE != '$edevs' " if($edanz == 1 && $edanz && $edevs !~ m(^%$)); $sql .= "DEVICE NOT IN ($edevs) " if($edanz > 1); @@ -9401,16 +9413,16 @@ sub DbRep_createSelectSql { $sql .= "( " if(($iranz || $irdswc) && $ireading !~ m(^%$)); if($irdswc && $ireading !~ m(^%$)) { @rwc = split(",",$irdswc); - my $i = 1; - my $len = scalar(@rwc); - foreach(@rwc) { - if($i<$len) { - $sql .= "READING LIKE '$_' OR "; - } else { - $sql .= "READING LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@rwc); + foreach(@rwc) { + if($i<$len) { + $sql .= "READING LIKE '$_' OR "; + } else { + $sql .= "READING LIKE '$_' "; + } + $i++; + } if($iranz) { $sql .= "OR "; } @@ -9421,9 +9433,9 @@ sub DbRep_createSelectSql { # excluded readings if($erdswc) { @dwc = split(",",$erdswc); - foreach(@dwc) { - $sql .= "READING NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "READING NOT LIKE '$_' AND "; + } } $sql .= "READING != '$ereading' " if($eranz && $eranz == 1 && $ereading !~ m(\%)); $sql .= "READING NOT IN ($ereading) " if($eranz > 1); @@ -9435,10 +9447,10 @@ sub DbRep_createSelectSql { $sql .= "TIMESTAMP >= $tf AND TIMESTAMP ".($tnfull?"<=":"<")." $tn "; } else { if ($dbmodel eq "POSTGRESQL") { - $sql .= "true "; - } else { - $sql .= "1 "; - } + $sql .= "true "; + } else { + $sql .= "1 "; + } } $sql .= "$addon;"; @@ -9459,7 +9471,7 @@ sub DbRep_createDeleteSql { if($table eq "current") { $sql = "delete FROM $table; "; - return $sql; + return $sql; } my ($idevs,$idevswc,$idanz,$ireading,$iranz,$irdswc,$edevs,$edevswc,$edanz,$ereading,$eranz,$erdswc) = DbRep_specsForSql($hash,$device,$reading); @@ -9470,10 +9482,10 @@ sub DbRep_createDeleteSql { if(defined $valfilter) { if ($dbmodel eq "POSTGRESQL") { - $vf = "VALUE ~ '$valfilter' AND "; - } else { - $vf = "VALUE REGEXP '$valfilter' AND "; - } + $vf = "VALUE ~ '$valfilter' AND "; + } else { + $vf = "VALUE REGEXP '$valfilter' AND "; + } } $sql = "delete FROM $table where "; @@ -9481,16 +9493,16 @@ sub DbRep_createDeleteSql { $sql .= "( " if(($idanz || $idevswc) && $idevs !~ m(^%$)); if($idevswc && $idevs !~ m(^%$)) { @dwc = split(",",$idevswc); - my $i = 1; - my $len = scalar(@dwc); - foreach(@dwc) { - if($i<$len) { - $sql .= "DEVICE LIKE '$_' OR "; - } else { - $sql .= "DEVICE LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@dwc); + foreach(@dwc) { + if($i<$len) { + $sql .= "DEVICE LIKE '$_' OR "; + } else { + $sql .= "DEVICE LIKE '$_' "; + } + $i++; + } if($idanz) { $sql .= "OR "; } @@ -9501,9 +9513,9 @@ sub DbRep_createDeleteSql { # excluded devices if($edevswc) { @dwc = split(",",$edevswc); - foreach(@dwc) { - $sql .= "DEVICE NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "DEVICE NOT LIKE '$_' AND "; + } } $sql .= "DEVICE != '$edevs' " if($edanz == 1 && $edanz && $edevs !~ m(^%$)); $sql .= "DEVICE NOT IN ($edevs) " if($edanz > 1); @@ -9512,16 +9524,16 @@ sub DbRep_createDeleteSql { $sql .= "( " if(($iranz || $irdswc) && $ireading !~ m(^%$)); if($irdswc && $ireading !~ m(^%$)) { @rwc = split(",",$irdswc); - my $i = 1; - my $len = scalar(@rwc); - foreach(@rwc) { - if($i<$len) { - $sql .= "READING LIKE '$_' OR "; - } else { - $sql .= "READING LIKE '$_' "; - } - $i++; - } + my $i = 1; + my $len = scalar(@rwc); + foreach(@rwc) { + if($i<$len) { + $sql .= "READING LIKE '$_' OR "; + } else { + $sql .= "READING LIKE '$_' "; + } + $i++; + } if($iranz) { $sql .= "OR "; } @@ -9532,9 +9544,9 @@ sub DbRep_createDeleteSql { # excluded readings if($erdswc) { @dwc = split(",",$erdswc); - foreach(@dwc) { - $sql .= "READING NOT LIKE '$_' AND "; - } + foreach(@dwc) { + $sql .= "READING NOT LIKE '$_' AND "; + } } $sql .= "READING != '$ereading' " if($eranz && $eranz == 1 && $ereading !~ m(\%)); $sql .= "READING NOT IN ($ereading) " if($eranz > 1); @@ -9546,10 +9558,10 @@ sub DbRep_createDeleteSql { $sql .= "TIMESTAMP >= '$tf' AND TIMESTAMP ".($tnfull?"<=":"<")." '$tn' $addon;"; } else { if ($dbmodel eq "POSTGRESQL") { - $sql .= "true;"; - } else { - $sql .= "1;"; - } + $sql .= "true;"; + } else { + $sql .= "1;"; + } } return $sql; @@ -9570,7 +9582,7 @@ sub DbRep_specsForSql { my ($idanz,$edanz) = (0,0); if($device =~ /EXCLUDE=/i) { ($idevice,$edevice) = split(/EXCLUDE=/i,$device); - $idevice = $idevice?DbRep_trim($idevice):"%"; + $idevice = $idevice?DbRep_trim($idevice):"%"; } else { $idevice = $device; } @@ -9582,13 +9594,13 @@ sub DbRep_specsForSql { $e =~ s/%/\.*/g if($e !~ /^%$/); # SQL Wildcard % auflösen @edvspcs = devspec2array($e); @edvspcs = map {s/\.\*/%/g; $_; } @edvspcs; - if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten - $edevswc .= "," if($edevswc); - $edevswc .= join(",",@edvspcs); - } else { - $edevs .= "," if($edevs); - $edevs .= join(",",@edvspcs); - } + if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten + $edevswc .= "," if($edevswc); + $edevswc .= join(",",@edvspcs); + } else { + $edevs .= "," if($edevs); + $edevs .= join(",",@edvspcs); + } } } $edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf1) @@ -9600,12 +9612,12 @@ sub DbRep_specsForSql { @idvspcs = devspec2array($d); @idvspcs = map {s/\.\*/%/g; $_; } @idvspcs; if((map {$_ =~ /%/;} @idvspcs) && $idevice !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten - $idevswc .= "," if($idevswc); - $idevswc .= join(",",@idvspcs); + $idevswc .= "," if($idevswc); + $idevswc .= join(",",@idvspcs); } else { - $idevs .= "," if($idevs); - $idevs .= join(",",@idvspcs); - } + $idevs .= "," if($idevs); + $idevs .= join(",",@idvspcs); + } } $idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf1) @@ -9621,12 +9633,12 @@ sub DbRep_specsForSql { foreach my $in (@idvs) { my $inc = 1; foreach(@edvs) { - next if($in ne $_); - $inc = 0; + next if($in ne $_); + $inc = 0; $nl .= "|" if($nl); $nl .= $_; # Liste der entfernten devices füllen - } - push(@residevs, $in) if($inc); + } + push(@residevs, $in) if($inc); } $edevs = join(",", map {($_ !~ /$nl/)?$_:();} @edvs) if($nl); @@ -9636,12 +9648,12 @@ sub DbRep_specsForSql { foreach my $inwc (@idvswc) { my $inc = 1; foreach(@edvswc) { - next if($inwc ne $_); - $inc = 0; + next if($inwc ne $_); + $inc = 0; $nlwc .= "|" if($nlwc); $nlwc .= $_; # Liste der entfernten devices füllen - } - push(@residevswc, $inwc) if($inc); + } + push(@residevswc, $inwc) if($inc); } $edevswc = join(",", map {($_ !~ /$nlwc/)?$_:();} @edvswc) if($nlwc); # Log3($name, 1, "DbRep $name - nlwc: $nlwc, mwc: @mwc"); @@ -9654,14 +9666,14 @@ sub DbRep_specsForSql { $idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf2) if($idanz > 1) { - $idevs =~ s/,/','/g; - $idevs = "'".$idevs."'"; + $idevs =~ s/,/','/g; + $idevs = "'".$idevs."'"; } $edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf2) if($edanz > 1) { - $edevs =~ s/,/','/g; - $edevs = "'".$edevs."'"; + $edevs =~ s/,/','/g; + $edevs = "'".$edevs."'"; } @@ -9675,7 +9687,7 @@ sub DbRep_specsForSql { if($reading =~ /EXCLUDE=/i) { ($ireading,$ereading) = split(/EXCLUDE=/i,$reading); - $ireading = $ireading?DbRep_trim($ireading):"%"; + $ireading = $ireading?DbRep_trim($ireading):"%"; } else { $ireading = $reading; } @@ -9683,13 +9695,13 @@ sub DbRep_specsForSql { if($ereading) { @erds = split(",",$ereading); foreach my $e (@erds) { - if($e =~ /%/ && $e !~ /^%$/) { # Readings mit Wildcard (%) erfassen - $erdswc .= "," if($erdswc); - $erdswc .= $e; - } else { - $erdgs .= "," if($erdgs); - $erdgs .= $e; - } + if($e =~ /%/ && $e !~ /^%$/) { # Readings mit Wildcard (%) erfassen + $erdswc .= "," if($erdswc); + $erdswc .= $e; + } else { + $erdgs .= "," if($erdgs); + $erdgs .= $e; + } } } @@ -9701,24 +9713,24 @@ sub DbRep_specsForSql { $irdswc .= $i; } else { $irdgs .= "," if($irdgs); - $irdgs .= $i; + $irdgs .= $i; } } $iranz = split(",",$irdgs); if($iranz > 1) { - $irdgs =~ s/,/','/g; - $irdgs = "'".$irdgs."'"; + $irdgs =~ s/,/','/g; + $irdgs = "'".$irdgs."'"; } if($ereading) { # Readings exkludiert - $eranz = split(",",$erdgs); - if($eranz > 1) { - $erdgs =~ s/,/','/g; - $erdgs = "'".$erdgs."'"; - } + $eranz = split(",",$erdgs); + if($eranz > 1) { + $erdgs =~ s/,/','/g; + $erdgs = "'".$erdgs."'"; + } } Log3 $name, 5, "DbRep $name - Readings for operation - \n" @@ -9774,7 +9786,7 @@ sub DbRep_checktimeaggr { if ( AttrVal($name,"timestamp_begin", undef) || AttrVal($name,"timestamp_end", undef) || - AttrVal($name,"timeDiffToNow", undef) || + AttrVal($name,"timeDiffToNow", undef) || AttrVal($name,"timeOlderThan", undef) || AttrVal($name,"timeYearPeriod", undef) || $timeoption ) { $IsTimeSet = 1; @@ -9785,32 +9797,32 @@ sub DbRep_checktimeaggr { } if($hash->{LASTCMD} =~ /delSeqDoublets|delDoublets/) { $aggregation = ($aggregation eq "no") ? "day" : $aggregation; # wenn Aggregation "no", für delSeqDoublets immer "day" setzen - $IsAggrSet = 1; + $IsAggrSet = 1; } if($hash->{LASTCMD} =~ /averageValue/ && AttrVal($name,"averageCalcForm","avgArithmeticMean") eq "avgDailyMeanGWS") { $aggregation = "day"; # für Tagesmittelwertberechnung des deutschen Wetterdienstes immer "day" - $IsAggrSet = 1; + $IsAggrSet = 1; } if($hash->{LASTCMD} =~ /^sql|delEntries|fetchrows|deviceRename|readingRename|tableCurrentFillup|reduceLog|\breadingsDifferenceByTimeDelta\b/) { - $IsAggrSet = 0; - $aggregation = "no"; + $IsAggrSet = 0; + $aggregation = "no"; } if($hash->{LASTCMD} =~ /deviceRename|readingRename/) { - $IsTimeSet = 0; + $IsTimeSet = 0; } if($hash->{LASTCMD} =~ /changeValue/) { - if($hash->{HELPER}{COMPLEX}) { + if($hash->{HELPER}{COMPLEX}) { $IsAggrSet = 1; - $aggregation = "day"; + $aggregation = "day"; } else { $IsAggrSet = 0; - $aggregation = "no"; + $aggregation = "no"; } } if($hash->{LASTCMD} =~ /syncStandby/ ) { if($aggregation !~ /minute|hour|day|week/) { $aggregation = "day"; - $IsAggrSet = 1; + $IsAggrSet = 1; } } @@ -9872,7 +9884,7 @@ return; # Übertragen von Readings und Ergebniswerten in ein anderes Device # # autoForward Attribut: -# +# # { # " => "" [=> ]", # " => "" [=> ]", @@ -9930,7 +9942,7 @@ sub DbRep_autoForward { Log3($name, 4, "$name - Forward reading \"$reading\" to \"$ddev:$dr\" "); CommandSetReading(undef, "$ddev $dr $value"); } - + return; } @@ -9946,14 +9958,14 @@ sub DbRep_getblockinginfo { my $len = 99; foreach my $h (values %BC_hash) { next if($h->{terminated} || !$h->{pid}); - my @allk = keys%{$h}; - foreach my $k (@allk) { - Log3 ($name, 5, "DbRep $name -> $k : ".$h->{$k}); - } + my @allk = keys%{$h}; + foreach my $k (@allk) { + Log3 ($name, 5, "DbRep $name -> $k : ".$h->{$k}); + } my $fn = (ref($h->{fn}) ? ref($h->{fn}) : $h->{fn}); my $arg = (ref($h->{arg}) ? ref($h->{arg}) : $h->{arg}); - my $arg1 = substr($arg,0,$len); - $arg1 = $arg1."..." if(length($arg) > $len+1); + my $arg1 = substr($arg,0,$len); + $arg1 = $arg1."..." if(length($arg) > $len+1); my $to = ($h->{timeout} ? $h->{timeout} : "N/A"); my $conn = ($h->{telnet} ? $h->{telnet} : "N/A"); push @rows, "$h->{pid}|ESCAPED|$fn|ESCAPED|$arg1|ESCAPED|$to|ESCAPED|$conn"; @@ -9965,7 +9977,7 @@ sub DbRep_getblockinginfo { if(!@rows) { ReadingsBulkUpdateTimeState($hash,undef,undef,"done - No BlockingCall processes running"); readingsEndUpdate($hash, 1); - return; + return; } my $res = ""; @@ -9980,8 +9992,8 @@ sub DbRep_getblockinginfo { } my $tab = $res."
"; - ReadingsBulkUpdateValue ($hash,"BlockingInfo",$tab); - ReadingsBulkUpdateValue ($hash,"Blocking_Count",$#rows+1); + ReadingsBulkUpdateValue ($hash,"BlockingInfo",$tab); + ReadingsBulkUpdateValue ($hash,"Blocking_Count",$#rows+1); ReadingsBulkUpdateTimeState($hash,undef,undef,"done"); readingsEndUpdate ($hash, 1); @@ -10006,39 +10018,39 @@ sub DbRep_normRelTime { @a = @{$hash->{HELPER}{REDUCELOG}} if($hash->{HELPER}{REDUCELOG}); @a = @{$hash->{HELPER}{DELENTRIES}} if($hash->{HELPER}{DELENTRIES}); foreach (@a) { - if($_ =~ /\b(\d+(:\d+)?)\b/) { - my ($od,$nd) = split(":",$1); # $od - Tage älter als , $nd - Tage neuer als - $toth = "d:$od" if($od); - $tdtn = "d:$nd" if($nd); - } + if($_ =~ /\b(\d+(:\d+)?)\b/) { + my ($od,$nd) = split(":",$1); # $od - Tage älter als , $nd - Tage neuer als + $toth = "d:$od" if($od); + $tdtn = "d:$nd" if($nd); + } } if($tdtn && $tdtn =~ /^\s*[ydhms]:(([\d]+.[\d]+)|[\d]+)\s*/) { $aval = $tdtn; - if($tdtn =~ /.*y:(([\d]+.[\d]+)|[\d]+).*/) { - $y = $tdtn; - $y =~ s/.*y:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($tdtn =~ /.*d:(([\d]+.[\d]+)|[\d]+).*/) { - $d = $tdtn; - $d =~ s/.*d:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($tdtn =~ /.*h:(([\d]+.[\d]+)|[\d]+).*/) { - $h = $tdtn; + if($tdtn =~ /.*y:(([\d]+.[\d]+)|[\d]+).*/) { + $y = $tdtn; + $y =~ s/.*y:(([\d]+.[\d]+)|[\d]+).*/$1/e; + } + if($tdtn =~ /.*d:(([\d]+.[\d]+)|[\d]+).*/) { + $d = $tdtn; + $d =~ s/.*d:(([\d]+.[\d]+)|[\d]+).*/$1/e; + } + if($tdtn =~ /.*h:(([\d]+.[\d]+)|[\d]+).*/) { + $h = $tdtn; $h =~ s/.*h:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($tdtn =~ /.*m:(([\d]+.[\d]+)|[\d]+).*/) { - $m = $tdtn; + } + if($tdtn =~ /.*m:(([\d]+.[\d]+)|[\d]+).*/) { + $m = $tdtn; $m =~ s/.*m:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($tdtn =~ /.*s:(([\d]+.[\d]+)|[\d]+).*/) { - $s = $tdtn; + } + if($tdtn =~ /.*s:(([\d]+.[\d]+)|[\d]+).*/) { + $s = $tdtn; $s =~ s/.*s:(([\d]+.[\d]+)|[\d]+).*/$1/e ; - } + } - no warnings 'uninitialized'; - Log3($name, 4, "DbRep $name - timeDiffToNow - year: $y, day: $d, hour: $h, min: $m, sec: $s"); - use warnings; + no warnings 'uninitialized'; + Log3($name, 4, "DbRep $name - timeDiffToNow - year: $y, day: $d, hour: $h, min: $m, sec: $s"); + use warnings; $y = $y?($y*365*86400):0; $d = $d?($d*86400):0; $h = $h?($h*3600):0; @@ -10047,35 +10059,35 @@ sub DbRep_normRelTime { $tdtn = $y + $d + $h + $m + $s + 1; # one security second for correct create TimeArray $tdtn = DbRep_corrRelTime($name,$tdtn,1); - $fdopt = ($aval =~ /.*FullDay.*$/ && $tdtn >= 86400)?1:0; # ist FullDay Option gesetzt UND Zeitdiff >= 1 Tag ? + $fdopt = ($aval =~ /.*FullDay.*$/ && $tdtn >= 86400)?1:0; # ist FullDay Option gesetzt UND Zeitdiff >= 1 Tag ? } if($toth && $toth =~ /^\s*[ydhms]:(([\d]+.[\d]+)|[\d]+)\s*/) { $aval = $toth; - if($toth =~ /.*y:(([\d]+.[\d]+)|[\d]+).*/) { - $y = $toth; - $y =~ s/.*y:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($toth =~ /.*d:(([\d]+.[\d]+)|[\d]+).*/) { - $d = $toth; - $d =~ s/.*d:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($toth =~ /.*h:(([\d]+.[\d]+)|[\d]+).*/) { - $h = $toth; + if($toth =~ /.*y:(([\d]+.[\d]+)|[\d]+).*/) { + $y = $toth; + $y =~ s/.*y:(([\d]+.[\d]+)|[\d]+).*/$1/e; + } + if($toth =~ /.*d:(([\d]+.[\d]+)|[\d]+).*/) { + $d = $toth; + $d =~ s/.*d:(([\d]+.[\d]+)|[\d]+).*/$1/e; + } + if($toth =~ /.*h:(([\d]+.[\d]+)|[\d]+).*/) { + $h = $toth; $h =~ s/.*h:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($toth =~ /.*m:(([\d]+.[\d]+)|[\d]+).*/) { - $m = $toth; + } + if($toth =~ /.*m:(([\d]+.[\d]+)|[\d]+).*/) { + $m = $toth; $m =~ s/.*m:(([\d]+.[\d]+)|[\d]+).*/$1/e; - } - if($toth =~ /.*s:(([\d]+.[\d]+)|[\d]+).*/) { - $s = $toth; + } + if($toth =~ /.*s:(([\d]+.[\d]+)|[\d]+).*/) { + $s = $toth; $s =~ s/.*s:(([\d]+.[\d]+)|[\d]+).*/$1/e ; - } + } - no warnings 'uninitialized'; - Log3($name, 4, "DbRep $name - timeOlderThan - year: $y, day: $d, hour: $h, min: $m, sec: $s"); - use warnings; + no warnings 'uninitialized'; + Log3($name, 4, "DbRep $name - timeOlderThan - year: $y, day: $d, hour: $h, min: $m, sec: $s"); + use warnings; $y = $y?($y*365*86400):0; $d = $d?($d*86400):0; $h = $h?($h*3600):0; @@ -10084,7 +10096,7 @@ sub DbRep_normRelTime { $toth = $y + $d + $h + $m + $s + 1; # one security second for correct create TimeArray $toth = DbRep_corrRelTime($name,$toth,0); - $fdopt = ($aval =~ /.*FullDay.*$/ && $toth >= 86400)?1:0; # ist FullDay Option gesetzt UND Zeitdiff >= 1 Tag ? + $fdopt = ($aval =~ /.*FullDay.*$/ && $toth >= 86400)?1:0; # ist FullDay Option gesetzt UND Zeitdiff >= 1 Tag ? } Log3($name, 4, "DbRep $name - FullDay option: $fdopt"); @@ -10130,7 +10142,7 @@ sub DbRep_corrRelTime { my $mg = ((int($mon)+1)+(($k-1)*12)+(11-int($dmon)+1)); # Gesamtzahl der Monate des Bewertungszeitraumes my $cly = 0; # Anzahl Schaltjahre innerhalb Beginn und Ende Auswertungszeitraum my $fly = 0; # erstes Schaltjahr nach Start - my $lly = 0; # letzes Schaltjahr nach Start + my $lly = 0; # letzes Schaltjahr nach Start while ($fyear+$k >= $fyear) { my $ily = DbRep_IsLeapYear($name,$fyear+$k); $cly++ if($ily); @@ -10146,7 +10158,7 @@ sub DbRep_corrRelTime { $tim += ($cly-1)*86400 if($cly); # Log3($name, 4, "DbRep $name - leap year correction 2"); } - + # Sommer/Winterzeitkorrektur (undef,undef,undef,undef,undef,undef,undef,undef,$disdst) = localtime(time-$tim); $tim += ($disdst-$isdst)*3600 if($disdst != $isdst); @@ -10202,12 +10214,12 @@ sub DbRep_beforeproc { my $ebd = AttrVal($name, "executeBeforeProc", undef); if($ebd) { Log3 ($name, 3, "DbRep $name - execute command before $txt: '$ebd' "); - my $err = AnalyzeCommandChain(undef, $ebd); - if ($err) { + my $err = AnalyzeCommandChain(undef, $ebd); + if ($err) { Log3 ($name, 2, "DbRep $name - command message before $txt: \"$err\" "); my $erread = "Warning - message from command before $txt appeared"; - ReadingsSingleUpdateValue ($hash, "before".$txt."_message", $err, 1); - ReadingsSingleUpdateValue ($hash, "state", $erread, 1); + ReadingsSingleUpdateValue ($hash, "before".$txt."_message", $err, 1); + ReadingsSingleUpdateValue ($hash, "state", $erread, 1); } } @@ -10227,11 +10239,11 @@ sub DbRep_afterproc { my $ead = AttrVal($name, "executeAfterProc", undef); if($ead) { Log3 ($name, 4, "DbRep $name - execute command after $txt: '$ead' "); - my $err = AnalyzeCommandChain(undef, $ead); - if ($err) { + my $err = AnalyzeCommandChain(undef, $ead); + if ($err) { Log3 ($name, 2, "DbRep $name - command message after $txt: \"$err\" "); - ReadingsSingleUpdateValue ($hash, "after".$txt."_message", $err, 1); - $erread = "Warning - $txt finished, but command message after $txt appeared"; + ReadingsSingleUpdateValue ($hash, "after".$txt."_message", $err, 1); + $erread = "Warning - $txt finished, but command message after $txt appeared"; } } @@ -10246,14 +10258,14 @@ sub DbRep_formatpicker { my ($str) = @_; if ($str =~ /^(\d{4})-(\d{2})-(\d{2})_(\d{2}):(\d{2})$/) { # Anpassung für datetime-Picker Widget - $str =~ s/_/ /; - $str = $str.":00"; + $str =~ s/_/ /; + $str = $str.":00"; } if ($str =~ /^(\d{4})-(\d{2})-(\d{2})_(\d{2}):(\d{2}):(\d{2})$/) { # Anpassung für datetime-Picker Widget - $str =~ s/_/ /; + $str =~ s/_/ /; } -return $str; +return $str; } #################################################################################################### @@ -10274,12 +10286,12 @@ sub DbRep_userexit { $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')"; + my $cmd = $hash->{HELPER}{USEREXITFN}."('$name','$reading','$value')"; $cmd = "{".$cmd."}"; - my $r = AnalyzeCommandChain(undef, $cmd); + my $r = AnalyzeCommandChain(undef, $cmd); } return; @@ -10342,7 +10354,7 @@ return undef; #################################################################################################### sub DbRep_NewDumpFilename { my ($sql_text,$dump_path,$dbname,$time_stamp,$character_set) = @_; - my $part = ""; + my $part = ""; my $sql_file = $dump_path.$dbname."_".$time_stamp.$part.".sql"; my $backupfile = $dbname."_".$time_stamp.$part.".sql"; @@ -10350,13 +10362,13 @@ sub DbRep_NewDumpFilename { $sql_text .= "SET FOREIGN_KEY_CHECKS=0;\n"; my ($filesize,$err) = DbRep_WriteToDumpFile($sql_text,$sql_file); - if($err) { - return (undef,undef,undef,undef,$err); - } + 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); } @@ -10366,13 +10378,13 @@ return ($sql_text,$first_insert,$sql_file,$backupfile,undef); sub DbRep_WriteToDumpFile { my ($inh,$sql_file) = @_; my $filesize; - my $err = 0; + 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); - } + $err = "Can't open file '$sql_file' for write access"; + return (undef,$err); + } print DATEI $inh; close(DATEI); @@ -10392,9 +10404,9 @@ return ($filesize,undef); #################################################################################################### sub DbRep_byteOutput { my $bytes = shift; - - return if(!defined($bytes)); - return $bytes if(!looks_like_number($bytes)); + + 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));}; @@ -10561,15 +10573,15 @@ sub DbRep_mysqlOptimizeTables { 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: ".$@); - $sth->finish; - $dbh->disconnect; + $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"); @@ -10577,38 +10589,38 @@ sub DbRep_mysqlOptimizeTables { foreach $tablename (@tablenames) { #optimize table if engine supports optimization - $engine = ''; + $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."); + 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) { + if ($ret) { Log3($name, 3, "DbRep $name - Table ".($opttbl+1)." `$tablename` optimized successfully."); - $opttbl++; + $opttbl++; } else { - Log3($name, 2, "DbRep $name - Error while optimizing table $tablename. Continue with next table or backup."); + 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: ".$@); - $sth->finish; - $dbh->disconnect; + $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); @@ -10754,14 +10766,14 @@ sub DbRep_sendftp { if(!$ftpServer) { $ftperr = "FTP-Error: FTP-Server isn't set."; - Log3($name, 2, "DbRep $name - $ftperr"); + 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); + Log3($name, 2, "DbRep $name - $ftperr"); + return ($ftperr,undef); } my $mod_ftpssl = 0; @@ -10770,7 +10782,7 @@ sub DbRep_sendftp { if ($ftpuseSSL) { # FTP mit SSL soll genutzt werden - $mod = "Net::FTPSSL => e.g. with 'sudo cpan -i Net::FTPSSL' "; + $mod = "Net::FTPSSL => e.g. with 'sudo cpan -i Net::FTPSSL' "; eval { require Net::FTPSSL; }; if(!$@){ $mod_ftpssl = 1; @@ -10788,13 +10800,13 @@ sub DbRep_sendftp { if ($ftpuseSSL && $mod_ftpssl) { # use ftp-ssl - my $enc = "E"; + 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 - $@"; + 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 - $@"; + or $ftperr = "FTP-Error: Can't connect - $@"; } else { $ftperr = "FTP-Error: required module couldn't be loaded. You have to install it first: $mod."; } @@ -10825,10 +10837,10 @@ sub DbRep_sendftp { $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"); + Log3($name, 2, "DbRep $name - $ftperr"); } else { $ftpmsg = "FTP: ".$file." transferred successfully to ".$ftpServer." into dir ".$ftpDir; - Log3($name, 3, "DbRep $name - $ftpmsg"); + Log3($name, 3, "DbRep $name - $ftpmsg"); } # Versionsverwaltung FTP-Verzeichnis @@ -10889,9 +10901,9 @@ sub DbRep_calcount { foreach my $key (sort(keys%{$ch})) { Log3 ($name, 4, "$key => ". $ch->{$key}); - if($ch->{$key} eq "1") { - $ncp{"$key"} = " ||"; - } + if($ch->{$key} eq "1") { + $ncp{"$key"} = " ||"; + } } return \%ncp; } @@ -11064,16 +11076,16 @@ sub DbRep_OutputWriteToDB { 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 ($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 - $@"); @@ -11089,8 +11101,8 @@ sub DbRep_OutputWriteToDB { # SQL-Startzeit my $wst = [gettimeofday]; - my $ihs = 0; - my $uhs = 0; + my $ihs = 0; + my $uhs = 0; foreach my $row (@row_array) { my @a = split("\\|",$row); $timestamp = $a[0]; @@ -11108,12 +11120,12 @@ sub DbRep_OutputWriteToDB { $uhs += $rv_uh if($rv_uh); Log3 ($hash->{NAME}, 4, "DbRep $name - UPDATE history: $row, RESULT: $rv_uh"); - + if ($rv_uh == 0) { - my $rv_ih = $sth_ih->execute($timestamp,$device,$type,$event,$reading,$value,$unit); + my $rv_ih = $sth_ih->execute($timestamp,$device,$type,$event,$reading,$value,$unit); $ihs += $rv_ih if($rv_ih); Log3 $hash->{NAME}, 4, "DbRep $name - INSERT history: $row, RESULT: $rv_ih"; - } + } } # update oder insert current if (lc($DbLogType) =~ m(current) ) { @@ -11137,7 +11149,7 @@ sub DbRep_OutputWriteToDB { $dbh->disconnect; - Log3 ($hash->{NAME}, 3, "DbRep $name - number of lines updated in \"$dblogname\": $uhs"); + 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"); $irowdone = $ihs + $uhs; @@ -11175,7 +11187,7 @@ sub DbRep_deleteOtherFromDB { # Inhalt $rh{$key} -> $runtime_string."|".$max_value."|".$row_max_time."|".$runtime_string_first."|".$runtime_string_next my @k = split("\\|",$rh{$key}); $value = $k[1] // undef; - $row_extreme_time = $k[2]; + $row_extreme_time = $k[2]; $runtime_string_first = $k[3]; $runtime_string_next = $k[4]; @@ -11201,13 +11213,13 @@ sub DbRep_deleteOtherFromDB { # SQL-Startzeit my $wst = [gettimeofday]; - my $dlines = 0; + my $dlines = 0; foreach my $row (@row_array) { my @a = split("\\|",$row); $device = $a[0]; $reading = $a[1]; $value = $a[2]; - $row_extreme_time = $a[3]; + $row_extreme_time = $a[3]; $runtime_string_first = $a[4]; $runtime_string_next = $a[5]; @@ -11236,7 +11248,7 @@ sub DbRep_deleteOtherFromDB { $dbh->disconnect; - Log3 $hash->{NAME}, 3, "DbRep $name - number of lines deleted in \"$dblogname\": $dlines"; + Log3 $hash->{NAME}, 3, "DbRep $name - number of lines deleted in \"$dblogname\": $dlines"; $irowdone = $dlines; @@ -11290,24 +11302,24 @@ sub DbRep_WriteToDB { Log3 ($name, 2, "DbRep $name - $@"); return ($wrt,$irowdone,$err); } - # update history mit/ohne primary key + # update history mit/ohne primary key if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') { - $sth_uh = $dbh->prepare("REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)"); - } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') { - $sth_uh = $dbh->prepare("INSERT OR REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)"); - } elsif ($usepkh && $dbloghash->{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=?)"); - } + $sth_uh = $dbh->prepare("REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)"); + } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') { + $sth_uh = $dbh->prepare("INSERT OR REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)"); + } elsif ($usepkh && $dbloghash->{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 && $dbloghash->{MODEL} eq 'MYSQL') { - eval { $sth_ic = $dbh->prepare("INSERT IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); }; + eval { $sth_ic = $dbh->prepare("INSERT IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); }; } elsif ($usepkc && $dbloghash->{MODEL} eq 'SQLITE') { eval { $sth_ic = $dbh->prepare("INSERT OR IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); }; } elsif ($usepkc && $dbloghash->{MODEL} eq 'POSTGRESQL') { @@ -11323,13 +11335,13 @@ sub DbRep_WriteToDB { } # update current mit/ohne primary key if ($usepkc && $dbloghash->{MODEL} eq 'MYSQL') { - $sth_uc = $dbh->prepare("REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); + $sth_uc = $dbh->prepare("REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); } elsif ($usepkc && $dbloghash->{MODEL} eq 'SQLITE') { - $sth_uc = $dbh->prepare("INSERT OR REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); + $sth_uc = $dbh->prepare("INSERT OR REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"); } elsif ($usepkc && $dbloghash->{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"); + $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=?)"); } @@ -11358,12 +11370,12 @@ sub DbRep_WriteToDB { if($histupd) { $rv_uh = $sth_uh->execute($type,$event,$value,$unit,$timestamp,$device,$reading); } - if ($rv_uh == 0) { - $ihs += $sth_ih->execute($timestamp,$device,$type,$event,$reading,$value,$unit); # V8.30.7 - # $ihs++; # V8.30.7 - } else { - $uhs += $rv_uh; # V8.30.7 - } + if ($rv_uh == 0) { + $ihs += $sth_ih->execute($timestamp,$device,$type,$event,$reading,$value,$unit); # V8.30.7 + # $ihs++; # V8.30.7 + } else { + $uhs += $rv_uh; # V8.30.7 + } } # update oder insert current if (lc($DbLogType) =~ m(current) ) { @@ -11380,8 +11392,8 @@ sub DbRep_WriteToDB { $dbh->rollback; return ($wrt,0,$err); } else { - $totrows++; # V8.30.7 - } + $totrows++; # V8.30.7 + } } eval {$dbh->commit() if(!$dbh->{AutoCommit});}; @@ -11459,9 +11471,9 @@ sub DbRep_sortVersion { my ($sseq,@versions) = @_; my @sorted = map {$_->[0]} - sort {$a->[1] cmp $b->[1]} - map {[$_, pack "C*", split /\./]} @versions; - + sort {$a->[1] cmp $b->[1]} + map {[$_, pack "C*", split /\./]} @versions; + @sorted = map {join ".", unpack "C*", $_} sort map {pack "C*", split /\./} @versions; @@ -11487,22 +11499,22 @@ sub DbRep_setVersionInfo { $hash->{HELPER}{VERSION} = $v; if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) { - # META-Daten sind vorhanden - $modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}} - if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 93_DbRep.pm 22678 2020-08-27 17:05:24Z DS_Starter $ im Kopf komplett! vorhanden ) - $modules{$type}{META}{x_version} =~ s/1.1.1/$v/g; - } else { - $modules{$type}{META}{x_version} = $v; - } - return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 93_DbRep.pm 22678 2020-08-27 17:05:24Z DS_Starter $ im Kopf komplett! vorhanden ) - if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) { - # es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen - # mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden - use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); + # META-Daten sind vorhanden + $modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}} + if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 93_DbRep.pm 22678 2020-08-27 17:05:24Z DS_Starter $ im Kopf komplett! vorhanden ) + $modules{$type}{META}{x_version} =~ s/1.1.1/$v/g; + } else { + $modules{$type}{META}{x_version} = $v; + } + return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 93_DbRep.pm 22678 2020-08-27 17:05:24Z DS_Starter $ im Kopf komplett! vorhanden ) + if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) { + # es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen + # mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden + use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); } } else { - # herkömmliche Modulstruktur - $hash->{VERSION} = $v; + # herkömmliche Modulstruktur + $hash->{VERSION} = $v; } return; @@ -11512,7 +11524,7 @@ return; # blockierende DB-Abfrage # liefert Ergebnis sofort zurück, setzt keine Readings #################################################################################################### -sub DbRep_dbValue { +sub DbRep_sqlCmdBlocking { my $name = shift; my $cmd = shift; my $hash = $defs{$name}; @@ -11524,14 +11536,21 @@ sub DbRep_dbValue { my $utf8 = $hash->{UTF8} // 0; my $srs = AttrVal($name, "sqlResultFieldSep", "|" ); - my $to = AttrVal($name, "timeout", 86400); + my $to = AttrVal($name, "timeout", 10 ); my ($err,$ret,$dbh); readingsDelete ($hash, "errortext"); ReadingsSingleUpdateValue ($hash, "state", "running", 1); - eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoCommit => 1, AutoInactiveDestroy => 1, mysql_enable_utf8 => $utf8 });}; + eval { $dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, + RaiseError => 1, + AutoCommit => 1, + AutoInactiveDestroy => 1, + mysql_enable_utf8 => $utf8 + } + ); + }; if ($@) { $err = $@; @@ -11544,7 +11563,7 @@ sub DbRep_dbValue { my $sql = ($cmd =~ m/\;$/xs) ? $cmd : $cmd.";"; Log3 ($name, 4, "DbRep $name - -------- New selection --------- "); - Log3 ($name, 4, "DbRep $name - Command: dbValue"); + Log3 ($name, 4, "DbRep $name - Command: sqlCmdBlocking"); Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); my $set; @@ -11628,7 +11647,7 @@ sub DbRep_dbValue { ReadingsSingleUpdateValue ($hash, "state", "error", 1); return $err; } - $ret = $nrows; + $ret = $nrows; } $sth->finish; @@ -11636,7 +11655,7 @@ sub DbRep_dbValue { my $rt = tv_interval($st); # SQL-Laufzeit ermitteln - my $com = (split(" ",$sql, 2))[0]; + my $com = (split " ", $sql, 2)[0]; Log3 ($name, 4, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com"); readingsBeginUpdate ($hash); @@ -11657,8 +11676,7 @@ return $ret; sub CommandDbReadingsVal { my ($cl, $param) = @_; - my @a = split("[ \t][ \t]*", $param); - my ($name, $devread, $ts, $default) = @a; + my ($name, $devread, $ts, $default) = split m{\s+}x, $param; $ts =~ s/_/ /; my $ret = DbReadingsVal($name, $devread, $ts, $default); @@ -11667,24 +11685,31 @@ return $ret; } sub DbReadingsVal($$$$) { - my ($name, $devread, $ts, $default) = @_; - my $hash = $defs{$name}; - my $dbmodel = $defs{$hash->{HELPER}{DBLOGDEVICE}}{MODEL}; + my $name = shift // return qq{A DbRep-device must be specified}; + my $devread = shift // return qq{"device:reading" must be specified}; + my $ts = shift // return qq{The Command needs a timestamp defined in format "YYYY-MM-DD_hh:mm:ss"}; + my $default = shift // return qq{The Command needs a default value defined}; + my ($err,$ret,$sql); - unless(defined($defs{$name})) { - return ("DbRep-device \"$name\" doesn't exist."); + if(!defined($defs{$name})) { + return qq{DbRep-device "$name" doesn't exist.}; } - unless($defs{$name}{TYPE} eq "DbRep") { - return ("\"$name\" is not a DbRep-device but of type \"".$defs{$name}{TYPE}."\""); + if(!$defs{$name}{TYPE} eq "DbRep") { + return qq{"$name" is not a DbRep-device but of type "}.$defs{$name}{TYPE}.qq{"}; } + + my $hash = $defs{$name}; + my $dbmodel = $defs{$hash->{HELPER}{DBLOGDEVICE}}{MODEL}; + $ts =~ s/_/ /; - unless($ts =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/) { - return ("timestamp has not the valid format. Use \"YYYY-MM-DD hh:mm:ss\" as timestamp."); + if($ts !~ /^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})$/x) { + return qq{timestamp has not the valid format. Use "YYYY-MM-DD_hh:mm:ss" as timestamp.}; } + my ($dev,$reading) = split(":",$devread); - unless($dev && $reading) { - return ("device:reading must be specified !"); + if(!$dev || !$reading) { + return qq{"device:reading" must be specified}; } if($dbmodel eq "MYSQL") { @@ -11717,13 +11742,14 @@ sub DbReadingsVal($$$$) { where device='$dev' and reading='$reading' and timestamp < '$ts' ) x order by diff limit 1;"; + } else { - return ("DbReadingsVal is not implemented for $dbmodel"); + return qq{DbReadingsVal is not implemented for $dbmodel}; } - $hash->{LASTCMD} = "dbValue $sql"; - $ret = DbRep_dbValue($name,$sql); - $ret = $ret?$ret:$default; + $hash->{LASTCMD} = "sqlCmdBlocking $sql"; + $ret = DbRep_sqlCmdBlocking($name,$sql); + $ret = $ret ? $ret : $default; return $ret; } @@ -11761,12 +11787,12 @@ sub DbRep_modAssociatedWith { $e =~ s/%/\.*/g if($e !~ /^%$/); # SQL Wildcard % auflösen @edvspcs = devspec2array($e); @edvspcs = map { my $e = $_; $e =~ s/\.\*/%/xg; } @edvspcs; - if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) aussortieren, die nicht aufgelöst werden konnten - $edevswc .= "|" if($edevswc); - $edevswc .= join(" ",@edvspcs); - } else { - $edevs .= "|" if($edevs); - $edevs .= join("|",@edvspcs); + if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) aussortieren, die nicht aufgelöst werden konnten + $edevswc .= "|" if($edevswc); + $edevswc .= join(" ",@edvspcs); + } else { + $edevs .= "|" if($edevs); + $edevs .= join("|",@edvspcs); } } } @@ -11873,16 +11899,16 @@ return;
  • rename of device/readings in datasets
  • change of reading values in the database (changeValue)
  • 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 (non-blocking)
  • -
  • Execution of arbitrary user specific SQL-commands (blocking) for usage in user own code (dbValue)
  • -
  • creation of backups of the database in running state non-blocking (MySQL, SQLite)
  • -
  • transfer dumpfiles to a FTP server after backup incl. version control
  • -
  • restore of SQLite- and MySQL-Dumps 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 with different timestamp but same values (clearing up consecutive doublets)
  • +
  • Execution of arbitrary user specific SQL-commands (non-blocking)
  • +
  • Execution of arbitrary user specific SQL-commands (blocking) for usage in user own code (sqlCmdBlocking)
  • +
  • creation of backups of the database in running state non-blocking (MySQL, SQLite)
  • +
  • transfer dumpfiles to a FTP server after backup incl. version control
  • +
  • restore of SQLite- and MySQL-Dumps 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 with different timestamp but same values (clearing up consecutive doublets)
  • Repair of a corrupted SQLite database ("database disk image is malformed")
  • transmission of datasets from source database into another (Standby) database (syncStandby)
  • reduce the amount of datasets in database (reduceLog)
  • @@ -11901,8 +11927,9 @@ return;

    Once a DbRep-Device is defined, the Perl function DbReadingsVal provided as well as and the FHEM command dbReadingsVal. - With this function you can, similar to the well known ReadingsVal, get a reading value from database. - The function execution is carried out blocking.

    + With this function you can, similar to the well known ReadingsVal, get a reading value from database.
    + The function is executed blocking with a standard timeout of 10 seconds to prevent a permanent blocking of FHEM. + The timeout is adjustable with the attribute timeout.

      The command syntax for the Perl function is:

      @@ -11912,7 +11939,7 @@ return;

      - Examples:
      + Example:
         $ret = DbReadingsVal("Rep.LogDB1","MyWetter:temperature","2018-01-13_08:00:00","");
         attr <name> userReadings oldtemp {DbReadingsVal("Rep.LogDB1","MyWetter:temperature","2018-04-13_08:00:00","")} 
      @@ -11934,14 +11961,16 @@ return;
         

      Example:
      - dbReadingsVal Rep.LogDB1 MyWetter:temperature 2018-01-13_08:00:00 0 + + dbReadingsVal Rep.LogDB1 MyWetter:temperature 2018-01-13_08:00:00 0 +

      - +
      <name> : name of the DbRep-Device to request
      <device:reading> : device:reading whose value is to deliver
      <timestamp> : timestamp of reading whose value is to deliver (*) in the form "YYYY-MM-DD_hh:mm:ss"
      <timestamp> : timestamp of reading whose value is to deliver (*) in format "YYYY-MM-DD_hh:mm:ss"
      <default> : default value if no reading value can be retrieved
    @@ -12015,7 +12044,7 @@ return;
      • adminCredentials <User> <Passwort> - - Save a user / password for the privileged respectively administrative database access. + - Save a user / password for the privileged respectively administrative database access. The user is required for database operations which has to be executed by a privileged user. Please see also attribute 'useAdminCredentials'.
        (only valid if database type is MYSQL and DbRep-type "Client") @@ -12024,10 +12053,10 @@ return;
      • averageValue [display | writeToDB | writeToDBSingle | writeToDBInTime] - calculates an average value of the database field "VALUE" in the time limits - of the possible time.*-attributes.

        + of the possible time.*-attributes.

        The reading to be evaluated must be specified in the attribute reading - must be specified. + must be specified. With the attribute averageCalcForm the calculation variant is used for Averaging defined.

        @@ -12035,18 +12064,18 @@ return; the options writeToDB, writeToDBSingle or writeToDBInTime the calculation results are written with a new reading name into the database.

        -
          +
            - + -
            writeToDB : writes one value each with the time stamps XX:XX:01 and XX:XX:59 within the respective evaluation period
            writeToDB : writes one value each with the time stamps XX:XX:01 and XX:XX:59 within the respective evaluation period
            writeToDBSingle : writes only one value with the time stamp XX:XX:59 at the end of an evaluation period
            writeToDBInTime : writes a value at the beginning and end of the time limits of an evaluation period
            -
          -
          + +
        +
        The new reading name is formed from a prefix and the original reading name, - where the original reading name can be replaced by the attribute "readingNameMap". + where the original reading name can be replaced by the attribute "readingNameMap". The prefix consists of the educational function and the aggregation.
        The timestamp of the new readings in the database is determined by the set aggregation period if no clear time of the result can be determined. @@ -12061,7 +12090,7 @@ return; Summarized the relevant attributes to control this function are:

        -
          +
            @@ -12072,9 +12101,9 @@ return;
            averageCalcForm : choose the calculation variant for average determination
            time.* : a number of attributes to limit selection by time
            valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
            -
          -
          -
          +
        +
        +

      • @@ -12098,17 +12127,17 @@ return; +
      • a string with usage of SQL-wildcard, e.g. "%OL%"
      • - - + -
        <old string> :
      • a simple string with/without spaces, e.g. "OL 12"
      • -
      • a string with usage of SQL-wildcard, e.g. "%OL%"
      • <new string> :
      • a simple string with/without spaces, e.g. "12 kWh"
      • +
        <new string> :
      • a simple string with/without spaces, e.g. "12 kWh"
      • Perl code embedded in "{}" with quotes, e.g. "{($VALUE,$UNIT) = split(" ",$VALUE)}". The perl expression the variables $VALUE and $UNIT are committed to. - The variables are changable within the perl code. The returned value - of VALUE and UNIT are saved into the database field VALUE respectively - UNIT of the dataset.
      • -
        + The variables are changable within the perl code. The returned value + of VALUE and UNIT are saved into the database field VALUE respectively + UNIT of the dataset. + +
        Examples:
        set <name> changeValue "OL","12 OL"
        @@ -12126,38 +12155,38 @@ return; Summarized the relevant attributes to control function changeValue are:

        -
          +
            - +
            device : include or exclude <device> from selection
            reading : include or exclude <reading> from selection
            time.* : a number of attributes to limit selection by time
            executeBeforeProc : execute a FHEM command (or Perl-routine) before start of changeValue
            executeBeforeProc : execute a FHEM command (or Perl-routine) before start of changeValue
            executeAfterProc : execute a FHEM command (or Perl-routine) after changeValue is finished
            valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
            -
          -
          -
          - - Note:
          +
        +
        +
        + + 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.


    • countEntries [history|current] - provides the number of table entries (default: history) between time period set - by time.* -attributes if set. + by time.* -attributes if set. If time.* attributes not set, all entries of the table will be count. - The attributes "device" and "reading" can be used to - limit the evaluation.
      + The attributes "device" and "reading" can be used to + limit the evaluation.
      By default the summary of all counted datasets, labeled by "ALLREADINGS", will be created. If the attribute "countEntriesDetail" is set, the number of every reading is reported additionally.

      The relevant attributes for this function are:

      -
        +
          @@ -12167,76 +12196,76 @@ return;
          aggregation : aggregatiion/grouping of time intervals
          time.* : a number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        -
        +
      +

    • delDoublets [adviceDelete | delete] - show respectively delete duplicate/multiple datasets. - Therefore the fields TIMESTAMP, DEVICE, READING and VALUE of records are compared.
      - 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". -

      - -
        + Therefore the fields TIMESTAMP, DEVICE, READING and VALUE of records are compared.
        + 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". +

        + +
          adviceDelete : simulates the datasets to delete in database (nothing will be deleted !)
          delete : deletes the doublets
          -
        -
        +
      +
      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 "delDoublets adviceDelete" is initially limited + The amount of datasets to show by commands "delDoublets adviceDelete" is initially limited (default: 1000) and can be adjusted by attribute "limit". - The adjustment of "limit" has no impact to the "delDoublets delete" function, but affects + The adjustment of "limit" has no impact to the "delDoublets delete" function, but affects ONLY the display of the data.
      - Before and after this "delDoublets" it is possible to execute a FHEM command or Perl script + Before and after this "delDoublets" it is possible to execute a FHEM command or Perl script (please see attributes "executeBeforeProc", "executeAfterProc"). -

      - -
        - Example:

        +

        + +
          + Example:

          Output of records to delete included their amount by "delDoublets adviceDelete":

          - - 2018-11-07_14-11-38__Dum.Energy__T 260.9_|_2
          - 2018-11-07_14-12-37__Dum.Energy__T 260.9_|_2
          - 2018-11-07_14-15-38__Dum.Energy__T 264.0_|_2
          - 2018-11-07_14-16-37__Dum.Energy__T 264.0_|_2
          -
          - In the created readings after "_|_" the amount of the appropriate records to delete - is shown. The records are deleted by command "delDoublets delete". -
        + + 2018-11-07_14-11-38__Dum.Energy__T 260.9_|_2
        + 2018-11-07_14-12-37__Dum.Energy__T 260.9_|_2
        + 2018-11-07_14-15-38__Dum.Energy__T 264.0_|_2
        + 2018-11-07_14-16-37__Dum.Energy__T 264.0_|_2
        +
        + In the created readings after "_|_" the amount of the appropriate records to delete + is shown. The records are deleted by command "delDoublets delete". +

      Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

      -
        +
          - - - + + + - + - + -
          allowDeletion : needs to be set to execute the delete option
          aggregation : choose the aggregation period
          limit : limits ONLY the count of datasets to display
          allowDeletion : needs to be set to execute the delete option
          aggregation : choose the aggregation period
          limit : limits ONLY the count of datasets to display
          device : include or exclude <device> from selection
          reading : include or exclude <reading> from selection
          executeBeforeProc : execute a FHEM command (or Perl-routine) before start of the function
          executeBeforeProc : execute a FHEM command (or Perl-routine) before start of the function
          executeAfterProc : execute a FHEM command (or Perl-routine) after the function is finished
          time.* : a number of attributes to limit selection by time
          time.* : a number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        -
        -
        + +
      +
      +
    • delEntries [<no>[:<nn>]] - deletes all database entries or only the database entries specified by - attributes device and/or reading.

      - - The time limits are considered according to the available time.*-attributes:

      + attributes device and/or reading.

      + + The time limits are considered according to the available time.*-attributes:

        "timestamp_begin" is set -> deletes db entries from this timestamp until current date/time
        @@ -12245,69 +12274,69 @@ return; "timeOlderThan" is set -> delete entries older than current time minus "timeOlderThan"
        "timeDiffToNow" is set -> delete db entries from current time minus "timeDiffToNow" until now
      - +
      Due to security reasons the attribute allowDeletion needs to be set to unlock the - delete-function.
      - Time limits (days) can be specified as an option. In this case, any time.*-attributes set are - overmodulated. - Records older than <no> days and (optionally) newer than - <nn> days are considered. -

      + delete-function.
      + Time limits (days) can be specified as an option. In this case, any time.*-attributes set are + overmodulated. + Records older than <no> days and (optionally) newer than + <nn> days are considered. +

      The relevant attributes to control function changeValue delEntries are:

      -
        +
          - +
          allowDeletion : unlock the delete function
          device : include or exclude <device> from selection
          reading : include or exclude <reading> from selection
          time.* : a number of attributes to limit selection by time
          executeBeforeProc : execute a FHEM command (or Perl-routine) before start of delEntries
          executeBeforeProc : execute a FHEM command (or Perl-routine) before start of delEntries
          executeAfterProc : execute a FHEM command (or Perl-routine) after delEntries is finished
          -
        -
        -
        +
      +
      +
    • -
      - +
      +
    • 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 + 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.
      - Before and after this "delSeqDoublets" it is possible to execute a FHEM command or Perl-script + 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.
      + Before and after this "delSeqDoublets" it is possible to execute a FHEM command or Perl-script (please see attributes "executeBeforeProc" and "executeAfterProc").

      - -
        - Example - the remaining datasets after executing delete-option are are marked as bold:

        -
          + +
            + 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
              @@ -12337,31 +12366,31 @@ return; 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
            -
          +

        Summarized the relevant attributes to control this function are:

        -
          +
            - - - + + + - + - - + + -
            allowDeletion : needs to be set to execute the delete option
            aggregation : choose the aggregation period
            limit : limits ONLY the count of datasets to display
            allowDeletion : needs to be set to execute the delete option
            aggregation : choose the aggregation period
            limit : limits ONLY the count of datasets to display
            device : include or exclude <device> from selection
            reading : include or exclude <reading> from selection
            executeBeforeProc : execute a FHEM command (or Perl-routine) before start of the function
            executeBeforeProc : execute a FHEM command (or Perl-routine) before start of the function
            executeAfterProc : execute a FHEM command (or Perl-routine) after the function is finished
            seqDoubletsVariance : Up to this value consecutive numerical datasets are handled as identical and should be deleted
            time.* : a number of attributes to limit selection by time
            seqDoubletsVariance : Up to this value consecutive numerical datasets are handled as identical and should be deleted
            time.* : a number of attributes to limit selection by time
            valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
            -
          + +
        -
        -
        - +
        +
        +
      • deviceRename <old_name>,<new_name> - 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 @@ -12374,8 +12403,8 @@ return; # 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:
        + + 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.


      • @@ -12385,19 +12414,19 @@ return; - calculates the difference of database column "VALUE" in the given time period. (see also the several time*-attributes).
        The reading to evaluate must be defined in attribute reading.
        This function is mostly reasonable if values are increasing permanently and don't write value differences into the database. - The difference will always be generated between all consecutive datasets (VALUE-Field) and add them together, in doing add carry value of the - previous aggregation period to the next aggregation period in case the previous period contains a value.
        - A 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. -

        - + The difference will always be generated between all consecutive datasets (VALUE-Field) and add them together, in doing add carry value of the + previous aggregation period to the next aggregation period in case the previous period contains a value.
        + A 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 + 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.

          @@ -12407,7 +12436,7 @@ return; 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, - in which the original reading name can be partly replaced by the value of attribute readingNameMap. + in which the original reading name can be partly replaced by the value of attribute readingNameMap. 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. @@ -12417,60 +12446,60 @@ return; Example of building a new reading name from the original reading "totalpac":
          diff_day_totalpac
          # <creation function>_<aggregation>_<original reading>
          -
        +

      Summarized the relevant attributes to control this function are:

      -
        +
          - - + + - + - - + + -
          aggregation : choose the aggregation period
          diffAccept : the accepted maximum difference between sequential records
          aggregation : choose the aggregation period
          diffAccept : the accepted maximum difference between sequential records
          device : include or exclude <device> from selection
          executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
          executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
          executeAfterProc : execution of FHEM command (or Perl-routine) after operation
          reading : include or exclude <reading> from selection
          readingNameMap : rename the resulted reading name
          time.* : a number of attributes to limit selection by time
          readingNameMap : rename the resulted reading name
          time.* : a number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        -
        -
        + +
      +
      +

    • dumpMySQL [clientSide | serverSide] - - creates a dump of the connected MySQL database.
      - Depending from selected option the dump will be created on Client- or on Server-Side.
      - The variants differs each other concerning the executing system, the creating location, the usage of + - creates a dump of the connected MySQL database.
      + Depending from selected option the dump will be created on Client- or on Server-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.
      + The option "clientSide" e.g. needs more powerful FHEM-Server hardware, but saves all available + tables inclusive possibly created views.
      With attribute "dumpCompress" a compression of dump file after creation can be switched on. -

      - -
        - Option clientSide
        - The dump will be created by client (FHEM-Server) and will be saved in FHEM log-directory by - default. +

        + +
          + 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"). + 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"). After the dump a FHEM-command can be executed as well (see attribute "executeAfterProc").

          - - Note:
          - To avoid FHEM from blocking, you have to operate DbLog in asynchronous mode if the table + + Note:
          + To avoid FHEM from blocking, you have to operate DbLog in asynchronous mode if the table optimization want to be used !


          - - By the attributes "dumpMemlimit" and "dumpSpeed" the run-time behavior of the function can be - controlled to optimize the performance and demand of ressources.

          + + 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:

          -
            + The attributes relevant for function "dumpMySQL clientSide" are:

            +
              @@ -12478,184 +12507,184 @@ return; - - + + - +
              dumpComment : User comment in head of dump file
              dumpDirLocal : the local destination directory for dump file creation
              dumpMemlimit : limits memory usage
              dumpSpeed : limits CPU utilization
              dumpFilesKeep : number of dump files to keep
              executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
              dumpFilesKeep : number of dump files to keep
              executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
              executeAfterProc : execution of FHEM command (or Perl-routine) after dump
              optimizeTablesBeforeDump : table optimization before dump
              optimizeTablesBeforeDump : table optimization before dump
              -
            -
            +
          +
          - After a successfull finished dump the old dumpfiles are deleted and only the number of files + 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". If "dumpFilesKeep = 0" is set, all dumpfiles (also the current created file), are deleted. This setting can be helpful, if FTP transmission is used and the created dumps are only keep remain in the FTP destination directory.

          - The naming convention of dump files is: <dbname>_<date>_<time>.sql[.gzip]

          - - To rebuild the database from a dump file the command:

          - -
            - set <name> restoreMySQL <filename>

            -
          + The naming convention of dump files is: <dbname>_<date>_<time>.sql[.gzip]

          + + To rebuild the database from a dump file the command:

          + +
            + set <name> restoreMySQL <filename>

            +
          - can be used.

          - - The created dumpfile (uncompressed) can imported on the MySQL-Server by:

          - -
            - mysql -u <user> -p <dbname> < <filename>.sql

            -
          - - as well to restore the database from dump file.


          + can be used.

          - - 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 + The created dumpfile (uncompressed) can imported on the MySQL-Server by:

          + +
            + mysql -u <user> -p <dbname> < <filename>.sql

            +
          + + as well to restore the database from dump file.


          + + + 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 is used !


          - - After the dump a FHEM-command can be executed as well (see attribute "executeAfterProc").

          - The attributes relevant for function "dumpMySQL serverSide" are:

          -
            + After the dump a FHEM-command can be executed as well (see attribute "executeAfterProc").

            + + The attributes relevant for function "dumpMySQL serverSide" are:

            +
              - - + + - +
              dumpDirRemote : destination directory of dump file on remote server
              dumpCompress : compress of dump files after creation
              dumpDirLocal : the local mounted directory dumpDirRemote
              dumpFilesKeep : number of dump files to keep
              executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
              dumpFilesKeep : number of dump files to keep
              executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
              executeAfterProc : execution of FHEM command (or Perl-routine) after dump
              optimizeTablesBeforeDump : table optimization before dump
              optimizeTablesBeforeDump : table optimization before dump
              -
            -
            - +
          +
          + 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 (see Wiki).

          - - 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"). -

          + The used database user must have the FILE privilege (see Wiki).

          + + 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 <name> dumpDirRemote /volume1/ApplicationBackup/dumps_FHEM/
            - attr <name> dumpDirLocal /sds1/backup/dumps_FHEM/
            - attr <name> dumpFilesKeep 2

            - + attr <name> dumpDirLocal /sds1/backup/dumps_FHEM/
            + attr <name> 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.
            + '/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".

          +
        + + 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[.gzip]

        - - You can start a restore of table history from serverSide-Backup by command:

        -
          - set <name> <restoreMySQL> <filename>.csv[.gzip]

          -
        - + The naming convention of dump files is: <dbname>_<date>_<time>.csv[.gzip]

        + + You can start a restore of table history from serverSide-Backup by command:

        +
          + set <name> <restoreMySQL> <filename>.csv[.gzip]

          +
        +

        - 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. + 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. The module also carries the version control of dump files in FTP-destination by attribute "ftpDumpFilesKeep".
        - Further attributes are:

        - -
          + 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: "/")
            ftpDumpFilesKeep : leave the number of dump files in FTP-destination <ftpDir> (default: 3)
            ftpDir : directory on FTP-server in which the file will be send into (default: "/")
            ftpDumpFilesKeep : leave the number of dump files in FTP-destination <ftpDir> (default: 3)
            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).
            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 + 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 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"). + 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 + + 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 function "dumpMySQL serverSide" are:

      -
        + The attributes relevant for function "dumpMySQL serverSide" are:

        +
          - - + + - +
          dumpCompress : compress of dump files after creation
          dumpDirLocal : Target directory of the dumpfiles
          dumpFilesKeep : number of dump files to keep
          executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
          dumpFilesKeep : number of dump files to keep
          executeBeforeProc : execution of FHEM command (or Perl-routine) before dump
          executeAfterProc : execution of FHEM command (or Perl-routine) after dump
          optimizeTablesBeforeDump : table optimization before dump
          optimizeTablesBeforeDump : table optimization before dump
          -
        -
        +
      +
      - 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". If "dumpFilesKeep = 0" is set, all + 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". If "dumpFilesKeep = 0" is set, all dumpfiles (also the current created file), are deleted. This setting can be helpful, if FTP transmission is used and the created dumps are only keep remain in the FTP destination directory.

      - The naming convention of dump files is: <dbname>_<date>_<time>.sqlitebkp[.gzip]

      - + The naming convention of dump files is: <dbname>_<date>_<time>.sqlitebkp[.gzip]

      + The database can be restored by command "set <name> restoreSQLite <filename>"
      The created dump file can be transfered to a FTP-server. Please see explanations about FTP- transfer in topic "dumpMySQL".

      -

    • +
    • eraseReadings - deletes all created readings in the device, except reading "state" and readings, which are contained in exception list defined by attribute "readingPreventFromDel".

    • - +
    • exportToFile [</path/file>] [MAXLINES=<lines>] - exports DB-entries to a file in CSV-format of time period specified by time attributes.

      @@ -12676,30 +12705,30 @@ return; 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.

      - The attributes relevant for this function are:

      -
        + The attributes relevant for this function are:

        +
          - + - +
          aggregation : determination of selection time slices
          device : include or exclude <device> from selection
          reading : include or exclude <reading> from selection
          time.* : a number of attributes to limit selection by time
          executeBeforeProc : execution of FHEM command (or Perl-routine) before export
          executeBeforeProc : execution of FHEM command (or Perl-routine) before export
          executeAfterProc : execution of FHEM command (or Perl-routine) after export
          expimpfile : the name of exportfile
          expimpfile : the name of exportfile
          time.* : a number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        +

    • fetchrows [history|current] - provides all table entries (default: history) - of time period set by time attributes respectively selection conditions + of time period set by time attributes respectively selection conditions by attributes "device" and "reading". An aggregation set will not be considered.
      - The direction of data selection can be determined by attribute - "fetchRoute".

      + The direction of data selection can be determined by attribute + "fetchRoute".

      Every reading of result is composed of the dataset timestring , an index, the device name and the reading name. @@ -12732,7 +12761,7 @@ return; For a better overview the relevant attributes are listed here in a table:

      -
        +
          @@ -12744,24 +12773,24 @@ return;
          device : include or exclude <device> from selection
          time.* : A number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        -
        -
        +
      +
      +
      - Note:
      + Note:
      Although the module is designed non-blocking, a huge number of selection result (huge number of rows) - can overwhelm the browser session respectively FHEMWEB. - Due to the sample space can be limited by attribute "limit". + can overwhelm the browser session respectively FHEMWEB. + Due to the sample space can be limited by attribute "limit". Of course ths attribute can be increased if your system capabilities allow a higher workload.

      -

    • +
    • index <Option> - - Reports the existing indexes in the database or creates the index which is needed. + - Reports the existing indexes in the database or creates the index which is needed. If the index is already created, it will be renewed (dropped and new created)

      - The possible options are:

      + The possible options are:

      -
        +
          @@ -12770,19 +12799,19 @@ return;
          list_all : reports the existing indexes
          recreate_Report_Idx : create or renew (if existing) the index Report_Idx in table history (index for DbRep)
          drop_Report_Idx : delete the index Report_Idx in table history
          -
        -
        +
      +
      For a better overview the relevant attributes for this operation are listed here:

      -
        +
          useAdminCredentials : use privileged user for the operation
          -
        -
        -
        +
      +
      +
      Note:
      The used database user needs the ALTER, CREATE and INDEX privilege.
      @@ -12799,13 +12828,13 @@ return; example: 2016-08-01,23:00:09,TestValue,TestUnit
      # Spaces are NOT allowed in fieldvalues !

      - - Note:
      + + 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 ! + it's needed by function diffValue. Otherwise no difference can be calculated and diffValue will be print out "0" for the respective period !

      -
    • +
  • importFromFile [<file>] @@ -12817,7 +12846,7 @@ return;
      dataset format:
      - "TIMESTAMP","DEVICE","TYPE","EVENT","READING","VALUE","UNIT"

      + "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. @@ -12827,15 +12856,15 @@ return; "2016-09-25 08:53:56","STP_5000","SMAUTILS","etotal: 11859.573","etotal","11859.573",""

      - The attributes relevant for this function are:

      -
        + The attributes relevant for this function are:

        +
          - +
          executeBeforeProc : execution of FHEM command (or Perl-routine) before import
          executeAfterProc : execution of FHEM command (or Perl-routine) after import
          expimpfile : the name of exportfile
          expimpfile : the name of exportfile
          -
        +

    @@ -12851,15 +12880,15 @@ return; If no option or the option display is 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, - in which the original reading name can be replaced by the value of attribute readingNameMap. + in which the original reading name can be replaced by the value of attribute readingNameMap. 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".

    - - With option deleteOther all datasets except the dataset with the maximum value are deleted.

    + + With option deleteOther all datasets except the dataset with the maximum value are deleted.

      Example of building a new reading name from the original reading "totalpac":
      @@ -12870,19 +12899,19 @@ return; Summarized the relevant attributes to control this function are:

      -
        +
          - + - - + + -
          aggregation : choose the aggregation period
          aggregation : choose the aggregation period
          device : include or exclude <device> from selection
          executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
          executeAfterProc : execution of FHEM command (or Perl-routine) after operation
          reading : include or exclude <reading> from selection
          readingNameMap : rename the resulted readings
          time.* : a number of attributes to limit selection by time
          readingNameMap : rename the resulted readings
          time.* : a number of attributes to limit selection by time
          valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
          -
        + +

      @@ -12896,15 +12925,15 @@ return; If no option or the option display is 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, in which the original reading name can be replaced by the value of attribute readingNameMap. 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".

      - - With option deleteOther all datasets except the dataset with the maximum value are deleted.

      + + With option deleteOther all datasets except the dataset with the maximum value are deleted.

        Example of building a new reading name from the original reading "totalpac":
        @@ -12915,34 +12944,34 @@ return; Summarized the relevant attributes to control this function are:

        -
          +
            - + - - + + -
            aggregation : choose the aggregation period
            aggregation : choose the aggregation period
            device : include or exclude <device> from selection
            executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
            executeAfterProc : execution of FHEM command (or Perl-routine) after operation
            reading : include or exclude <reading> from selection
            readingNameMap : rename the resulted readings
            time.* : a number of attributes to limit selection by time
            readingNameMap : rename the resulted readings
            time.* : a number of attributes to limit selection by time
            valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
            -
          + +

        -
      • optimizeTables - optimize tables in the connected database (MySQL).
        - Before and after an optimization it is possible to execute a FHEM command. +
      • 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:
          +
            + 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 <[device:]oldreadingname>,<newreadingname>
          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 @@ -12961,18 +12990,18 @@ return; If the reading name to be renamed was not found in the database, a WARNING will appear in reading "reading_not_renamed".
          Appropriate entries will be written to Logfile if verbose >= 3 is set.

          - - Note:
          + + 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.


        • reduceLog [<no>[:<nn>]] [average[=day]] [EXCLUDE=device1:reading1,device2:reading2,...] [INCLUDE=device:reading]
          Reduces historical data sets.

          - - Method without option specification

          - - If no options are specified, the data will be stored within the time specified by the time.* attributes. + + Method without option specification

          + + If no options are specified, the data will be stored within the time specified by the time.* attributes. Time limits reduced to one entry (the first) per hour per Device & Reading. At least one of the time.* attributes must be set (see table below). In this case, the missing time limit is calculated by the module. @@ -12982,13 +13011,13 @@ return; or be excluded. Both restrictions reduce the selected data and reduce the resource requirements. The read "reduceLogState" contains the execution result of the last reduceLog command.

          - - Taking the above into account, the following attributes are relevant for this function:

          -
            + Taking the above into account, the following attributes are relevant for this function:

            + +
              - + @@ -12998,9 +13027,9 @@ return;
              executeBeforeProc : execution of FHEM command (or Perl-routine) before reducelog
              executeBeforeProc : execution of FHEM command (or Perl-routine) before reducelog
              executeAfterProc : execution of FHEM command (or Perl-routine) after reducelog
              device : include or exclude <device> for selection
              reading : include or exclude <reading> for selection
              timestamp_begin : records newer than this attribute will be reduced
              valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
              -
            +

          - + Examples:

            attr <name> timeOlderThan = d:200
            @@ -13029,37 +13058,37 @@ return; # Records older than 5 and newer than 10 days and containing DEVICE "Luftdaten_remote are adjusted. Numerical values of an hour are reduced to an average value

            -
          -
          +
        +
        - Method with option specification

        - - Records older than <no> days and (optionally) newer than - <nn> days are considered. + Method with option specification

        + + Records older than <no> days and (optionally) newer than + <nn> days are considered. Specifying average not only cleans up the database, but also all numerical values of an hour are reduced to a single mean value. With the option average=day all numerical values of a day are reduced to a single Average value reduced (implies 'average').

        The additions "EXCLUDE" and "INCLUDE" can be added to exclude device/reading combinations of reduceLog - or to include them. This specification is evaluated as regex and overwrites the setting of the attributes "device". - and "reading", which are not considered in this case.

        + or to include them. This specification is evaluated as regex and overwrites the setting of the attributes "device". + and "reading", which are not considered in this case.

        - Note:
        + Note:
        Although the function itself is designed non-blocking, the assigned DbLog device should operated in asynchronous mode to avoid blocking of FHEMWEB (table lock).
        It is also strongly recommended to use the standard INDEX 'Search_Idx' in the table 'history'. to put on !
        - The processing of this command may take an extremely long time (without INDEX).

        + The processing of this command may take an extremely long time (without INDEX).


      • - +
      • repairSQLite - repairs a corrupted SQLite database.
        A corruption is usally existent when the error message "database disk image is malformed" appears in reading "state" of the connected DbLog-device. If the command was started, the connected DbLog-device will firstly disconnected from the database for 10 hours (36000 seconds) automatically (breakup time). After the repair is finished, the DbLog-device will be connected to the (repaired) database immediately.
        - As an argument the command can be completed by a differing breakup time (in seconds).
        + As an argument the command can be completed by a differing breakup time (in seconds).
        The corrupted database is saved as <database>.corrupt in same directory.

          @@ -13069,72 +13098,72 @@ return; set <name> repairSQLite 600
          # the database is trying to repair, breakup time is 10 minutes

          - - Note:
          + + Note:
          It can't be guaranteed, that the repair attempt proceed successfully and no data loss will result. Depending from corruption severity data loss may occur or the repair will fail even though no error appears during the repair process. Please make sure a valid backup took place !


          -
        - +
      +
    • restoreMySQL <File> - restore a database from serverSide- or clientSide-Dump.
      The function provides a drop-down-list of files which can be used for restore.

      - - Usage of serverSide-Dumps
      - The content of history-table will be restored from a serverSide-Dump. + + Usage of serverSide-Dumps
      + The content of history-table will be restored from a serverSide-Dump. Therefore the remote directory "dumpDirRemote" of the MySQL-Server has to be mounted on the - Client and make it usable to the DbRep device by setting attribute dumpDirLocal - to the appropriate value.
      - All files with extension "csv[.gzip]" and if the filename is beginning with the name of the connected database - (see Internal DATABASE) are listed. -

      - - Usage of clientSide-Dumps
      + Client and make it usable to the DbRep device by setting attribute dumpDirLocal + to the appropriate value.
      + All files with extension "csv[.gzip]" and if the filename is beginning with the name of the connected database + (see Internal DATABASE) are listed. +

      + + Usage of clientSide-Dumps
      The used database user needs the FILE privilege (see Wiki).
      - All tables and views (if present) are restored. - The directory which contains the dump files has to be set by attribute dumpDirLocal - to make it usable by the DbRep device.
      - All files with extension "sql[.gzip]" and if the filename is beginning with the name of the connected database - (see Internal DATABASE) are listed.
      - The restore speed depends of the server variable "max_allowed_packet". You can change - this variable in file my.cnf to adapt the speed. Please consider the need of sufficient ressources - (especially RAM). -

      - + All tables and views (if present) are restored. + The directory which contains the dump files has to be set by attribute dumpDirLocal + to make it usable by the DbRep device.
      + All files with extension "sql[.gzip]" and if the filename is beginning with the name of the connected database + (see Internal DATABASE) are listed.
      + The restore speed depends of the server variable "max_allowed_packet". You can change + this variable in file my.cnf to adapt the speed. Please consider the need of sufficient ressources + (especially RAM). +

      + The database user needs rights for database management, e.g.:
      CREATE, ALTER, INDEX, DROP, SHOW VIEW, CREATE VIEW

      -

    • +
    • restoreSQLite <File>.sqlitebkp[.gzip] - 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[.gzip]" and if the filename is beginning with the name of the connected database - will are listed.

      -

    • + will are listed.

      +
      -
    • sqlCmd - Execute an arbitrary user specific command.
      +
    • sqlCmd - Execute an arbitrary user specific command.
      If the command contains a operation to delete data, the attribute 'allowDeletion' - has to be set for security reason.
      + has to be set for security reason.
      The statement doesn't consider limitations by attributes "device", "reading", "time.*" respectively "aggregation".
      This command also accept the setting of MySQL session variables like "SET @open:=NULL, @closed:=NULL;" or the usage of SQLite PRAGMA before execution the SQL-Statement. If the session variable or PRAGMA has to be set every time before executing a SQL statement, the attribute 'sqlCmdVars' can be set.
      - If the attribute 'timestamp_begin' respectively 'timestamp_end' - is assumed in the statement, it is possible to use placeholder §timestamp_begin§ respectively - §timestamp_end§ on suitable place.

      - - If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the - original timestamp.

      - -
        + If the attribute 'timestamp_begin' respectively 'timestamp_end' + is assumed in the statement, it is possible to use placeholder §timestamp_begin§ respectively + §timestamp_end§ on suitable place.

        + + If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the + original timestamp.

        + +
          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 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
            • @@ -13166,22 +13195,22 @@ return;
            • set <name> sqlCmd PRAGMA temp_store=MEMORY; PRAGMA synchronous=FULL; PRAGMA journal_mode=WAL; PRAGMA cache_size=4000; select count(*) from history;
            • set <name> sqlCmd PRAGMA temp_store=FILE; PRAGMA temp_store_directory = '/opt/fhem/'; VACUUM;
            -
            - - 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".

            - +
            + + 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".

            + The module provides a command history once a sqlCmd command was executed successfully. To use this option, activate the attribute "sqlCmdHistoryLength" with list lenght you want.

            For a better overview the relevant attributes for sqlCmd are listed in a table:

            -
              +
                - + @@ -13189,80 +13218,80 @@ return;
                allowDeletion : activates capabilty to delete datasets
                executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
                executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
                executeAfterProc : execution of FHEM command (or Perl-routine) after operation
                sqlResultFormat : determines presentation style of command result
                sqlResultFieldSep : choice of a useful field separator for result
                sqlCmdVars : set SQL session variable or PRAGMA before execute the SQL statement
                useAdminCredentials : use privileged user for the operation
                -
              -
              -
              +
            +
            +
            - Note:
            + 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.

            -
            + 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.

            +
        • sqlCmdHistory - If history is activated by attribute "sqlCmdHistoryLength", an already successfully executed sqlCmd-command can be repeated from a drop-down list.
          By execution of the last list entry, "__purge_historylist__", the list itself can be - deleted.

          + deleted.

          For a better overview the relevant attributes for this command are listed in a table:

          -
            +
              - +
              allowDeletion : activates capabilty to delete datasets
              executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
              executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
              executeAfterProc : execution of FHEM command (or Perl-routine) after operation
              sqlResultFormat : determines presentation style of command result
              sqlResultFieldSep : choice of a useful field separator for result
              -
            -
            -
            -
            +
          +
          +
          +

        • sqlSpecial - This function provides a drop-down list with a selection of prepared reportings.
          - The statements result is depicted in reading "SqlResult". - The result can be formatted by attribute sqlResultFormat + The statements result is depicted in reading "SqlResult". + The result can be formatted by attribute sqlResultFormat a well as the used field separator by attribute sqlResultFieldSep.

          - The following predefined reportings are selectable:

          -
            + The following predefined reportings are selectable:

            +
              - - + -
              50mostFreqLogsLast2days : reports the 50 most occuring log entries of the last 2 days
              allDevCount : all devices occuring in database and their quantity
              allDevReadCount : all device/reading combinations occuring in database and their quantity
              recentReadingsOfDevice : determines the newest records of a device available in the database. The - device must be defined in attribute device. - Only one device to be evaluated can be specified..
              readingsDifferenceByTimeDelta : determines the value difference of successive data records of a reading. The - device and reading must be defined in the attribute device or reading. - Only one device to be evaluated and only one reading to be evaluated can be specified. +
              recentReadingsOfDevice : determines the newest records of a device available in the database. The + device must be defined in attribute device. + Only one device to be evaluated can be specified..
              readingsDifferenceByTimeDelta : determines the value difference of successive data records of a reading. The + device and reading must be defined in the attribute device or reading. + Only one device to be evaluated and only one reading to be evaluated can be specified. The time limits of the evaluation are defined by the time.*-attributes.
              -
            -
            - - The relevant attributes for this function are:

            -
              + +
            +
            + + The relevant attributes for this function are:

            +
              - +
              executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
              executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
              executeAfterProc : execution of FHEM command (or Perl-routine) after operation
              sqlResultFormat : determines the formatting of the result
              sqlResultFieldSep : determines the used field separator in statement result
              -
            - +
          +


        • sumValue [display | writeToDB | writeToDBSingle | writeToDBInTime] - Calculates the total values of the database field "VALUE" in the time limits - of the possible time.*-attributes.

          + of the possible time.*-attributes.

          The reading to be evaluated must be specified in the attribute reading. This function is useful if continuous value differences of a reading are written @@ -13272,18 +13301,18 @@ return; the options writeToDB, writeToDBSingle or writeToDBInTime the calculation results are written with a new reading name into the database.

          -
            +
              - + -
              writeToDB : writes one value each with the time stamps XX:XX:01 and XX:XX:59 within the respective evaluation period
              writeToDB : writes one value each with the time stamps XX:XX:01 and XX:XX:59 within the respective evaluation period
              writeToDBSingle : writes only one value with the time stamp XX:XX:59 at the end of an evaluation period
              writeToDBInTime : writes a value at the beginning and end of the time limits of an evaluation period
              -
            -
            + +
          +
          The new reading name is formed from a prefix and the original reading name, - where the original reading name can be replaced by the attribute "readingNameMap". + where the original reading name can be replaced by the attribute "readingNameMap". The prefix consists of the educational function and the aggregation.
          The timestamp of the new reading in the database is determined by the set aggregation period if no clear time of the result can be determined. @@ -13298,19 +13327,19 @@ return; Summarized the relevant attributes to control this function are:

          -
            +
              - + - - + + -
              aggregation : choose the aggregation period
              aggregation : choose the aggregation period
              device : include or exclude <device> from selection
              executeBeforeProc : execution of FHEM command (or Perl-routine) before operation
              executeAfterProc : execution of FHEM command (or Perl-routine) after operation
              reading : include or exclude <reading> from selection
              readingNameMap : rename the resulted readings
              time.* : a number of attributes to limit selection by time
              readingNameMap : rename the resulted readings
              time.* : a number of attributes to limit selection by time
              valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
              -
            + +

        • @@ -13325,11 +13354,11 @@ return; If the attribute "aggregation" has value "no" or "month", the datasets are transmitted automatically in daily time slices into standby-database. Source- and Standby-database can be of different types. -

          +

          The relevant attributes to control the syncStandby function are:

          -
            +
              @@ -13341,29 +13370,29 @@ return;
              aggregation : adjustment of time slices for data transmission (hour,day,week,...)
              valueFilter : an additional REGEXP to control the record selection. The REGEXP is applied to the database field 'VALUE'.
              -
            +
          -
          - -
        • 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. +

        • + +
        • 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.

        • + "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. +
        • 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:
            +
              + 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.

              - -

            + +


      @@ -13400,26 +13429,29 @@ return;

          +
        • 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. + 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.
          + explained there.

          -
            - Example
            - get <name> dbstatus
            - attr <name> showStatus %uptime%,%qcache%
            - # Only readings containing "uptime" and "qcache" in name will be created +
              + Example
              + get <name> dbstatus
              + attr <name> showStatus %uptime%,%qcache%
              + # Only readings containing "uptime" and "qcache" in name will be created +


            -
          -
        • dbValue <SQL-statement> - + +
        • sqlCmdBlocking <SQL-statement> - Executes the specified SQL-statement in blocking manner. Because of its mode of operation this function is particular convenient for user own perl scripts.
          The input accepts multi line commands and delivers multi line results as well. @@ -13429,111 +13461,130 @@ return; by attribute "sqlResultFieldSep" (default "|"). Several result lines are separated by newline ("\n").
          This function only set/update status readings, the userExitFn function isn't called. -
          - -
            - Examples for use in FHEMWEB
            - {fhem("get <name> dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device")}
            - get <name> dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device
            - {CommandGet(undef,"Rep.LogDB1 dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device")}
            -
          -

          + +
            + Examples:
            + { fhem("get <name> sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device") }
            + { CommandGet(undef,"Rep.LogDB1 sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device") }
            + get <name> sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device
            +
          +
        • +

          + If you create a little routine in 99_myUtils, for example:
          -sub dbval($$) {
          -  my ($name,$cmd) = @_;
          -  my $ret = CommandGet(undef,"$name dbValue $cmd"); 
          -return $ret;
          +sub dbval {
          +  my $name = shift;
          +  my $cmd) = shift;
          +  my $ret = CommandGet(undef,"$name sqlCmdBlocking $cmd"); 
          +  return $ret;
           }                            
                                       
          it can be accessed with e.g. those calls:

          -
            - Examples:
            - {dbval("<name>","select count(*) from history")}
            - $ret = dbval("<name>","select count(*) from history");
            -
          - - -

          - +
            + Examples:
            + { dbval("<name>","select count(*) from history") }
            + $ret = dbval("<name>","select count(*) from history");
            +
          + +

          + +
        • 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.
          + there.

          -
            - Example
            - get <name> dbvars
            - attr <name> showVariables %version%,%query_cache%
            - # Only readings containing "version" and "query_cache" in name will be created +
              + Example
              + get <name> dbvars
              + attr <name> showVariables %version%,%query_cache%
              + # Only readings containing "version" and "query_cache" in name will be created +


            -
          +
        • minTimestamp - Identifies the oldest timestamp in the database (will be executed implicitely at FHEM start). The timestamp is used as begin of data selection if no time attribut is set to determine the start date.


        • +
        • 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.
          + 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.
        • -

          +

          -
        • storedCredentials - Reports the users / passwords stored for database access by the device.
          + +
        • storedCredentials - Reports the users / passwords stored for database access by the device.
          (only valid if database type is MYSQL)


        • +
        • 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.
          + 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 +
              + 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. + 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.
          + 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 +
              + Example
              + get <name> tableinfo
              + attr <name> showTableInfo current,history
              + # Only informations related to tables "current" and "history" are going to be created +
            -

            -
          +

          +
        • versionNotes [hints | rel | <key>] - Shows realease informations and/or hints about the module. It contains only main release informations for module users.
          If no options are specified, both release informations and hints will be shown. "rel" shows only release informations and "hints" shows only hints. By the <key>-specification only the hint with the specified number is shown. -
        • -
          +

          + +
            + + + + + +
            rel : zeigt nur Release Informationen
            hints : zeigt nur Hinweise an
            <key> : es wird der Hinweis mit der angegebenen Nummer angezeigt
            +
          + +
      @@ -13561,8 +13612,8 @@ return $ret;
    • aggregation - Aggregation of Device/Reading-selections. Possible values are hour, day, week, month, year and "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 contains all values of Device/Reading in the selected time period.

    • + difference values of a reading (sumValue) and so on. Using aggregation "no" (default) an + aggregation don't happens but the output contains all values of Device/Reading in the selected time period.
    • allowDeletion - unlocks the delete-function

    • @@ -13581,8 +13632,8 @@ return $ret; Wildcards (.*) are permitted in the specification <source-reading>.

        - Example: -
        +                                Example:
        +                                
         {
           ".*"        => "Dum.Rep.All",             
           ".*AVGAM.*" => "Dum.Rep     => average",  
        @@ -13601,18 +13652,18 @@ return $ret;
         
                                          At the moment the following methods are implemented: 

        -
          +
            - - -
            avgArithmeticMean : the arithmetic average is calculated (default)
            avgDailyMeanGWS : calculates the daily medium temperature according the +
            avgDailyMeanGWS : calculates the daily medium temperature according the specifications of german weather service (pls. see "get <name> versionNotes 2").
            This variant uses aggregation "day" automatically.
            avgTimeWeightMean : calculates a time weighted average mean value is calculated
            -
          + avgTimeWeightMean : calculates a time weighted average mean value is calculated + +

        @@ -13623,29 +13674,29 @@ return $ret;
      • device - Selection of particular or several devices.
        You can specify a list of devices separated by "," or use device specifications (devspec).
        - In that case the device names are derived from the device specification and the existing + In that case the device names are derived from the device specification and the existing devices in FHEM before carry out the SQL selection.
        If the the device, list or device specification is prepended by "EXCLUDE=", the devices are excluded from database selection.

          - Examples:
          - 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
          - attr <name> device TYPE=SSCam EXCLUDE=SDS1_SVS
          - attr <name> device TYPE=SSCam,TYPE=ESPEasy EXCLUDE=SDS1_SVS
          + Examples:
          + 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
          + attr <name> device TYPE=SSCam EXCLUDE=SDS1_SVS
          + attr <name> device TYPE=SSCam,TYPE=ESPEasy EXCLUDE=SDS1_SVS
          attr <name> device EXCLUDE=SDS1_SVS
          - attr <name> device EXCLUDE=TYPE=SSCam
          -
        + attr <name> device EXCLUDE=TYPE=SSCam
        +

      If you need more information about device specifications, execute "get <name> versionNotes 3". -

      +

      @@ -13656,24 +13707,24 @@ return $ret; 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. -

      + 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:

        - + 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

        - + 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. + 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

    • @@ -13686,21 +13737,21 @@ return $ret;
    • dumpDirLocal - Target directory of database dumps by command "dumpMySQL clientSide" or "dumpSQLite" (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" (dumpMySQL serverSide) to - DbRep.

    • + 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" (dumpMySQL serverSide) 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.

    • + 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.

    • @@ -13708,8 +13759,8 @@ return $ret;
    • 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.

    • + was created successfully. + The global attrubute "archivesort" will be considered.
    • executeAfterProc - you can specify a FHEM command or perl function which should be executed @@ -13717,12 +13768,12 @@ return $ret; Perl functions have to be enclosed in {} .

        - Example:

        - attr <name> executeAfterProc set og_gz_westfenster off;
        - attr <name> executeAfterProc {adump ("<name>")}

        - - # "adump" is a function defined in 99_myUtils.pm e.g.:
        - + Example:

        + attr <name> executeAfterProc set og_gz_westfenster off;
        + attr <name> executeAfterProc {adump ("<name>")}

        + + # "adump" is a function defined in 99_myUtils.pm e.g.:
        +
         sub adump {
             my ($name) = @_;
        @@ -13742,12 +13793,12 @@ sub adump {
                                          Perl functions have to be enclosed in {} .

          - Example:

          - attr <name> executeBeforeProc set og_gz_westfenster on;
          - attr <name> executeBeforeProc {bdump ("<name>")}

          - - # "bdump" is a function defined in 99_myUtils.pm e.g.:
          - + Example:

          + attr <name> executeBeforeProc set og_gz_westfenster on;
          + attr <name> executeBeforeProc {bdump ("<name>")}

          + + # "bdump" is a function defined in 99_myUtils.pm e.g.:
          +
           sub bdump {
               my ($name) = @_;
          @@ -13774,7 +13825,7 @@ sub bdump {
                                           strftime manual). 
                                           

          -
            +
              @@ -13789,20 +13840,20 @@ sub bdump {
              %L : is replaced by the value of global logdir attribute
              %U : week number of year with Sunday as first day of week (00..53)
              %W : week number of year with Monday as first day of week (00..53)
              -
            +

            - Examples:
            - attr <name> expimpfile /sds1/backup/exptest_%TSB.csv
            + Examples:
            + attr <name> expimpfile /sds1/backup/exptest_%TSB.csv
            attr <name> expimpfile /sds1/backup/exptest_%Y-%m-%d.csv
            -
          +

        About POSIX wildcard usage please see also explanations in Filelog.
        -

        +

        @@ -13827,9 +13878,9 @@ sub bdump { ascent - the data are read ascent . If amount of datasets specified by attribut "limit" is exceeded, the oldest x datasets are shown.
        -
      - -


    • +
    + +


  • fetchValueFn - When fetching the database content, you are able to manipulate the value fetched from the @@ -13838,10 +13889,10 @@ sub bdump { The value of the database field VALUE is provided in variable $VALUE.

      - Example:
      - attr <name> fetchValueFn { $VALUE =~ s/^.*Used:\s(.*)\sMB,.*/$1." MB"/e }
      - - # From a long line a specific pattern is extracted and will be displayed als VALUE instead + Example:
      + attr <name> fetchValueFn { $VALUE =~ s/^.*Used:\s(.*)\sMB,.*/$1." MB"/e }
      + + # From a long line a specific pattern is extracted and will be displayed als VALUE instead the whole line


  • @@ -13849,13 +13900,13 @@ sub bdump {
  • 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".

  • @@ -13868,7 +13919,7 @@ sub bdump {
  • ftpDumpFilesKeep - leave the number of dump files in FTP-destination <ftpDir> (default: 3). Are there more (older) dump files present, these files are deleted after a new dump was transfered successfully.

  • - +
  • ftpPassive - set if passive FTP is to be used

  • @@ -13887,38 +13938,38 @@ sub bdump {
  • 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).

  • + 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") ! + FHEM if DbLog isn't working in asynchronous mode (DbLog-attribute "asyncMode") !
      -
    +

  • reading - Selection of particular or several readings. More than one reading can be specified by a comma separated list.
    - SQL wildcard (%) can be used.
    + SQL wildcard (%) can be used.
    If the reading or the reading list is prepended by "EXCLUDE=", those readings are not included.

    - +
      - Examples:
      - attr <name> reading etotal
      - attr <name> reading et%
      - attr <name> reading etotal,etoday
      + Examples:
      + attr <name> reading etotal
      + attr <name> reading et%
      + attr <name> reading etotal,etoday
      attr <name> reading eto%,Einspeisung EXCLUDE=etoday
      attr <name> reading etotal,etoday,Ein% EXCLUDE=%Wirkleistung
      -
    -

    + +

  • @@ -13952,19 +14003,19 @@ sub bdump {

      - Examples:
      - attr <name> seqDoubletsVariance 0.0014
      - attr <name> seqDoubletsVariance 1.45
      + Examples:
      + attr <name> seqDoubletsVariance 0.0014
      + attr <name> seqDoubletsVariance 1.45
      attr <name> seqDoubletsVariance 3.0 2.0
      attr <name> seqDoubletsVariance 1.5 EDGE=negative
      -
    -

    + +

  • 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.

  • + of all sql-statements necessara for within an executed DbRep-function in background.
  • showStatus - limits the sample space of command "get <name> dbstatus". SQL-Wildcard (%) can be used. @@ -13988,7 +14039,7 @@ sub bdump {
  • - +
  • showSvrInfo - limits the sample space of command "get <name> svrinfo". SQL-Wildcard (%) can be used.

    @@ -13999,7 +14050,7 @@ sub bdump {
  • - +
  • showTableInfo - Determine the tablenames which are selected by command "get <name> tableinfo". SQL-Wildcard (%) can be used.

    @@ -14011,7 +14062,7 @@ sub bdump {
  • - +
  • sqlCmdHistoryLength - Activates the command history of "sqlCmd" and determines the length of it.

  • @@ -14020,9 +14071,9 @@ sub bdump { statement with "set <name> sqlCmd".

      - Examples:
      - attr <name> sqlCmdVars SET @open:=NULL, @closed:=NULL;
      - attr <name> sqlCmdVars PRAGMA temp_store=MEMORY;PRAGMA synchronous=FULL;PRAGMA journal_mode=WAL;
      + Examples:
      + attr <name> sqlCmdVars SET @open:=NULL, @closed:=NULL;
      + attr <name> sqlCmdVars PRAGMA temp_store=MEMORY;PRAGMA synchronous=FULL;PRAGMA journal_mode=WAL;


    @@ -14037,24 +14088,24 @@ sub bdump {
      separated - every line of the result will be generated sequentially in a single - reading. (default)

      + reading. (default)

      mline - the result will be generated as multiline in - Reading SqlResult. -

      + Reading SqlResult. +

      sline - the result will be generated as singleline in - Reading SqlResult. - Datasets are separated by "]|[".

      + Reading SqlResult. + Datasets are separated by "]|[".

      table - the result will be generated as an table in - Reading SqlResult.

      + Reading SqlResult.

      json - creates the Reading SqlResult as a JSON - coded hash. - Every hash-element consists of the serial number of the dataset (key) - and its value. + 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:
      -
      +        To process the result, you may use a userExitFn in 99_myUtils for example: 
      +
               sub resfromjson {
                 my ($name,$reading,$value) = @_;
                 my $hash   = $defs{$name};
      @@ -14062,23 +14113,23 @@ sub bdump {
                 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);
      +          
      +            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;
               }
      -  	    
      +
    -
    +
    @@ -14089,18 +14140,18 @@ sub bdump {

      - Example:

      - attr <name> timeYearPeriod 06-25 06-24

      - - # evaluates the database within the time limits 25. june AAAA and 24. june BBBB.
      + Example:

      + attr <name> 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
    The format of timestamp is as used with DbLog "YYYY-MM-DD HH:MM:SS". For the attributes "timestamp_begin", "timestamp_end" @@ -14162,13 +14213,13 @@ sub bdump { Make sure that "timestamp_begin" < "timestamp_end" is fulfilled.

      - Example:

      - attr <name> timestamp_begin current_year_begin
      - attr <name> timestamp_end current_year_end

      - - # Analyzes the database between the time limits of the current year.
      -
    -

    + Example:

    + attr <name> timestamp_begin current_year_begin
    + attr <name> timestamp_end current_year_end

    + + # Analyzes the database between the time limits of the current year.
    + +

    Note
    @@ -14186,67 +14237,67 @@ sub bdump {

      - Examples for input format:
      - attr <name> timeDiffToNow 86400
      + 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
      + 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
      + attr <name> timeDiffToNow h:2.5
      # the start time is set to "current time - 2,5 hours"
      - attr <name> timeDiffToNow y:1 h:2.5
      + attr <name> timeDiffToNow y:1 h:2.5
      # the start time is set to "current time - 1 year and 2,5 hours"
      - attr <name> timeDiffToNow y:1.5
      + attr <name> timeDiffToNow y:1.5
      # the start time is set to "current time - 1.5 years"
      attr <name> timeDiffToNow d:8 FullDay
      # the start time is set to "current time - 8 days", the selection time period is expanded to the begin / end of the involved days
      -
    -
    + +
    If both attributes "timeDiffToNow" and "timeOlderThan" are set, the selection period will be calculated between of these timestamps dynamically.

    -
  • +
  • timeOlderThan - the end time 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. The time period will be calculated dynamically at - execution time. Optional can with the additional entry "FullDay" the selection start time + "<current time> - <timeOlderThan>" will be considered. The time period will be calculated dynamically at + execution time. Optional can with the additional entry "FullDay" the selection start time and the selection end time be expanded to the begin / end of the involved days (take only effect if adjusted time difference is >= 1 day).

      - Examples for input format:
      - attr <name> timeOlderThan 86400
      + Examples for input format:
      + attr <name> timeOlderThan 86400
      # the selection end time is set to "current time - 86400 seconds"
      - attr <name> timeOlderThan d:2 h:3 m:2 s:10
      - # the selection end time is set to "current time - 2 days 3 hours 2 minutes 10 seconds"
      - attr <name> timeOlderThan m:600
      + attr <name> timeOlderThan d:2 h:3 m:2 s:10
      + # the selection end time is set to "current time - 2 days 3 hours 2 minutes 10 seconds"
      + attr <name> timeOlderThan m:600
      # the selection end time is set to "current time - 600 minutes" gesetzt
      - attr <name> timeOlderThan h:2.5
      + attr <name> timeOlderThan h:2.5
      # the selection end time is set to "current time - 2,5 hours"
      - attr <name> timeOlderThan y:1 h:2.5
      + attr <name> timeOlderThan y:1 h:2.5
      # the selection end time is set to "current time - 1 year and 2,5 hours"
      - attr <name> timeOlderThan y:1.5
      + attr <name> timeOlderThan y:1.5
      # the selection end time is set to "current time - 1.5 years"
      attr <name> timeOlderThan d:8 FullDay
      # the end time is set to "current time - 8 days", the selection time period is expanded to the begin / end of the involved days
      -
    -
    + +
    If both attributes "timeDiffToNow" and "timeOlderThan" are set, the selection period will be calculated between of these timestamps dynamically.

  • - +
  • timeout - set the timeout-value for Blocking-Call Routines in background in seconds (default 86400)

  • - +
  • useAdminCredentials - If set, a before with "set <aame> adminCredentials" saved privileged user is used for particular database operations.
    @@ -14258,7 +14309,7 @@ sub bdump { To activate the interfaace, at first you should implement the subroutine which will be called by the interface in your 99_myUtils.pm as shown by the example:
    -
    +        
             sub UserFunction {
               my ($name,$reading,$value) = @_;
               my $hash = $defs{$name};
    @@ -14268,32 +14319,32 @@ sub bdump {
               ...
             return;
             }
    -  	    
    - The interface activation takes place by setting the subroutine name into the attribute. +
    + The interface activation takes place by setting the subroutine name into 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:
      + 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 creation in the device the Regex will be - evaluated. - If the evaluation is true, the subroutine will be called. - For further processing the following parameters are forwarded to the function:

      +
    +
    -
      + The interface works generally without and independent from events. + If the attribute is set, after every reading creation in the device the Regex will be + evaluated. + If the evaluation is true, the subroutine will be called. + For further processing the following parameters are forwarded to the function:

      + +
      • $name - the name of the DbRep-Device
      • $reading - the name of the created reading
      • $value - the value of the reading
      • - -
      -

      + +
    +

  • @@ -14302,7 +14353,7 @@ sub bdump { so on). Please consider the explanations within the set-commands. Further information is available with command "get <name> versionNotes 4".
    - + @@ -14330,11 +14381,11 @@ sub bdump { 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".

  • + 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

  • @@ -14394,7 +14445,7 @@ sub bdump {
    - + 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.

    @@ -14426,29 +14477,29 @@ sub bdump {
  • Selektion der Datensätze unter Verwendung von dynamisch berechneter Zeitgrenzen zum Ausführungszeitpunkt.
  • Dubletten-Hervorhebung bei Datensatzanzeige (fetchrows)
  • Berechnung der Anzahl von Datensätzen einer Device/Reading-Kombination unter Berücksichtigung von Zeitgrenzen - und verschiedenen Aggregationen.
  • + und verschiedenen Aggregationen.
  • Die Berechnung von Summen-, Differenz-, Maximum-, Minimum- und Durchschnittswerten numerischer Readings - in Zeitgrenzen und verschiedenen Aggregationen.
  • + 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.
  • + 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/Readings in Datenbanksätzen
  • Ändern von Reading-Werten (VALUES) in der Datenbank (changeValue)
  • 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 (non-blocking)
  • -
  • Ausführen von beliebigen Benutzer spezifischen SQL-Kommandos (blocking) zur Verwendung in eigenem Code (dbValue)
  • -
  • Backups der FHEM-Datenbank im laufenden Betrieb erstellen (MySQL, SQLite)
  • -
  • senden des Dumpfiles zu einem FTP-Server nach dem Backup incl. Versionsverwaltung
  • -
  • Restore von SQLite- und MySQL-Dumps
  • -
  • 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
  • + Befehl (siehe DbRep-Agent) +
  • Ausführen von beliebigen Benutzer spezifischen SQL-Kommandos (non-blocking)
  • +
  • Ausführen von beliebigen Benutzer spezifischen SQL-Kommandos (blocking) zur Verwendung in eigenem Code (sqlCmdBlocking)
  • +
  • Backups der FHEM-Datenbank im laufenden Betrieb erstellen (MySQL, SQLite)
  • +
  • senden des Dumpfiles zu einem FTP-Server nach dem Backup incl. Versionsverwaltung
  • +
  • Restore von SQLite- und MySQL-Dumps
  • +
  • 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 mit unterschiedlichen Zeitstempel aber gleichen Werten (sequentielle Dublettenbereinigung)
  • -
  • Reparatur einer korrupten SQLite Datenbank ("database disk image is malformed")
  • +
  • Reparatur einer korrupten SQLite Datenbank ("database disk image is malformed")
  • Übertragung von Datensätzen aus der Quelldatenbank in eine andere (Standby) Datenbank (syncStandby)
  • Reduktion der Anzahl von Datensätzen in der Datenbank (reduceLog)
  • Löschen von doppelten Datensätzen (delDoublets)
  • @@ -14466,8 +14517,9 @@ sub bdump { Sobald ein DbRep-Device definiert ist, wird sowohl die Perl Funktion DbReadingsVal als auch das FHEM Kommando dbReadingsVal zur Verfügung gestellt. - Mit dieser Funktion läßt sich, ähnlich dem allgemeinen ReadingsVal, der Wert eines Readings aus der Datenbank abrufen. - Die Funktionsausführung erfolgt blockierend.

    + Mit dieser Funktion läßt sich, ähnlich dem allgemeinen ReadingsVal, der Wert eines Readings aus der Datenbank abrufen.
    + Die Funktionsausführung erfolgt blockierend mit einem Standardtimeout von 10 Sekunden um eine dauerhafte Blockierung von FHEM zu verhindern. + Der Timeout ist mit dem Attribut timeout anpassbar.

      Die Befehlssyntax für die Perl Funktion ist:

      @@ -14477,7 +14529,7 @@ sub bdump {

      - Beispiele:
      + Beispiel:
         $ret = DbReadingsVal("Rep.LogDB1","MyWetter:temperature","2018-01-13_08:00:00","");
         attr <name> userReadings oldtemp {DbReadingsVal("Rep.LogDB1","MyWetter:temperature","2018-04-13_08:00:00","")} 
      @@ -14499,7 +14551,9 @@ sub bdump {
         

      Beispiel:
      - dbReadingsVal Rep.LogDB1 MyWetter:temperature 2018-01-13_08:00:00 0 + + dbReadingsVal Rep.LogDB1 MyWetter:temperature 2018-01-13_08:00:00 0 +

      @@ -14581,7 +14635,7 @@ sub bdump {
        • adminCredentials <User> <Passwort> - - Speichert einen User / Passwort für den privilegierten bzw. administrativen + - Speichert einen User / Passwort für den privilegierten bzw. administrativen Datenbankzugriff. Er wird bei Datenbankoperationen benötigt, die mit einem privilegierten User ausgeführt werden müssen. Siehe auch Attribut 'useAdminCredentials'.
          (nur gültig bei Datenbanktyp MYSQL und DbRep-Typ "Client") @@ -14590,10 +14644,10 @@ sub bdump {
        • averageValue [display | writeToDB | writeToDBSingle | writeToDBInTime] - berechnet einen Durchschnittswert des Datenbankfelds "VALUE" in den Zeitgrenzen - der möglichen time.*-Attribute.

          + der möglichen time.*-Attribute.

          Es muss das auszuwertende Reading im Attribut reading - angegeben sein. + angegeben sein. Mit dem Attribut averageCalcForm wird die Berechnungsvariante zur Mittelwertermittlung definiert.

          @@ -14601,18 +14655,18 @@ sub bdump { den Optionen writeToDB, writeToDBSingle bzw. writeToDBInTime werden die Berechnungsergebnisse mit einem neuen Readingnamen in der Datenbank gespeichert.

          -
            +
      - + -
      writeToDB : schreibt jeweils einen Wert mit den Zeitstempeln XX:XX:01 und XX:XX:59 innerhalb der jeweiligen Auswertungsperiode
      writeToDB : schreibt jeweils einen Wert mit den Zeitstempeln XX:XX:01 und XX:XX:59 innerhalb der jeweiligen Auswertungsperiode
      writeToDBSingle : schreibt nur einen Wert mit dem Zeitstempel XX:XX:59 am Ende einer Auswertungsperiode
      writeToDBInTime : schreibt jeweils einen Wert am Anfang und am Ende der Zeitgrenzen einer Auswertungsperiode
      -
    -
    + + +
    Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet, - wobei der originale Readingname durch das Attribut "readingNameMap" ersetzt werden kann. + wobei der originale Readingname durch das Attribut "readingNameMap" ersetzt werden kann. 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. @@ -14627,22 +14681,22 @@ sub bdump { Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

    -
      +
        - + - + - - + + -
        aggregation : Auswahl einer Aggregationsperiode
        aggregation : Auswahl einer Aggregationsperiode
        averageCalcForm : Auswahl der Berechnungsvariante für den Durchschnitt
        device : einschließen oder ausschließen von Datensätzen die <device> enthalten
        executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
        executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
        executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
        reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
        readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
        time.* : eine Reihe von Attributen zur Zeitabgrenzung
        readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
        time.* : eine Reihe von Attributen zur Zeitabgrenzung
        valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
        -
      -
      -
      + +
    +
    +

    @@ -14665,15 +14719,15 @@ sub bdump { +
  • ein String mit Verwendung von SQL-Wildcard, z.B. "%OL%"
  • - - + -
    <alter String> :
  • ein einfacher String mit/ohne Leerzeichen, z.B. "OL 12"
  • -
  • ein String mit Verwendung von SQL-Wildcard, z.B. "%OL%"
  • <neuer String> :
  • ein einfacher String mit/ohne Leerzeichen, z.B. "12 kWh"
  • +
    <neuer String> :
  • ein einfacher String mit/ohne Leerzeichen, z.B. "12 kWh"
  • Perl Code eingeschlossen in "{}" inkl. Quotes, z.B. "{($VALUE,$UNIT) = split(" ",$VALUE)}". Dem Perl-Ausdruck werden die Variablen $VALUE und $UNIT übergeben. Sie können innerhalb des Perl-Code geändert werden. Der zurückgebene Wert von $VALUE und $UNIT wird in dem Feld VALUE bzw. UNIT des Datensatzes gespeichert.
  • +
    Beispiele:
    @@ -14692,40 +14746,40 @@ sub bdump { Zusammengefasst sind die zur Steuerung von changeValue relevanten Attribute:

    -
      +
        - +
        device : einschließen oder ausschließen von Datensätzen die <device> enthalten
        aggregation : Auswahl einer Aggregationsperiode
        reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
        time.* : eine Reihe von Attributen zur Zeitabgrenzung
        executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start changeValue
        executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start changeValue
        executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende changeValue
        valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
        -
      -
      -
      - - Hinweis:
      +
    +
    +
    + + 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).


    - +
  • countEntries [history | current] - liefert die Anzahl der Tabelleneinträge (default: history) in den gegebenen - Zeitgrenzen (siehe Attribute). + Zeitgrenzen (siehe Attribute). Sind die Timestamps nicht gesetzt, werden alle Einträge der Tabelle gezählt. Beschränkungen durch die Attribute Device bzw. Reading - gehen in die Selektion mit ein.
    + gehen in die Selektion mit ein.
    Standardmäßig wird die Summe aller Datensätze, gekennzeichnet mit "ALLREADINGS", erstellt. Ist das Attribut "countEntriesDetail" gesetzt, wird die Anzahl jedes einzelnen Readings zusätzlich ausgegeben.

    Die für diese Funktion relevanten Attribute sind:

    -
      +
        @@ -14736,76 +14790,76 @@ sub bdump {
        aggregation : Zusammenfassung/Gruppierung von Zeitintervallen
        readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
        valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
        -
      -
      +
    +

  • delDoublets [adviceDelete | delete] - zeigt bzw. löscht doppelte / mehrfach vorkommende Datensätze. - Dazu wird Timestamp, Device,Reading und Value ausgewertet.
    - Die Attribute zur Aggregation,Zeit-,Device- und Reading-Abgrenzung werden dabei - berücksichtigt. Ist das Attribut "aggregation" nicht oder auf "no" gesetzt, wird im Standard die Aggregation - "day" verwendet. -

    - -
      + Dazu wird Timestamp, Device,Reading und Value ausgewertet.
      + Die Attribute zur Aggregation,Zeit-,Device- und Reading-Abgrenzung werden dabei + berücksichtigt. Ist das Attribut "aggregation" nicht oder auf "no" gesetzt, wird im Standard die Aggregation + "day" verwendet. +

      + +
        adviceDelete : ermittelt die zu löschenden Datensätze (es wird nichts gelöscht !)
        delete : löscht die Dubletten
        -
      -
      +
    +
    Aus Sicherheitsgründen muss das Attribut "allowDeletion" für die "delete" Option - gesetzt sein.
    - Die Anzahl der anzuzeigenden Datensätze des Kommandos "delDoublets adviceDelete" ist zunächst - begrenzt (default 1000) und kann durch das Attribut "limit" angepasst - werden. - Die Einstellung von "limit" hat keinen Einfluss auf die "delDoublets delete" Funktion, sondern - beeinflusst NUR die Anzeige der Daten.
    + gesetzt sein.
    + Die Anzahl der anzuzeigenden Datensätze des Kommandos "delDoublets adviceDelete" ist zunächst + begrenzt (default 1000) und kann durch das Attribut "limit" angepasst + werden. + Die Einstellung von "limit" hat keinen Einfluss auf die "delDoublets delete" Funktion, sondern + beeinflusst NUR die Anzeige der Daten.
    Vor und nach der Ausführung von "delDoublets" kann ein FHEM-Kommando bzw. Perl-Routine ausgeführt - werden. (siehe Attribute "executeBeforeProc", "executeAfterProc") -

    - -
      - Beispiel:

      + werden. (siehe Attribute "executeBeforeProc", "executeAfterProc") +

      + +
        + Beispiel:

        Ausgabe der zu löschenden Records inklusive der Anzahl mit "delDoublets adviceDelete":

        - - 2018-11-07_14-11-38__Dum.Energy__T 260.9_|_2
        - 2018-11-07_14-12-37__Dum.Energy__T 260.9_|_2
        - 2018-11-07_14-15-38__Dum.Energy__T 264.0_|_2
        - 2018-11-07_14-16-37__Dum.Energy__T 264.0_|_2
        -
        - Im Werteteil der erzeugten Readings wird nach "_|_" die Anzahl der entsprechenden Datensätze - ausgegeben, die mit "delDoublets delete" gelöscht werden. -
      + + 2018-11-07_14-11-38__Dum.Energy__T 260.9_|_2
      + 2018-11-07_14-12-37__Dum.Energy__T 260.9_|_2
      + 2018-11-07_14-15-38__Dum.Energy__T 264.0_|_2
      + 2018-11-07_14-16-37__Dum.Energy__T 264.0_|_2
      +
      + Im Werteteil der erzeugten Readings wird nach "_|_" die Anzahl der entsprechenden Datensätze + ausgegeben, die mit "delDoublets delete" gelöscht werden. +

    Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

    -
      +
        - - + + - - - - -
        allowDeletion : needs to be set to execute the delete option
        aggregation : Auswahl einer Aggregationsperiode
        allowDeletion : needs to be set to execute the delete option
        aggregation : Auswahl einer Aggregationsperiode
        device : einschließen oder ausschließen von Datensätzen die <device> enthalten
        limit : begrenzt NUR die Anzahl der anzuzeigenden Datensätze
        reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
        time.* : eine Reihe von Attributen zur Zeitabgrenzung
        executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start des Befehls
        executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende des Befehls
        valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
        -
      -
      -
      + time.* : eine Reihe von Attributen zur Zeitabgrenzung + executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start des Befehls + executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende des Befehls + valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet. + +
    +
    +
  • delEntries [<no>[:<nn>]] - löscht alle oder die durch die Attribute device und/oder - reading definierten Datenbankeinträge. Die Eingrenzung über Timestamps erfolgt - folgendermaßen:

    + 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
      @@ -14817,16 +14871,16 @@ sub bdump {
      Aus Sicherheitsgründen muss das Attribut allowDeletion - gesetzt sein um die Löschfunktion freizuschalten.
      - Zeitgrenzen (Tage) können als Option angegeben werden. In diesem Fall werden eventuell gesetzte Zeitattribute - übersteuert. - Es werden Datensätze berücksichtigt die älter sind als <no> Tage und (optional) neuer sind als - <nn> Tage. -

      + gesetzt sein um die Löschfunktion freizuschalten.
      + Zeitgrenzen (Tage) können als Option angegeben werden. In diesem Fall werden eventuell gesetzte Zeitattribute + übersteuert. + Es werden Datensätze berücksichtigt die älter sind als <no> Tage und (optional) neuer sind als + <nn> Tage. +

      Die zur Steuerung von delEntries relevanten Attribute:

      -
        +
          @@ -14834,51 +14888,51 @@ sub bdump { - +
          allowDeletion : Freischaltung der Löschfunktion
          reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
          readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
          time.* : eine Reihe von Attributen zur Zeitabgrenzung
          executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start delEntries
          executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start delEntries
          executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende delEntries
          valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
          -
        -
        +
      +
      -
      - +
      +
    • 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 + 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 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.
      + 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.
      Vor und nach der Ausführung von "delSeqDoublets" kann ein FHEM-Kommando bzw. Perl-Routine ausgeführt werden. (siehe Attribute executeBeforeProc, executeAfterProc) -

      - -
        - Beispiel - die nach Verwendung der delete-Option in der DB verbleibenden Datensätze sind fett - gekennzeichnet:

        -
          +

          + +
            + 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
              @@ -14908,29 +14962,29 @@ sub bdump { 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
            -
          +

        Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

        -
          +
            - - + + - - - - + + + + - -
            allowDeletion : needs to be set to execute the delete option
            aggregation : Auswahl einer Aggregationsperiode
            allowDeletion : needs to be set to execute the delete option
            aggregation : Auswahl einer Aggregationsperiode
            device : einschließen oder ausschließen von Datensätzen die <device> enthalten
            limit : begrenzt NUR die Anzahl der anzuzeigenden Datensätze
            reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
            readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
            seqDoubletsVariance : bis zu diesem Wert werden aufeinander folgende numerische Datensätze als identisch angesehen und werden gelöscht
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start des Befehls
            readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
            seqDoubletsVariance : bis zu diesem Wert werden aufeinander folgende numerische Datensätze als identisch angesehen und werden gelöscht
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start des Befehls
            executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende des Befehls
            valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
            -
          -
          -
          + valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet. + +
        +
        +
        @@ -14938,8 +14992,8 @@ sub bdump {
      • deviceRename <old_name>,<new_name> - 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.

        + Zeitgrenzen oder Beschränkungen durch die Attribute Device bzw. + Reading werden nicht berücksichtigt.

          Beispiel:
          @@ -14948,8 +15002,8 @@ sub bdump { # 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:
          + + 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).


          @@ -14958,16 +15012,16 @@ sub bdump {
        • diffValue [display | writeToDB] - berechnet den Differenzwert des Datenbankfelds "VALUE" in den angegebenen Zeitgrenzen (siehe verschiedenen time*-Attribute). Es muss das auszuwertende Reading im Attribut reading angegeben sein.
          - Diese Funktion ist z.B. zur Auswertung von Daten sinnvoll, deren Werte sich fortlaufend erhöhen und keine Wertdifferenzen wegschreiben.
          + Diese Funktion ist z.B. zur Auswertung von Daten sinnvoll, deren Werte sich fortlaufend erhöhen und keine Wertdifferenzen wegschreiben.
          Es wird immer die Differenz aus den VALUE-Werten der im Aggregationszeitraum (z.B. day) vorhandenen Datensätzen gebildet und aufsummiert, - 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.

          - + 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 @@ -14980,7 +15034,7 @@ sub bdump { 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, - wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. + wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. 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. @@ -14995,53 +15049,53 @@ sub bdump { Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

            -
              +
                - + - - + + - - + + -
                aggregation : Auswahl einer Aggregationsperiode
                aggregation : Auswahl einer Aggregationsperiode
                device : einschließen oder ausschließen von Datensätzen die <device> enthalten
                diffAccept : akzeptierte positive Werte-Differenz zwischen zwei unmittelbar aufeinander folgenden Datensätzen
                executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
                diffAccept : akzeptierte positive Werte-Differenz zwischen zwei unmittelbar aufeinander folgenden Datensätzen
                executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
                executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
                reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
                readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
                time* : eine Reihe von Attributen zur Zeitabgrenzung
                readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
                time* : eine Reihe von Attributen zur Zeitabgrenzung
                valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
                -
              -
              + +
            +

          • 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.
            + - 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.
            Mit dem Attribut "dumpCompress" kann eine Komprimierung der erstellten Dumpfiles eingeschaltet werden. -

            - -
              - 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. - Nach dem Dump kann ebenfalls ein FHEM-Kommando (siehe Attribut "executeAfterProc") ausgeführt werden.

              - - Achtung !
              - Um ein Blockieren von FHEM zu vermeiden, muß DbLog im asynchronen Modus betrieben werden wenn die - Tabellenoptimierung verwendet wird !


              - - Ü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:

              -
                +
                  + 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. + Nach dem Dump kann ebenfalls ein FHEM-Kommando (siehe Attribut "executeAfterProc") ausgeführt werden.

                  + + Achtung !
                  + Um ein Blockieren von FHEM zu vermeiden, muß DbLog im asynchronen Modus betrieben werden wenn die + Tabellenoptimierung verwendet wird !


                  + + Ü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:

                  +
                    @@ -15049,179 +15103,179 @@ sub bdump { - - + + - +
                    dumpComment : User-Kommentar im Dumpfile
                    dumpDirLocal : das lokale Zielverzeichnis für die Erstellung des Dump
                    dumpMemlimit : Begrenzung der Speicherverwendung
                    dumpSpeed : Begrenzung die CPU-Belastung
                    dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
                    executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
                    dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
                    executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
                    executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach dem Dump
                    optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
                    optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
                    -
                  -
                  +
                +
                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". Falls "dumpFilesKeep = 0" gesetzt ist, werden alle Dumpfiles (auch das aktuell erstellte File), gelöscht. Diese Einstellung kann sinnvoll sein, wenn FTP aktiviert ist und die erzeugten Dumps nur im FTP-Zielverzeichnis erhalten bleiben sollen.

                - - Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sql[.gzip]

                - - Um die Datenbank aus dem Dumpfile wiederherzustellen kann das Kommmando:

                - -
                  - set <name> restoreMySQL <filename>

                  -
                + + Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sql[.gzip]

                + + Um die Datenbank aus dem Dumpfile wiederherzustellen kann das Kommmando:

                + +
                  + set <name> restoreMySQL <filename>

                  +
                - verwendet werden.

                - - Das erzeugte Dumpfile (unkomprimiert) kann ebenfalls 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.

                + verwendet werden.

                + + Das erzeugte Dumpfile (unkomprimiert) kann ebenfalls 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:

                -
                  + Die für "dumpMySQL serverSide" relevanten Attribute sind:

                  +
                    - - + + - +
                    dumpDirRemote : das Erstellungsverzeichnis des Dumpfile auf dem entfernten Server
                    dumpCompress : Komprimierung des Dumpfiles nach der Erstellung
                    dumpDirLocal : Directory des lokal gemounteten dumpDirRemote-Verzeichnisses
                    dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
                    executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
                    dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
                    executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
                    executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach dem Dump
                    optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
                    optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
                    -
                  -
                  - - 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 (siehe Wiki).

                  - - Hinweis:
                  - Soll die interne Versionsverwaltung und die Dumpfilekompression des Moduls genutzt, sowie die Größe des erzeugten +
                +
                + + 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 (siehe Wiki).

                + + Hinweis:
                + Soll die interne Versionsverwaltung und die Dumpfilekompression des Moduls genutzt, sowie 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"). -

                + 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 <name> dumpDirRemote /volume1/ApplicationBackup/dumps_FHEM/
                  - attr <name> dumpDirLocal /sds1/backup/dumps_FHEM/
                  - attr <name> dumpFilesKeep 2

                  - + attr <name> dumpDirLocal /sds1/backup/dumps_FHEM/
                  + attr <name> 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.
                  + 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".

              + 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[.gzip]

              - - Ein Restore der Datenbank aus diesem Backup kann durch den Befehl:

              -
                - set <name> <restoreMySQL> <filename>.csv[.gzip]

                -
              - - gestartet werden.

              + Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.csv[.gzip]

              + + Ein Restore der Datenbank aus diesem Backup kann durch den Befehl:

              +
                + set <name> <restoreMySQL> <filename>.csv[.gzip]

                +
              + + 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.
              + 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.
              Das Modul übernimmt ebenfalls die Versionierung der Dumpfiles im FTP-Zielverzeichnis mit Hilfe des Attributes "ftpDumpFilesKeep". - Für die FTP-Übertragung relevante Attribute sind:

              - -
                + Für die FTP-Übertragung relevante 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: "/")
                  ftpDumpFilesKeep : Es wird die angegebene Anzahl Dumpfiles im <ftpDir> belassen (default: 3)
                  ftpDir : Verzeichnis auf dem FTP-Server in welches das File übertragen werden soll (default: "/")
                  ftpDumpFilesKeep : Es wird die angegebene Anzahl Dumpfiles im <ftpDir> belassen (default: 3)
                  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).
                  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 + 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") + 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:

          -
            + 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:

            +
              - - + + - +
              dumpCompress : Komprimierung des Dumpfiles nach der Erstellung
              dumpDirLocal : Zielverzeichnis der Dumpfiles
              dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
              dumpFilesKeep : Anzahl der aufzubwahrenden Dumpfiles
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor dem Dump
              executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach dem Dump
              optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
              optimizeTablesBeforeDump : Tabelloptimierung vor dem Dump ausführen
              -
            -
            +
          +
          - Nach einem erfolgreichen Dump werden alte Dumpfiles gelöscht und nur die Anzahl Files, definiert durch das + 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". Falls "dumpFilesKeep = 0" gesetzt, werden alle Dumpfiles (auch das aktuell erstellte File), gelöscht. Diese Einstellung kann sinnvoll sein, wenn FTP aktiviert ist und die erzeugten Dumps nur im FTP-Zielverzeichnis erhalten bleiben sollen.

          - - Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sqlitebkp[.gzip]

          - - Die Datenbank kann mit "set <name> restoreSQLite <Filename>" wiederhergestellt + + Die Namenskonvention der Dumpfiles ist: <dbname>_<date>_<time>.sqlitebkp[.gzip]

          + + Die Datenbank kann mit "set <name> restoreSQLite <Filename>" wiederhergestellt werden.
          Das erstellte Dumpfile kann auf einen FTP-Server übertragen werden. Siehe dazu die Erläuterungen unter "dumpMySQL".

          -

        • +
        • eraseReadings - Löscht alle angelegten Readings im Device, außer dem Reading "state" und Readings, die in der Ausnahmeliste definiert mit Attribut "readingPreventFromDel" enthalten sind. @@ -15244,31 +15298,31 @@ sub bdump { das Exportfile geschrieben. Dadurch wird die Hauptspeicherverwendung optimiert wenn sehr große Datenmengen exportiert werden sollen und vermeidet den "died prematurely" Abbruchfehler.

          - Die für diese Funktion relevanten Attribute sind:

          - + Die für diese Funktion relevanten Attribute sind:

          +
            - + - +
            aggregation : Festlegung der Selektionspaketierung
            device : einschließen oder ausschließen von Datensätzen die <device> enthalten
            reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
            reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
            executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor dem Export ausführen
            executeAfterProc : FHEM Kommando (oder Perl-Routine) nach dem Export ausführen
            expimpfile : der Name des Exportfiles
            expimpfile : der Name des Exportfiles
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
            -
          - +
        +

      • fetchrows [history|current] - liefert alle Tabelleneinträge (default: history) - in den gegebenen Zeitgrenzen bzw. Selektionsbedingungen durch die Attribute + in den gegebenen Zeitgrenzen bzw. Selektionsbedingungen durch die Attribute "device" und "reading". Eine evtl. gesetzte Aggregation wird dabei nicht berücksichtigt.
        - Die Leserichtung in der Datenbank kann durch das Attribut - "fetchRoute" bestimmt werden.

        + Die Leserichtung in der Datenbank kann durch das Attribut + "fetchRoute" bestimmt werden.

        Jedes Ergebnisreading setzt sich aus dem Timestring des Datensatzes, einem Dubletten-Index, dem Device und dem Reading zusammen. @@ -15305,7 +15359,7 @@ sub bdump { Zur besseren Übersicht sind die zur Steuerung von fetchrows relevanten Attribute hier noch einmal dargestellt:

        -
          +
            @@ -15317,26 +15371,26 @@ sub bdump {
            device : einschließen oder ausschließen von Datensätzen die <device> enthalten
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            valueFilter : filtert die anzuzeigenden Datensätze mit einem regulären Ausdruck (Datenbank spezifischer REGEXP). Der REGEXP wird auf Werte des Datenbankfeldes 'VALUE' angewendet.
            -
          -
          -
          +
        +
        +
        - Hinweis:
        + 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.

        -

      • + 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.

        +
      • index <Option> - - Listet die in der Datenbank vorhandenen Indexe auf bzw. legt die benötigten Indexe + - Listet die in der Datenbank vorhandenen Indexe auf bzw. legt die benötigten Indexe an. Ist ein Index bereits angelegt, wird er erneuert (gelöscht und erneut angelegt)

        - Die möglichen Optionen sind:

        + Die möglichen Optionen sind:

        -
          +
            @@ -15345,23 +15399,23 @@ sub bdump {
            list_all : listet die vorhandenen Indexe auf
            recreate_Report_Idx : erstellt oder erneuert (falls vorhanden) den Index Report_Idx in Tabelle history (Index für DbRep)
            drop_Report_Idx : löscht den Index Report_Idx in Tabelle history
            -
          -
          +
        +
        Die für diese Funktion relevanten Attribute sind:

        -
          +
            useAdminCredentials : benutzt einen privilegierten User für die Operation
            -
          -
          +
        +
        Hinweis:
        Der verwendete Datenbank-Nutzer benötigt das ALTER, CREATE und INDEX Privileg.
        -

      • +
      • 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.

        @@ -15374,14 +15428,14 @@ sub bdump { Beispiel: 2016-08-01,23:00:09,TestValue,TestUnit
        # Es sind KEINE Leerzeichen im Feldwert erlaubt !

        - - Hinweis:
        + + 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 ! + 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 [<File>] @@ -15403,41 +15457,41 @@ sub bdump { "2016-09-25 08:53:56","STP_5000","SMAUTILS","etotal: 11859.573","etotal","11859.573",""

      - Die für diese Funktion relevanten Attribute sind:

      -
        + Die für diese Funktion relevanten Attribute sind:

        +
          - + - +
          executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor dem Import ausführen
          executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor dem Import ausführen
          executeAfterProc : FHEM Kommando (oder Perl-Routine) nach dem Import ausführen
          expimpfile : der Name des Importfiles
          expimpfile : der Name des Importfiles
          -
        +


  • maxValue [display | writeToDB | deleteOther] - berechnet den Maximalwert des Datenbankfelds "VALUE" in den Zeitgrenzen - (Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan" etc. + (Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan" etc. Es muss das auszuwertende Reading über das Attribut reading - angegeben sein. + angegeben sein. Die Auswertung enthält den Zeitstempel des ermittelten Maximumwertes innerhalb der - Aggregation bzw. Zeitgrenzen. + Aggregation bzw. Zeitgrenzen. Im Reading wird der Zeitstempel des letzten Auftretens vom Maximalwert ausgegeben, - falls dieser Wert im Intervall mehrfach erreicht wird.

    + 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, - wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. + wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. Der Präfix setzt sich aus der Bildungsfunktion und der Aggregation zusammen.
    Der Timestamp des neuen Readings in der Datenbank wird von der eingestellten Aggregationsperiode abgeleitet. Das Feld "EVENT" wird mit "calculated" gefüllt.

    - - Wird die Option deleteOther verwendet, werden alle Datensätze außer dem Datensatz mit dem - ermittelten Maximalwert aus der Datenbank innerhalb der definierten Grenzen gelöscht.

    + + Wird die Option deleteOther verwendet, werden alle Datensätze außer dem Datensatz mit dem + ermittelten Maximalwert aus der Datenbank innerhalb der definierten Grenzen gelöscht.

      Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
      @@ -15448,46 +15502,46 @@ sub bdump { Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

      -
        +
          - + - + - - + + -
          aggregation : Auswahl einer Aggregationsperiode
          aggregation : Auswahl einer Aggregationsperiode
          device : einschließen oder ausschließen von Datensätzen die <device> enthalten
          executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
          executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
          executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
          reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
          readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
          time.* : eine Reihe von Attributen zur Zeitabgrenzung
          readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
          time.* : eine Reihe von Attributen zur Zeitabgrenzung
          valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
          -
        -
        + +
      +

    • minValue [display | writeToDB | deleteOther] - berechnet den Minimalwert des Datenbankfelds "VALUE" in den Zeitgrenzen - (Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan" etc. + (Attribute) "timestamp_begin", "timestamp_end" bzw. "timeDiffToNow / timeOlderThan" etc. Es muss das auszuwertende Reading über das Attribut reading - angegeben sein. + angegeben sein. Die Auswertung enthält den Zeitstempel des ermittelten Minimumwertes innerhalb der - Aggregation bzw. Zeitgrenzen. + Aggregation bzw. Zeitgrenzen. Im Reading wird der Zeitstempel des ersten Auftretens vom Minimalwert ausgegeben - falls dieser Wert im Intervall mehrfach erreicht wird.

      + 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, - wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. + wobei der originale Readingname durch das Attribut readingNameMap ersetzt werden kann. 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. Das Feld "EVENT" wird mit "calculated" gefüllt.

      - - Wird die Option deleteOther verwendet, werden alle Datensätze außer dem Datensatz mit dem - ermittelten Maximalwert aus der Datenbank innerhalb der definierten Grenzen gelöscht.

      + + Wird die Option deleteOther verwendet, werden alle Datensätze außer dem Datensatz mit dem + ermittelten Maximalwert aus der Datenbank innerhalb der definierten Grenzen gelöscht.

        Beispiel neuer Readingname gebildet aus dem Originalreading "totalpac":
        @@ -15498,40 +15552,40 @@ sub bdump { Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

        -
          +
            - + - + - - + + -
            aggregation : Auswahl einer Aggregationsperiode
            aggregation : Auswahl einer Aggregationsperiode
            device : einschließen oder ausschließen von Datensätzen die <device> enthalten
            executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
            executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
            executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
            reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
            readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
            time.* : eine Reihe von Attributen zur Zeitabgrenzung
            valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
            -
          -
          + +
        +

        - -
      • optimizeTables - optimiert die Tabellen in der angeschlossenen Datenbank (MySQL).
        - Vor und nach der Optimierung kann ein FHEM-Kommando ausgeführt werden. + +
      • 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:
          + +
            + 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 <[Device:]alterReadingname>,<neuerReadingname>
          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.
          + gesetzte Zeitgrenzen oder Beschränkungen durch die Attribute + Device bzw. Reading werden nicht berücksichtigt.
          Optional kann eine Device angegeben werden. In diesem Fall werden nur die alten Readings dieses Devices in den neuen Readingnamen umgesetzt.

          @@ -15548,18 +15602,18 @@ sub bdump { "reading_not_renamed" ausgegeben.
          Entsprechende Einträge erfolgen auch im Logfile mit verbose=3.

          - - Hinweis:
          + + 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).


        • reduceLog [<no>[:<nn>]] [average[=day]] [EXCLUDE=device1:reading1,device2:reading2,...] [INCLUDE=device:reading]
          Reduziert historische Datensätze.

          - - Arbeitsweise ohne Optionsangabe

          - - Sind keine Optionen angegeben, werden die Daten innerhalb der durch die time.*-Attribute bestimmten + + Arbeitsweise ohne Optionsangabe

          + + Sind keine Optionen angegeben, werden die Daten innerhalb der durch die time.*-Attribute bestimmten Zeitgrenzen auf einen Eintrag (den ersten) pro Stunde je Device & Reading reduziert. Es muss mindestens eines der time.*-Attribute gesetzt sein (siehe Tabelle unten). Die jeweils fehlende Zeitabgrenzung wird in diesem Fall durch das Modul errechnet. @@ -15569,13 +15623,13 @@ sub bdump { bzw. ausgeschlossen werden. Beide Eingrenzungen reduzieren die selektierten Daten und verringern den Ressourcenbedarf. Das Reading "reduceLogState" enthält das Ausführungsergebnis des letzten reduceLog-Befehls.

          - - Unter Berücksichtigung des oben genannten sind für diese Funktion folgende Attribute relevant:

          -
            + Unter Berücksichtigung des oben genannten sind für diese Funktion folgende Attribute relevant:

            + +
              - + @@ -15585,9 +15639,9 @@ sub bdump {
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor dem Export ausführen
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor dem Export ausführen
              executeAfterProc : FHEM Kommando (oder Perl-Routine) nach dem Export ausführen
              device : einschließen oder ausschließen von Datensätzen die <device> enthalten
              reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
              timestamp_begin : es werden Datenbankeinträge neuer als dieses Attribut reduziert
              valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
              -
            +

          - + Beispiele:

            attr <name> timeOlderThan = d:200
            @@ -15618,29 +15672,29 @@ sub bdump { # Datensätze die älter als 5 und neuer als 10 Tage sind und DEVICE "Luftdaten_remote" enthalten, werden bereinigt. Numerische Werte einer Stunde werden auf einen Mittelwert reduziert

            -
          -
          - - Arbeitsweise mit Optionsangabe

          - - Es werden Datensätze berücksichtigt die älter sind als <no> Tage und (optional) neuer sind als - <nn> Tage. +
        +
        + + Arbeitsweise mit Optionsangabe

        + + Es werden Datensätze berücksichtigt die älter sind als <no> Tage und (optional) neuer sind als + <nn> Tage. Durch die Angabe von average wird nicht nur die Datenbank bereinigt, sondern alle numerischen Werte einer Stunde werden auf einen einzigen Mittelwert reduziert. Mit der Option average=day werden alle numerischen Werte eines Tages auf einen einzigen Mittelwert reduziert (impliziert 'average').

        Die Zusätze "EXCLUDE" bzw. "INCLUDE" können ergänzt werden um device/reading Kombinationen von reduceLog auszuschließen - bzw. einzuschließen. Diese Angabe wird als Regex ausgewertet und überschreibt die Einstellung der Attribute "device" - und "reading", die in diesem Fall nicht beachtet werden.

        + bzw. einzuschließen. Diese Angabe wird als Regex ausgewertet und überschreibt die Einstellung der Attribute "device" + und "reading", die in diesem Fall nicht beachtet werden.

        - Hinweis:
        + 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).
        Weiterhin wird dringend empfohlen den standard INDEX 'Search_Idx' in der Tabelle 'history' anzulegen !
        - Die Abarbeitung dieses Befehls dauert unter Umständen (ohne INDEX) extrem lange.

        + Die Abarbeitung dieses Befehls dauert unter Umständen (ohne INDEX) extrem lange.


      • repairSQLite - repariert eine korrupte SQLite-Datenbank.
        @@ -15649,7 +15703,7 @@ sub bdump { Wird dieses Kommando gestartet, wird das angeschlossene DbLog-Device zunächst automatisch für 10 Stunden (36000 Sekunden) von der Datenbank getrennt (Trennungszeit). Nach Abschluss der Reparatur erfolgt wieder eine sofortige Neuverbindung zur reparierten Datenbank.
        - Dem Befehl kann eine abweichende Trennungszeit (in Sekunden) als Argument angegeben werden.
        + Dem Befehl kann eine abweichende Trennungszeit (in Sekunden) als Argument angegeben werden.
        Die korrupte Datenbank wird als <database>.corrupt im gleichen Verzeichnis gespeichert.

          @@ -15659,53 +15713,53 @@ sub bdump { set <name> repairSQLite 600
          # Die Datenbank wird repariert, Trennungszeit beträgt 10 Minuten

          - - Hinweis:
          + + Hinweis:
          Es ist nicht garantiert, dass die Reparatur erfolgreich verläuft und keine Daten verloren gehen. Je nach Schwere der Korruption kann Datenverlust auftreten oder die Reparatur scheitern, auch wenn kein Fehler im Ablauf signalisiert wird. Ein Backup der Datenbank sollte unbedingt vorhanden sein !


          -
        +
    • restoreMySQL <File> - stellt die Datenbank aus einem serverSide- oder clientSide-Dump wieder her.
      - Die Funktion stellt über eine Drop-Down Liste eine Dateiauswahl für den Restore zur Verfügung.

      - - Verwendung eines serverSide-Dumps
      + Die Funktion stellt über eine Drop-Down Liste eine Dateiauswahl für den Restore zur Verfügung.

      + + Verwendung eines serverSide-Dumps
      Der verwendete Datenbankuser benötigt das FILE Privileg (siehe Wiki).
      - Es wird der Inhalt der history-Tabelle aus einem serverSide-Dump wiederhergestellt. + Es wird der Inhalt der history-Tabelle aus einem serverSide-Dump wiederhergestellt. 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[.gzip]" und deren Name mit der - verbundenen Datenbank beginnt (siehe Internal DATABASE), aufgelistet. -

      - - Verwendung eines clientSide-Dumps
      - Es werden alle Tabellen und eventuell vorhandenen Views wiederhergestellt. - Das Verzeichnis, in dem sich die Dump-Files befinden, ist im Attribut dumpDirLocal dem - DbRep-Device bekannt zu machen.
      - Es werden alle Files mit der Endung "sql[.gzip]" und deren Name mit der - verbundenen Datenbank beginnt (siehe Internal DATABASE), aufgelistet.
      - Die Geschwindigkeit des Restores ist abhängig von der Servervariable "max_allowed_packet". Durch Veränderung - dieser Variable im File my.cnf kann die Geschwindigkeit angepasst werden. Auf genügend verfügbare Ressourcen (insbesondere - RAM) ist dabei zu achten.

      + und im Attribut dumpDirLocal dem DbRep-Device bekannt zu machen.
      + Es werden alle Files mit der Endung "csv[.gzip]" und deren Name mit der + verbundenen Datenbank beginnt (siehe Internal DATABASE), aufgelistet. +

      + + Verwendung eines clientSide-Dumps
      + Es werden alle Tabellen und eventuell vorhandenen Views wiederhergestellt. + Das Verzeichnis, in dem sich die Dump-Files befinden, ist im Attribut dumpDirLocal dem + DbRep-Device bekannt zu machen.
      + Es werden alle Files mit der Endung "sql[.gzip]" und deren Name mit der + verbundenen Datenbank beginnt (siehe Internal DATABASE), aufgelistet.
      + Die Geschwindigkeit des Restores ist abhängig von der Servervariable "max_allowed_packet". Durch Veränderung + dieser Variable im File my.cnf kann die Geschwindigkeit angepasst werden. Auf genügend verfügbare Ressourcen (insbesondere + RAM) ist dabei zu achten.

      Der Datenbankuser benötigt Rechte zum Tabellenmanagement, z.B.:
      CREATE, ALTER, INDEX, DROP, SHOW VIEW, CREATE VIEW -

      -

    • +

      +
    • restoreSQLite <File>.sqlitebkp[.gzip] - 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[.gzip]" und deren Name mit dem Namen der - verbundenen Datenbank beginnt, aufgelistet .

      -

    • - + verbundenen Datenbank beginnt, aufgelistet .

      +
      +
    • sqlCmd - führt ein beliebiges benutzerspezifisches Kommando aus.
      Enthält dieses Kommando eine Delete-Operation, muss zur Sicherheit das Attribut - allowDeletion gesetzt sein.
      + allowDeletion gesetzt sein.
      Bei der Ausführung dieses Kommandos werden keine Einschränkungen durch gesetzte Attribute "device", "reading", "time.*" bzw. "aggregation" berücksichtigt.
      Dieses Kommando akzeptiert ebenfalls das Setzen von SQL Session Variablen wie z.B. @@ -15714,19 +15768,19 @@ sub bdump { Soll die Session Variable oder das PRAGMA vor jeder Ausführung eines SQL Statements gesetzt werden, kann dafür das Attribut sqlCmdVars verwendet werden.
      - 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.

      - - Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des - originalen Timestamps zu verhindern.

      - -
        + 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.

        + + Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des + originalen Timestamps zu verhindern.

        + +
          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 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
            • @@ -15758,11 +15812,11 @@ sub bdump {
            • set <name> sqlCmd PRAGMA temp_store=MEMORY; PRAGMA synchronous=FULL; PRAGMA journal_mode=WAL; PRAGMA cache_size=4000; select count(*) from history;
            • set <name> sqlCmd PRAGMA temp_store=FILE; PRAGMA temp_store_directory = '/opt/fhem/'; VACUUM;
            -
            - - 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.

            +
            + + 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.

            Das Modul stellt optional eine Kommando-Historie zur Verfügung sobald ein SQL-Kommando erfolgreich ausgeführt wurde. @@ -15772,10 +15826,10 @@ sub bdump { Zur besseren Übersicht sind die zur Steuerung von sqlCmd relevanten Attribute hier noch einmal dargestellt:

            -
              +
                - + @@ -15784,14 +15838,14 @@ sub bdump {
                executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
                executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
                executeAfterProc : FHEM Kommando (oder Perl-Routine) nach der Operation ausführen
                allowDeletion : aktiviert Löschmöglichkeit
                sqlResultFormat : legt die Darstellung des Kommandoergebnisses fest
                sqlCmdVars : setzt SQL Session Variablen oder PRAGMA vor jeder Ausführung des SQL-Statements
                useAdminCredentials : benutzt einen privilegierten User für die Operation
                -
              -
              +
            +
            - Hinweis:
            + 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.

            + 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.


          @@ -15803,83 +15857,83 @@ sub bdump { Zur besseren Übersicht sind die zur Steuerung dieser Funktion von relevanten Attribute hier noch einmal zusammenstellt:

          -
            +
              - +
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
              executeAfterProc : FHEM Kommando (oder Perl-Routine) nach der Operation ausführen
              allowDeletion : aktiviert Löschmöglichkeit
              sqlResultFormat : legt die Darstellung des Kommandoergebnis fest
              sqlResultFieldSep : Auswahl Feldtrenner im Ergebnis
              -
            -
            -
            +
          +
          +
          -
          +
        • sqlSpecial - Die Funktion bietet eine Drop-Downliste mit einer Auswahl vorbereiter Auswertungen an.
          - Das Ergebnis des Statements wird im Reading "SqlResult" dargestellt. - Die Ergebnis-Formatierung kann durch das Attribut sqlResultFormat + 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.

          - - Es sind die folgenden vordefinierte Auswertungen auswählbar:

          -
            + + Es sind die folgenden vordefinierte Auswertungen auswählbar:

            +
              - - +
              50mostFreqLogsLast2days : ermittelt die 50 am häufigsten vorkommenden Loggingeinträge der letzten 2 Tage
              allDevCount : alle in der Datenbank vorkommenden Devices und deren Anzahl
              allDevReadCount : alle in der Datenbank vorkommenden Device/Reading-Kombinationen und deren Anzahl
              recentReadingsOfDevice : ermittelt die neuesten in der Datenbank vorhandenen Datensätze eines Devices. Das auszuwertende - Device muß im Attribut device definiert sein. - Es kann nur ein auszuwertendes Device angegeben werden.
              readingsDifferenceByTimeDelta : ermittelt die Wertedifferenz aufeinanderfolgender Datensätze eines Readings. Das auszuwertende - Device und Reading muß im Attribut device bzw. reading definiert sein. - Es kann nur ein auszuwertendes Device und nur ein auszuwertendes Reading angegeben werden. +
              recentReadingsOfDevice : ermittelt die neuesten in der Datenbank vorhandenen Datensätze eines Devices. Das auszuwertende + Device muß im Attribut device definiert sein. + Es kann nur ein auszuwertendes Device angegeben werden.
              readingsDifferenceByTimeDelta : ermittelt die Wertedifferenz aufeinanderfolgender Datensätze eines Readings. Das auszuwertende + Device und Reading muß im Attribut device bzw. reading definiert sein. + Es kann nur ein auszuwertendes Device und nur ein auszuwertendes Reading angegeben werden. Die Zeitgrenzen der Auswertung werden durch die time.*-Attribute festgelegt.
              -
            -
            +
          +
          - Die für diese Funktion relevanten Attribute sind:

          -
            + Die für diese Funktion relevanten Attribute sind:

            +
              - +
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
              executeBeforeProc : FHEM Kommando (oder Perl-Routine) vor der Operation ausführen
              executeAfterProc : FHEM Kommando (oder Perl-Routine) nach der Operation ausführen
              sqlResultFormat : Optionen der Ergebnisformatierung
              sqlResultFieldSep : Auswahl des Trennzeichens zwischen Ergebnisfeldern
              -
            - +
          +


        • - +
        • sumValue [display | writeToDB | writeToDBSingle | writeToDBInTime] - Berechnet die Summenwerte des Datenbankfelds "VALUE" in den Zeitgrenzen - der möglichen time.*-Attribute.

          + der möglichen time.*-Attribute.

          Es muss das auszuwertende Reading im Attribut reading - angegeben sein. Diese Funktion ist sinnvoll wenn fortlaufend Wertedifferenzen eines - Readings in die Datenbank geschrieben werden.

          + 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 den Optionen writeToDB, writeToDBSingle bzw. writeToDBInTime werden die Berechnungsergebnisse mit einem neuen Readingnamen in der Datenbank gespeichert.

          -
            +
              - + -
              writeToDB : schreibt jeweils einen Wert mit den Zeitstempeln XX:XX:01 und XX:XX:59 innerhalb der jeweiligen Auswertungsperiode
              writeToDB : schreibt jeweils einen Wert mit den Zeitstempeln XX:XX:01 und XX:XX:59 innerhalb der jeweiligen Auswertungsperiode
              writeToDBSingle : schreibt nur einen Wert mit dem Zeitstempel XX:XX:59 am Ende einer Auswertungsperiode
              writeToDBInTime : schreibt jeweils einen Wert am Anfang und am Ende der Zeitgrenzen einer Auswertungsperiode
              -
            -
            + +
          +
          Der neue Readingname wird aus einem Präfix und dem originalen Readingnamen gebildet, - wobei der originale Readingname durch das Attribut "readingNameMap" ersetzt werden kann. + wobei der originale Readingname durch das Attribut "readingNameMap" ersetzt werden kann. 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. @@ -15894,20 +15948,20 @@ sub bdump { Zusammengefasst sind die zur Steuerung dieser Funktion relevanten Attribute:

          -
            +
              - + - + - - + + -
              aggregation : Auswahl einer Aggregationsperiode
              aggregation : Auswahl einer Aggregationsperiode
              device : einschließen oder ausschließen von Datensätzen die <device> enthalten
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
              executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
              reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
              readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
              time.* : eine Reihe von Attributen zur Zeitabgrenzung
              readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
              time.* : eine Reihe von Attributen zur Zeitabgrenzung
              valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
              -
            -
            + +
          +

        • @@ -15922,46 +15976,46 @@ sub bdump { Hat das Attribut "aggregation" den Wert "no" oder "month", werden die Datensätze automatisch in Tageszeitscheiben zur Standby-Datenbank übertragen. Quell- und Standby-Datenbank können unterschiedlichen Typs sein. -

          +

          Die zur Steuerung der syncStandby Funktion relevanten Attribute sind:

          -
            +
              - +
              aggregation : Einstellung der Zeitscheiben zur Übertragung (hour,day,week)
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
              executeBeforeProc : ausführen FHEM Kommando (oder Perl-Routine) vor Start Operation
              executeAfterProc : ausführen FHEM Kommando (oder Perl-Routine) nach Ende Operation
              device : einschließen oder ausschließen von Datensätzen die <device> enthalten
              reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
              time.* : Attribute zur Zeitabgrenzung der zu übertragenden Datensätze.
              valueFilter : ein zusätzliches REGEXP um die Datenselektion zu steuern. Der REGEXP wird auf das Datenbankfeld 'VALUE' angewendet.
              -
            -
            +
          +

          - -
        • tableCurrentFillup - Die current-Tabelle wird mit einem Extrakt der history-Tabelle aufgefüllt. - Die Attribute zur Zeiteinschränkung bzw. device, reading werden ausgewertet. + +
        • 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. + +
        • 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:
            + +
              + 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.

              - +

            - +
        @@ -15999,27 +16053,34 @@ sub bdump {
            +
          • blockinginfo - Listet die aktuell systemweit laufenden Hintergrundprozesse (BlockingCalls) mit ihren Informationen auf. - Zu lange Zeichenketten (z.B. Argumente) werden gekürzt ausgeschrieben. + 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.
            + 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 - -

              -
            - -
          • dbValue <SQL-Statement> - - Führt das angegebene SQL-Statement blockierend aus. Diese Funktion ist durch ihre Arbeitsweise +
              + Beispiel
              + get <name> dbstatus
              + attr <name> showStatus %uptime%,%qcache%
              + # Es werden nur Readings erzeugt die im Namen "uptime" und "qcache" enthaltenen +
            +
          • +

            + + +
          • sqlCmdBlocking <SQL-Statement> - + Führt das angegebene SQL-Statement blockierend mit einem Standardtimeout von 10 Sekunden aus. + Der Timeout kann mit dem Attribut timeout verändert werden. +
            + + Diese Funktion ist durch ihre Arbeitsweise speziell für den Einsatz in benutzerspezifischen Scripten geeignet.
            Die Eingabe akzeptiert Mehrzeiler und gibt ebenso mehrzeilige Ergebisse zurück. Dieses Kommando akzeptiert ebenfalls das Setzen von SQL Session Variablen wie z.B. @@ -16029,54 +16090,56 @@ sub bdump { werden mit Newline ("\n") separiert.
            Diese Funktion setzt/aktualisiert nur Statusreadings, die Funktion im Attribut "userExitFn" wird nicht aufgerufen. -
            - -
              - Bespiele zur Nutzung im FHEMWEB
              - {fhem("get <name> dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device")}
              - get <name> dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device
              - {CommandGet(undef,"Rep.LogDB1 dbValue select device,count(*) from history where timestamp > '2018-04-01' group by device")}
              -
            -

            - Erstellt man eine kleine Routine in 99_myUtils, wie z.B.: + +
              + Beispiele:
              + { fhem("get <name> sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device") }
              + { CommandGet(undef,"Rep.LogDB1 sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device") }
              + get <name> sqlCmdBlocking select device,count(*) from history where timestamp > '2018-04-01' group by device
              +
            +
          • +

            + + Erstellt man eine kleine Routine in 99_myUtils, wie z.B.:
            -sub dbval($$) {
            -  my ($name,$cmd) = @_;
            -  my $ret = CommandGet(undef,"$name dbValue $cmd"); 
            -return $ret;
            +sub dbval {
            +  my $name = shift;
            +  my $cmd  = shift;
            +  my $ret  = CommandGet(undef,"$name sqlCmdBlocking $cmd"); 
            +  return $ret;
             }                            
                                         
            - kann dbValue vereinfacht verwendet werden mit Aufrufen wie: + kann sqlCmdBlocking vereinfacht verwendet werden mit Aufrufen wie:

            -
              - Bespiele
              - {dbval("<name>","select count(*) from history")}
              - oder
              - $ret = dbval("<name>","select count(*) from history");
              -
            +
              + Beispiele:
              + { dbval("<name>","select count(*) from history") }
              + oder
              + $ret = dbval("<name>","select count(*) from history");
              +
            - -

            +

            - +
          • 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.
            + 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 - -

              -
            +
              + Beispiel
              + get <name> dbvars
              + attr <name> showVariables %version%,%query_cache%
              + # Es werden nur Readings erzeugt die im Namen "version" und "query_cache" enthalten +
            +
          • +

            +
          • minTimestamp - Ermittelt den Zeitstempel des ältesten Datensatzes in der Datenbank (wird implizit beim Start von FHEM ausgeführt). Der Zeitstempel wird als Selektionsbeginn verwendet wenn kein Zeitattribut den Selektionsbeginn @@ -16084,56 +16147,70 @@ return $ret;


          • +
          • 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.
            + 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.


          • - + +
          • storedCredentials - Listet die im Device gespeicherten User / Passworte für den Datenbankzugriff auf.
            (nur gültig bei Datenbanktyp MYSQL)


          • - + +
          • 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 - -

              -
            + hier zu finden.

            +
              + Beispiel
              + 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. + 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.
            + Readings sind hier zu finden.

            -
              - Bespiel
              - get <name> tableinfo
              - attr <name> showTableInfo current,history
              - # Es werden nur Information der Tabellen "current" und "history" angezeigt - -

              -
            +
              + Beispiel
              + get <name> tableinfo
              + attr <name> showTableInfo current,history
              + # Es werden nur Information der Tabellen "current" und "history" angezeigt +
            +
          • +

            +
          • versionNotes [hints | rel | <key>] - Zeigt Release Informationen und/oder Hinweise zum Modul an. Es sind nur Release Informationen mit Bedeutung für den Modulnutzer enthalten.
            Sind keine Optionen angegben, werden sowohl Release Informationen als auch Hinweise angezeigt. - "rel" zeigt nur Release Informationen und "hints" nur Hinweise an. Mit der <key>-Angabe - wird der Hinweis mit der angegebenen Nummer angezeigt. +

            + +
              + + + + + +
              rel : zeigt nur Release Informationen
              hints : zeigt nur Hinweise an
              <key> : es wird der Hinweis mit der angegebenen Nummer angezeigt
              +
            +

          • @@ -16188,8 +16265,8 @@ return $ret; In der Angabe <source-reading> sind Wildcards (.*) erlaubt.

              - Beispiel: -
              +                                Beispiel:
              +                                
               {
                 ".*"        => "Dum.Rep.All",             
                 ".*AVGAM.*" => "Dum.Rep     => average",  
              @@ -16210,18 +16287,18 @@ return $ret;
               
                                               Zur Zeit sind folgende Varianten implementiert: 

              -
                +
                  - - -
                  avgArithmeticMean : es wird der arithmetische Mittelwert berechnet (default)
                  avgDailyMeanGWS : berechnet die Tagesmitteltemperatur entsprechend den +
                  avgDailyMeanGWS : berechnet die Tagesmitteltemperatur entsprechend den Vorschriften des deutschen Wetterdienstes (siehe "get <name> versionNotes 2").
                  Diese Variante verwendet automatisch die Aggregation "day".
                  avgTimeWeightMean : berechnet den zeitgewichteten Mittelwert
                  -
                + avgTimeWeightMean : berechnet den zeitgewichteten Mittelwert + +

              @@ -16233,53 +16310,53 @@ return $ret;
            • device - Abgrenzung der DB-Selektionen auf ein bestimmtes oder mehrere Devices.
              Es können Geräte-Spezifikationen (devspec) angegeben werden.
              - In diesem Fall werden die Devicenamen vor der Selektion aus der Geräte-Spezifikationen und den aktuell in FHEM - vorhandenen Devices aufgelöst.
              + In diesem Fall werden die Devicenamen vor der Selektion aus der Geräte-Spezifikationen und den aktuell in FHEM + vorhandenen Devices aufgelöst.
              Wird dem Device bzw. der Device-Liste oder Geräte-Spezifikation ein "EXCLUDE=" vorangestellt, werden diese Devices von der Selektion ausgeschlossen.

                - 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
                - attr <name> device TYPE=SSCam EXCLUDE=SDS1_SVS
                - attr <name> device TYPE=SSCam,TYPE=ESPEasy EXCLUDE=SDS1_SVS
                + 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
                + attr <name> device TYPE=SSCam EXCLUDE=SDS1_SVS
                + attr <name> device TYPE=SSCam,TYPE=ESPEasy EXCLUDE=SDS1_SVS
                attr <name> device EXCLUDE=SDS1_SVS
                attr <name> device EXCLUDE=TYPE=SSCam
                -
              +

            Falls weitere Informationen zu Geräte-Spezifikationen benötigt werden, bitte "get <name> versionNotes 3" ausführen. -

            +

          • 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. -

            + 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:

              - + 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

              - + 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. + Differenzwert.
              + # Es ist zu entscheiden ob der Datensatz gelöscht, ignoriert, oder das Attribut diffAccept angepasst werden sollte.

          • - +
          • disable - deaktiviert das Modul

          • @@ -16291,28 +16368,28 @@ return $ret;
          • dumpDirLocal - Zielverzeichnis für die Erstellung von Dumps mit "dumpMySQL clientSide" oder "dumpSQLite". default: "{global}{modpath}/log/" auf dem FHEM-Server.
            - Ebenfalls werden in diesem Verzeichnis alte Backup-Files durch die interne Versionsverwaltung - gesucht und gelöscht wenn die gefundene Anzahl den Attributwert "dumpFilesKeep" - überschreitet. Das Attribut dient auch dazu ein lokal gemountetes Verzeichnis "dumpDirRemote" (bei dumpMySQL serverSide) - DbRep bekannt zu machen.

          • + Ebenfalls werden in diesem Verzeichnis alte Backup-Files durch die interne Versionsverwaltung + gesucht und gelöscht wenn die gefundene Anzahl den Attributwert "dumpFilesKeep" + überschreitet. Das Attribut dient auch dazu ein lokal gemountetes Verzeichnis "dumpDirRemote" (bei dumpMySQL serverSide) + 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 das Dump 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 angegebene Anzahl Dumpfiles im Dumpdir belassen (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.

          • + Attribut "archivesort" wird berücksichtigt.
          • executeAfterProc - Es kann ein FHEM-Kommando oder eine Perl-Funktion angegeben werden welche nach der @@ -16320,12 +16397,12 @@ return $ret; Funktionen sind in {} einzuschließen.

              - Beispiel:

              - attr <name> executeAfterProc set og_gz_westfenster off;
              - attr <name> executeAfterProc {adump ("<name>")}

              - - # "adump" ist eine in 99_myUtils definierte Funktion.
              - + Beispiel:

              + attr <name> executeAfterProc set og_gz_westfenster off;
              + attr <name> executeAfterProc {adump ("<name>")}

              + + # "adump" ist eine in 99_myUtils definierte Funktion.
              +
               sub adump {
                   my ($name) = @_;
              @@ -16338,19 +16415,19 @@ sub adump {
               
          • - - + +
          • executeBeforeProc - Es kann ein FHEM-Kommando oder eine Perl-Funktion angegeben werden welche vor der Befehlsabarbeitung ausgeführt werden soll.
            Funktionen sind in {} einzuschließen.

              - Beispiel:

              - attr <name> executeBeforeProc set og_gz_westfenster on;
              - attr <name> executeBeforeProc {bdump ("<name>")}

              - - # "bdump" ist eine in 99_myUtils definierte Funktion.
              - + Beispiel:

              + attr <name> executeBeforeProc set og_gz_westfenster on;
              + attr <name> executeBeforeProc {bdump ("<name>")}

              + + # "bdump" ist eine in 99_myUtils definierte Funktion.
              +
               sub bdump {
                   my ($name) = @_;
              @@ -16376,7 +16453,7 @@ sub bdump {
                                               sein (siehe auch strftime Beschreibung). 

              -
                +
                  @@ -16391,19 +16468,19 @@ sub bdump {
                  %L : wird ersetzt durch den Wert des global logdir Attributs
                  %U : Wochennummer des Jahres, wobei Wochenbeginn = Sonntag (00..53)
                  %W : Wochennummer des Jahres, wobei Wochenbeginn = Montag (00..53)
                  -
                +

                - Beispiele:
                - attr <name> expimpfile /sds1/backup/exptest_%TSB.csv
                + Beispiele:
                + attr <name> expimpfile /sds1/backup/exptest_%TSB.csv
                attr <name> expimpfile /sds1/backup/exptest_%Y-%m-%d.csv
                -
              +

            Zur POSIX Wildcardverwendung siehe auch die Erläuterungen zu Filelog. -

            +

          • @@ -16428,9 +16505,9 @@ sub bdump { 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.
            -
          - -

          +
        + +

      • fetchValueFn - Der angezeigte Wert des Datenbankfeldes VALUE kann vor der Erstellung des entsprechenden @@ -16439,10 +16516,10 @@ sub bdump { Der Wert des Datenbankfeldes VALUE wird in der Variable $VALUE zur Verfügung gestellt.

          - Beispiel:
          - attr <name> fetchValueFn { $VALUE =~ s/^.*Used:\s(.*)\sMB,.*/$1." MB"/e }
          - - # Von einer langen Ausgabe wird ein spezifisches Zeichenmuster extrahiert und als VALUE + Beispiel:
          + attr <name> fetchValueFn { $VALUE =~ s/^.*Used:\s(.*)\sMB,.*/$1." MB"/e }
          + + # Von einer langen Ausgabe wird ein spezifisches Zeichenmuster extrahiert und als VALUE anstatt der gesamten Zeile im Reading angezeigt.


      • @@ -16450,14 +16527,14 @@ sub bdump {
      • ftpUse - FTP Transfer nach einem Dump wird eingeschaltet (ohne SSL Verschlüsselung). Das erzeugte Datenbank Backupfile wird non-blocking zum angegebenen FTP-Server (Attribut "ftpServer") - übertragen.

      • + übertragen.
        - +
      • ftpUseSSL - FTP Transfer mit SSL Verschlüsselung nach einem Dump wird eingeschaltet. Das erzeugte Datenbank Backupfile wird non-blocking zum angegebenen FTP-Server (Attribut "ftpServer") - übertragen.

      • + übertragen.
        - +
      • ftpUser - User zur Anmeldung am FTP-Server nach einem Dump, default: "anonymous".

      • @@ -16472,7 +16549,7 @@ sub bdump { (ältere) Dumpfiles vorhanden, werden diese gelöscht nachdem ein neuer Dump erfolgreich übertragen wurde.
        - +
      • ftpPassive - setzen wenn passives FTP verwendet werden soll

      • @@ -16490,19 +16567,19 @@ sub bdump {
      • 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.

      • + 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 ! + FHEM falls DbLog nicht im asynchronen Modus (DbLog-Attribut "asyncMode") betrieben wird !
          -
        +

    • @@ -16513,26 +16590,26 @@ sub bdump { Wird dem Reading bzw. der Reading-Liste ein "EXCLUDE=" vorangestellt, werden diese Readings nicht inkludiert.

      - +
        - Beispiele:
        - attr <name> reading etotal
        - attr <name> reading et%
        - attr <name> reading etotal,etoday
        + Beispiele:
        + attr <name> reading etotal
        + attr <name> reading et%
        + attr <name> reading etotal,etoday
        attr <name> reading eto%,Einspeisung EXCLUDE=etoday
        attr <name> reading etotal,etoday,Ein% EXCLUDE=%Wirkleistung
        -
      -

      +
    +

  • - +
  • readingNameMap - ein Teil des erstellten Readingnamens wird mit dem angegebenen String ersetzt.

  • 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.
    @@ -16540,7 +16617,7 @@ sub bdump { Siehe auch Abschnitt DbRep-Agent.

  • - +
  • seqDoubletsVariance <positive Abweichung [negative Abweichung] [EDGE=negative|positive]>
    Akzeptierte Abweichung für das Kommando "set <name> delSeqDoublets".
    Der Wert des Attributs beschreibt die Abweichung bis zu der aufeinanderfolgende numerische @@ -16557,22 +16634,22 @@ sub bdump {

      - Beispiele:
      - attr <name> seqDoubletsVariance 0.0014
      - attr <name> seqDoubletsVariance 1.45
      + Beispiele:
      + attr <name> seqDoubletsVariance 0.0014
      + attr <name> seqDoubletsVariance 1.45
      attr <name> seqDoubletsVariance 3.0 2.0
      attr <name> seqDoubletsVariance 1.5 EDGE=negative
      -
    -

    + +

  • 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.

  • + SQl-Statement, sondern die Summe aller notwendigen SQL-Abfragen innerhalb der jeweiligen + Funktion betrachtet.
    - +
  • showStatus - grenzt die Ergebnismenge des Befehls "get <name> dbstatus" ein. Es können SQL-Wildcard (%) verwendet werden.

    @@ -16584,7 +16661,7 @@ sub bdump {
  • - +
  • showVariables - grenzt die Ergebnismenge des Befehls "get <name> dbvars" ein. Es können SQL-Wildcard (%) verwendet werden.

    @@ -16608,7 +16685,7 @@ sub bdump {
  • - +
  • showTableInfo - grenzt die Ergebnismenge des Befehls "get <name> tableinfo" ein. Es können SQL-Wildcard (%) verwendet werden.

    @@ -16629,9 +16706,9 @@ sub bdump { SQL-Statement

      - Beispiel:
      - attr <name> sqlCmdVars SET @open:=NULL, @closed:=NULL;
      - attr <name> sqlCmdVars PRAGMA temp_store=MEMORY;PRAGMA synchronous=FULL;PRAGMA journal_mode=WAL;
      + Beispiel:
      + attr <name> sqlCmdVars SET @open:=NULL, @closed:=NULL;
      + attr <name> sqlCmdVars PRAGMA temp_store=MEMORY;PRAGMA synchronous=FULL;PRAGMA journal_mode=WAL;


  • @@ -16640,26 +16717,26 @@ sub bdump {
  • sqlResultFieldSep - legt den verwendeten Feldseparator (default: "|") im Ergebnis des Kommandos "set ... sqlCmd" fest.

  • - +
  • sqlResultFormat - legt die Formatierung des Ergebnisses des Kommandos "set <name> 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.

        + SqlResult dargestellt.

        sline - das Ergebnis wird als Singleline im Reading SqlResult dargestellt. Satztrenner ist"]|[".

        table - das Ergebnis wird als Tabelle im Reading - SqlResult dargestellt.

        + 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.

        + 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:
        -
        +        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};
        @@ -16667,22 +16744,22 @@ sub bdump {
                   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);
        +          
        +            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;
                 }
        -  	    
        - +
        +

      @@ -16695,15 +16772,15 @@ sub bdump {

        - Beispiel:

        - attr <name> timeYearPeriod 06-25 06-24

        - - # wertet die Datenbank in den Zeitgrenzen 25. Juni AAAA bis 24. Juni BBBB aus.
        + Beispiel:

        + attr <name> 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 -
      -

      +
    +

  • @@ -16739,7 +16816,7 @@ sub bdump {
  • 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 "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:

      @@ -16768,13 +16845,13 @@ sub bdump { Natürlich sollte man immer darauf achten dass "timestamp_begin" < "timestamp_end" ist.

        - Beispiel:

        - attr <name> timestamp_begin current_year_begin
        - attr <name> timestamp_end current_year_end

        - - # Wertet die Datenbank in den Zeitgrenzen des aktuellen Jahres aus.
        -
      -
      + Beispiel:

      + attr <name> timestamp_begin current_year_begin
      + attr <name> timestamp_end current_year_end

      + + # Wertet die Datenbank in den Zeitgrenzen des aktuellen Jahres aus.
      +
    +
    Hinweis
    @@ -16791,82 +16868,82 @@ sub bdump { der Zusatzangabe "FullDay" der Selektionsbeginn und das Selektionsende auf Beginn / Ende der jeweiligen Selektionstage erweitert werden (wirkt nur wenn eingestellte Zeitdifferenz ist >= 1 Tag).

    - +
      - Eingabeformat Beispiele:
      - attr <name> timeDiffToNow 86400
      + Eingabeformat Beispiele:
      + 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
      + 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
      + attr <name> timeDiffToNow h:2.5
      # die Startzeit wird auf "aktuelle Zeit - 2,5 Stunden" gesetzt
      - attr <name> timeDiffToNow y:1 h:2.5
      + attr <name> timeDiffToNow y:1 h:2.5
      # die Startzeit wird auf "aktuelle Zeit - 1 Jahr und 2,5 Stunden" gesetzt
      - attr <name> timeDiffToNow y:1.5
      + attr <name> timeDiffToNow y:1.5
      # die Startzeit wird auf "aktuelle Zeit - 1,5 Jahre gesetzt
      - attr <name> timeDiffToNow d:8 FullDay
      + attr <name> timeDiffToNow d:8 FullDay
      # die Startzeit wird auf "aktuelle Zeit - 8 Tage gesetzt, der Selektionszeitraum wird auf Beginn / Ende der beteiligten Tage erweitert
      -
    -
    + +
    Sind die Attribute "timeDiffToNow" und "timeOlderThan" gleichzeitig gesetzt, wird der Selektionszeitraum zwischen diesen Zeitpunkten dynamisch kalkuliert.

  • - +
  • 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. Die Timestampermittlung erfolgt - dynamisch zum Ausführungszeitpunkt. Optional kann mit der Zusatzangabe + Zeit> - <timeOlderThan>" berücksichtigt. Die Timestampermittlung erfolgt + dynamisch zum Ausführungszeitpunkt. Optional kann mit der Zusatzangabe "FullDay" der Selektionsbeginn und das Selektionsende auf Beginn / Ende der jeweiligen Selektionstage erweitert werden (wirkt nur wenn eingestellte Zeitdifferenz ist >= 1 Tag).

      - Eingabeformat Beispiele:
      - attr <name> timeOlderThan 86400
      + Eingabeformat Beispiele:
      + attr <name> timeOlderThan 86400
      # das Selektionsende wird auf "aktuelle Zeit - 86400 Sekunden" gesetzt
      - attr <name> timeOlderThan d:2 h:3 m:2 s:10
      - # das Selektionsende wird auf "aktuelle Zeit - 2 Tage 3 Stunden 2 Minuten 10 Sekunden" gesetzt
      - attr <name> timeOlderThan m:600
      + attr <name> timeOlderThan d:2 h:3 m:2 s:10
      + # das Selektionsende wird auf "aktuelle Zeit - 2 Tage 3 Stunden 2 Minuten 10 Sekunden" gesetzt
      + attr <name> timeOlderThan m:600
      # das Selektionsende wird auf "aktuelle Zeit - 600 Minuten" gesetzt
      - attr <name> timeOlderThan h:2.5
      + attr <name> timeOlderThan h:2.5
      # das Selektionsende wird auf "aktuelle Zeit - 2,5 Stunden" gesetzt
      - attr <name> timeOlderThan y:1 h:2.5
      + attr <name> timeOlderThan y:1 h:2.5
      # das Selektionsende wird auf "aktuelle Zeit - 1 Jahr und 2,5 Stunden" gesetzt
      - attr <name> timeOlderThan y:1.5
      + attr <name> timeOlderThan y:1.5
      # das Selektionsende wird auf "aktuelle Zeit - 1,5 Jahre gesetzt
      - attr <name> timeOlderThan d:8 FullDay
      + attr <name> timeOlderThan d:8 FullDay
      # das Selektionsende wird auf "aktuelle Zeit - 8 Tage gesetzt, der Selektionszeitraum wird auf Beginn / Ende der beteiligten Tage erweitert
      -
    -
    + +
    Sind die Attribute "timeDiffToNow" und "timeOlderThan" gleichzeitig gesetzt, wird der Selektionszeitraum zwischen diesen Zeitpunkten dynamisch kalkuliert.

  • - +
  • timeout - das Attribut setzt den Timeout-Wert für die Blocking-Call Routinen in Sekunden (Default: 86400)

  • - +
  • useAdminCredentials - Wenn gesetzt, wird ein zuvor mit "set <Name> adminCredentials" gespeicherter privilegierter User für bestimmte Datenbankoperationen verwendet.
    (nur gültig für Datenbanktyp MYSQL und DbRep-Typ "Client")

  • - +
  • 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_myUtils.pm nach folgendem Muster erstellt:
    + 99_myUtils.pm nach folgendem Muster erstellt:
    -
    +        
             sub UserFunction {
               my ($name,$reading,$value) = @_;
               my $hash = $defs{$name};
    @@ -16876,33 +16953,33 @@ sub bdump {
               ...
             return;
             }
    -  	    
    - - Die Aktivierung der Schnittstelle erfogt durch Setzen des Funktionsnamens im Attribut. - Optional kann ein Reading:Value Regex als Argument angegeben werden. Wird kein Regex - angegeben, werden alle Wertekombinationen als "wahr" gewertet (entspricht .*:.*). -

    - -
      - Beispiel:
      +
    + + Die Aktivierung der Schnittstelle erfogt durch Setzen des Funktionsnamens 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 jedes - Readings im Device. Ist die Prüfung wahr, wird die angegebene Funktion aufgerufen. - Zur Weiterverarbeitung werden der aufgerufenenen Funktion folgende Variablen übergeben:

    + +
    -
      + 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 jedes + Readings im Device. 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
      • - -
      - -
      + +
    +
  • +

    @@ -16939,15 +17016,15 @@ sub bdump { <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".

  • + 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

  • + +
  • sqlCmd - das letzte ausgeführte sqlCmd-Kommando


  • @@ -17006,7 +17083,7 @@ sub bdump {
    - + 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).