diff --git a/fhem/CHANGED b/fhem/CHANGED
index 009e076b7..4f645aa3d 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it.
+ - feature: 93_DbRep: V7.2.0, new attributes "seqDoubletsVariance",
+ "timeYearPeriod", minor fixes
- feature: 98_TRAFFIC: v1.3.3, added alternatives, various improvements
- feature: 70_BRAVIA: new command "application" to start an application on TV
- feature: FHEMWEB: add structure to roomnames (Forum #63530)
diff --git a/fhem/FHEM/93_DbRep.pm b/fhem/FHEM/93_DbRep.pm
index 9f41a2f4f..7800741bb 100644
--- a/fhem/FHEM/93_DbRep.pm
+++ b/fhem/FHEM/93_DbRep.pm
@@ -37,6 +37,9 @@
###########################################################################################################################
# Versions History:
#
+# 7.2.0 27.12.2017 new attribute "seqDoubletsVariance"
+# 7.1.0 22.12.2017 new attribute timeYearPeriod for reports correspondig to e.g. electricity billing,
+# bugfix connection check is running after restart allthough dev is disabled
# 7.0.0 18.12.2017 don't set $runtime_string_first,$runtime_string_next,$ts if time/aggregation-attributes
# not set, devren_Push redesigned, new command get blockinginfo, identify if reopen is
# running on dblog-device and postpone the set-command
@@ -270,7 +273,7 @@ use Encode qw(encode_utf8);
sub DbRep_Main($$;$);
-my $DbRepVersion = "7.0.0";
+my $DbRepVersion = "7.2.0";
my %dbrep_col = ("DEVICE" => 64,
"TYPE" => 64,
@@ -324,6 +327,7 @@ sub DbRep_Initialize($) {
"readingNameMap ".
"readingPreventFromDel ".
"role:Client,Agent ".
+ "seqDoubletsVariance ".
"showproctime:1,0 ".
"showSvrInfo ".
"showVariables ".
@@ -331,6 +335,7 @@ sub DbRep_Initialize($) {
"showTableInfo ".
"sqlResultFormat:separated,mline,sline,table,json ".
"sqlResultFieldSep:|,:,\/ ".
+ "timeYearPeriod ".
"timestamp_begin ".
"timestamp_end ".
"timeDiffToNow ".
@@ -743,6 +748,8 @@ sub DbRep_Attr($$$$) {
dumpComment
dumpSpeed
optimizeTablesBeforeDump
+ seqDoubletsVariance
+ timeYearPeriod
timestamp_begin
timestamp_end
timeDiffToNow
@@ -823,6 +830,37 @@ sub DbRep_Attr($$$$) {
}
if ($cmd eq "set") {
+ if ($aName =~ /seqDoubletsVariance/) {
+ unless (looks_like_number($aVal)) { return " The Value of $aName is not valid. Only figures are allowed !";}
+ }
+ 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\".";}
+ 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;
+ # 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;
+ if ($mm2 <= $mm1 && $c <= $e) {
+ $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); };
+ if ($@) {
+ my @l = split (/at/, $@);
+ return " The Value of $aName is out of range - $l[0]";
+ }
+ delete($attr{$name}{timestamp_begin}) if ($attr{$name}{timestamp_begin});
+ delete($attr{$name}{timestamp_end}) if ($attr{$name}{timestamp_end});
+ delete($attr{$name}{timeDiffToNow}) if ($attr{$name}{timeDiffToNow});
+ delete($attr{$name}{timeOlderThan}) if ($attr{$name}{timeOlderThan});
+ return undef;
+ }
if ($aName eq "timestamp_begin" || $aName eq "timestamp_end") {
my ($a,$b,$c) = split('_',$aVal);
if ($a =~ /^current$|^previous$/ && $b =~ /^hour$|^day$|^week$|^month$|^year$/ && $c =~ /^begin$|^end$/) {
@@ -845,31 +883,26 @@ sub DbRep_Attr($$$$) {
delete($attr{$name}{timeDiffToNow}) if ($attr{$name}{timeDiffToNow});
delete($attr{$name}{timeOlderThan}) if ($attr{$name}{timeOlderThan});
}
-
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") {
unless ($aVal =~ m/^[A-Za-z\d_\.-]+$/) { return " Unsupported character in $aName found. Use only A-Z a-z _ . -";}
}
-
if ($aName eq "timeDiffToNow") {
unless ($aVal =~ /^[0-9]+$/ || $aVal =~ /^\s*[dhms]:([\d]+)\s*/ && $aVal !~ /.*,.*/ )
- { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"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 \"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}{timeOlderThan}) if ($attr{$name}{timeOlderThan});
}
-
if ($aName eq "timeOlderThan") {
unless ($aVal =~ /^[0-9]+$/ || $aVal =~ /^\s*[dhms]:([\d]+)\s*/ && $aVal !~ /.*,.*/ )
- { return "The Value of \"$aName\" isn't valid. Set simple seconds like \"86400\" or use form like \"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 \"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}{timeDiffToNow}) if ($attr{$name}{timeDiffToNow});
}
-
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);
@@ -881,15 +914,12 @@ sub DbRep_Attr($$$$) {
unless($aVal <= ($dml / 10)) {return "The Value of $aName mustn't be greater than 'dumpMemlimit / 10' ! ";}
}
}
-
if ($aName eq "ftpUse") {
delete($attr{$name}{ftpUseSSL});
}
-
if ($aName eq "ftpUseSSL") {
delete($attr{$name}{ftpUse});
}
-
if ($aName eq "reading" || $aName eq "device") {
if ($dbmodel && $dbmodel ne 'SQLITE') {
my $attrname = uc($aName);
@@ -1006,7 +1036,7 @@ sub DbRep_firstconnect($) {
$hash->{dbloghash} = $defs{$dblogdevice};
my $dbconn = $hash->{dbloghash}{dbconn};
-if ($init_done == 1) {
+if ($init_done == 1 && !IsDisabled($name)) {
if ( !DbRep_Connect($hash) ) {
Log3 ($name, 2, "DbRep $name - DB connect failed. Credentials of database $hash->{DATABASE} are valid and database reachable ?");
@@ -1218,6 +1248,27 @@ sub createTimeArray($$$) {
$tsbegin = formatpicker($tsbegin);
$tsend = AttrVal($name, "timestamp_end", strftime "%Y-%m-%d %H:%M:%S", localtime(time));
$tsend = formatpicker($tsend);
+
+ 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 $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;
+ if ($mep <= $mbp && $c <= $e) {
+ $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") {
@@ -3945,8 +3996,9 @@ sub delseqdoubl_DoParse($) {
my $dbpassword = $attr{"sec$dblogname"}{secret};
my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0;
my $limit = AttrVal($name, "limit", 1000);
+ my $var = AttrVal($name, "seqDoubletsVariance", undef);
my $table = "history";
- my ($err,$dbh,$sth,$sql,$rowlist,$nrows,$selspec,$st);
+ my ($err,$dbh,$sth,$sql,$rowlist,$nrows,$selspec,$st,$var1,$var2);
# Background-Startzeit
my $bst = [gettimeofday];
@@ -4025,13 +4077,20 @@ sub delseqdoubl_DoParse($) {
($ndev,$nread,undef,undef,$nval) = split("_ESC_", $nr); # Werte des aktuellen Elements
$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) && $var) { # Varianz +- falls $val numerischer Wert
+ $var1 = $oval + $var;
+ $var2 = $oval - $var;
+ } else {
+ undef $var1;
+ undef $var2;
+ }
$oor = pop @sel; # das vorletzte Element der Liste
$ooval = (split '_ESC_', $oor)[-1]; # Value des vorletzten Elements
if ($ndev.$nread ne $odev.$oread) {
push (@sel,$oor);
push (@sel,$or);
push (@sel,$nr);
- } elsif ($ooval eq $oval) {
+ } elsif ($ooval eq $oval || (($var1 && ($ooval <= $var1)) && ($var2 && ($var2 <= $ooval))) ) {
push (@sel,$oor);
push (@sel,$nr);
# Log3 ($name, 5, "DbRep $name -> warping: $or");
@@ -6246,9 +6305,9 @@ sub checktimeaggr ($) {
my $IsAggrSet = 0;
my $aggregation = AttrVal($name,"aggregation","no");
- if (AttrVal($name,"timestamp_begin",undef) || AttrVal($name,"timestamp_end",undef) ||
- AttrVal($name,"timeDiffToNow",undef) || AttrVal($name,"timeOlderThan",undef) ) {
- $IsTimeSet = 1;
+ if ( AttrVal($name,"timestamp_begin",undef) || AttrVal($name,"timestamp_end",undef) ||
+ AttrVal($name,"timeDiffToNow",undef) || AttrVal($name,"timeOlderThan",undef) || AttrVal($name,"timeYearPeriod",undef) ) {
+ $IsTimeSet = 1;
}
if ($aggregation ne "no") {
@@ -7064,7 +7123,9 @@ return;
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".
+ 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.
attr <Name> seqDoubletsVariance 0.0014
attr <Name> seqDoubletsVariance 1.45
attr <Name> seqDoubletsVariance 0.0014
attr <Name> seqDoubletsVariance 1.45