From 48fff2e00a1bec9d10b973b7beae87c40d194e14 Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Sat, 5 Apr 2014 06:37:49 +0000
Subject: [PATCH] average: counter changes from Stefan
git-svn-id: https://svn.fhem.de/fhem/trunk@5443 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/FHEM/98_average.pm | 171 ++++++++++++++++++++++++++--------------
1 file changed, 112 insertions(+), 59 deletions(-)
diff --git a/fhem/FHEM/98_average.pm b/fhem/FHEM/98_average.pm
index 9e95191ec..043164d31 100644
--- a/fhem/FHEM/98_average.pm
+++ b/fhem/FHEM/98_average.pm
@@ -1,6 +1,6 @@
##############################################
# $Id$
-# Avarage computing
+# Average computing
package main;
use strict;
@@ -14,8 +14,13 @@ average_Initialize($)
$hash->{DefFn} = "average_Define";
$hash->{NotifyFn} = "average_Notify";
$hash->{NotifyOrderPrefix} = "10-"; # Want to be called before the rest
- $hash->{AttrList} = "disable:0,1";
-}
+ $hash->{AttrList} = "disable:0,1 " .
+ "disabledForIntervals " .
+ "computeMethod:integral,counter " .
+ "noaverage:0,1 " .
+ "nominmax:0,1 " .
+ "floatformat:%0.1f,%0.2f";
+ }
##########################
@@ -38,14 +43,22 @@ average_Define($$$)
return undef;
}
+
+sub
+avg_setValTime($$$$)
+{
+ my ($r, $rname, $val, $tn) = @_;
+ $r->{$rname}{VAL} = $val;
+ $r->{$rname}{TIME} = $tn;
+}
##########################
sub
average_Notify($$)
{
my ($avg, $dev) = @_;
- my $avgName = $avg->{NAME};
+ my $myName = $avg->{NAME};
- return "" if(AttrVal($avgName, "disable", undef));
+ return "" if(IsDisabled($myName));
my $devName = $dev->{NAME};
my $re = $avg->{REGEXP};
@@ -53,6 +66,12 @@ average_Notify($$)
my $tn;
my $myIdx = $max;
+ my $doCounter = (AttrVal($myName, "computeMethod", "integral") eq "counter");
+ my $doMMx = (AttrVal($myName, "nominmax", "0") eq "0");
+ my $doAvg = (AttrVal($myName, "noaverage", "0") eq "0");
+ my $ffmt = AttrVal($myName, "floatformat", "%0.1f");
+ my $r = $dev->{READINGS};
+
for (my $i = 0; $i < $max; $i++) {
my $s = $dev->{CHANGED}[$i];
@@ -60,8 +79,8 @@ average_Notify($$)
# Filtering
next if(!defined($s));
my ($evName, $val) = split(" ", $s, 2); # resets $1
-# Log3 $avgName, 1,"mytestavg pre-filter: ".$devName.$evName." s=".$s;
- next if($devName !~ m/^$re$/ && "$devName:$s" !~ m/^$re$/ || $s =~ m/_avg_/);
+ next if($devName !~ m/^$re$/ && "$devName:$s" !~ m/^$re$/ ||
+ $s =~ m/(_avg_|_cum_|_min_|_max_|_cnt_)/);
if(defined($1)) {
my $reArg = $1;
if(defined($2)) {
@@ -73,81 +92,95 @@ average_Notify($$)
next if(!defined($val) || $val !~ m/^(-?\d+\.?\d*)/);
$val = $1;
-# Log3 $avgName, 1,"mytestavg pst-filter: ".$devName.$evName." val=".$val;
-
################
# Avg computing
$evName =~ s/[^A-Za-z_-].*//;
$tn = TimeNow() if(!$tn);
- my $r = $dev->{READINGS};
my @dNow = split("[ :-]", $tn);
- for(my $idx = 0; $idx <= 1; $idx++) {
+ for(my $idx = 0; $idx <= 1; $idx++) { # 0:day 1:month
my $secNow = 3600*$dNow[3] + 60*$dNow[4] + $dNow[5];
$secNow += $dNow[2]*86400 if($idx);
my $cumName = "${evName}_cum_" . ($idx ? "month" : "day");
my $avgName = "${evName}_avg_" . ($idx ? "month" : "day");
- my $minName = "${evName}_min_" . ($idx ? "month" : "day"); ##MH
- my $maxName = "${evName}_max_" . ($idx ? "month" : "day"); ##MH
+ my $minName = "${evName}_min_" . ($idx ? "month" : "day");
+ my $maxName = "${evName}_max_" . ($idx ? "month" : "day");
+ my $cntName = "${evName}_cnt_" . ($idx ? "month" : "day");
- if(!$r->{$cumName}) {
- $r->{$cumName}{VAL} = $secNow*$val;
- $r->{$avgName}{VAL} = $val;
- $r->{$maxName}{VAL} = $val; ##MH
- $r->{$minName}{VAL} = $val; ##MH
- $r->{$cumName}{TIME} = $r->{$avgName}{TIME} = $tn;
+ if($doCounter && !defined($r->{$cntName})) {
+ avg_setValTime($r, $cntName, 1, $tn);
+ delete $r->{$cumName}; # Reset when switching to counter-mode
+ delete $r->{$avgName};
+ }
+
+ if($doMMx && (!defined($r->{$maxName}) || !defined($r->{$minName}))) {
+ avg_setValTime($r, $maxName, $val, $tn);
+ avg_setValTime($r, $minName, $val, $tn);
+ }
+
+ if(!defined($r->{$cumName}) || ($doAvg && !defined($r->{$avgName}))) {
+ my $cum = ($doCounter ? $val : $secNow*$val);
+ avg_setValTime($r, $cumName, $cum, $tn);
+ avg_setValTime($r, $avgName, $val, $tn) if ($doAvg);
next;
}
-
- ##MH take care of existing average definitions - just add this one..
- if(!$r->{$maxName}) {
- $r->{$maxName}{VAL} = $val;
- $r->{$maxName}{TIME} = $tn;
- }
- ##MH take care of existing average definitions - just add this one..
- if(!$r->{$minName}) {
- $r->{$minName}{VAL} = $val;
- $r->{$minName}{TIME} = $tn;
- }
-
+
my @dLast = split("[ :-]", $r->{$cumName}{TIME});
my $secLast = 3600*$dLast[3] + 60*$dLast[4] + $dLast[5];
$secLast += $dLast[2]*86400 if($idx);
if($idx == 0 && ($dLast[2] == $dNow[2]) ||
- $idx == 1 && ($dLast[1] == $dNow[1])) {
- my $cum = $r->{$cumName}{VAL} + ($secNow-$secLast) * $val;
- $r->{$cumName}{VAL} = $cum;
- my $div = ($secNow ? $secNow : 1);
- $r->{$avgName}{VAL} = sprintf("%0.1f", $cum/$div);
- ##MH change only if current value bigger than maxvalue
- if($r->{$maxName}{VAL} < $val) {
- $r->{$maxName}{VAL} = sprintf("%0.1f", $val); ##MH
- $r->{$maxName}{TIME} = $tn; ##MH
+ $idx == 1 && ($dLast[1] == $dNow[1])) { # same day or month
+
+ my $cVal = $r->{$cumName}{VAL};
+ $cVal += ($doCounter ? $val : ($secNow-$secLast) * $val);
+ avg_setValTime($r, $cumName, $cVal, $tn);
+
+ if($doAvg) {
+ my $div = ($secNow ? $secNow : 1);
+ if($doCounter) {
+ $div = $r->{$cntName}{VAL}+1;
+ avg_setValTime($r, $cntName, $div, $tn);
+ }
+ my $lVal = sprintf($ffmt, $r->{$cumName}{VAL}/$div);
+ avg_setValTime($r, $avgName, $lVal, $tn);
}
- ##MH change only if current value smaller than minvalue
- if($r->{$minName}{VAL} > $val) {
- $r->{$minName}{VAL} = sprintf("%0.1f", $val); ##MH
- $r->{$minName}{TIME} = $tn; ##MH
+ if($doMMx) {
+ avg_setValTime($r, $maxName, sprintf($ffmt,$val), $tn)
+ if($r->{$maxName}{VAL} < $val);
+ avg_setValTime($r, $minName, sprintf($ffmt,$val), $tn)
+ if($r->{$minName}{VAL} > $val);
}
- } else {
- $dev->{CHANGED}[$myIdx++] = "$avgName: ".$r->{$avgName}{VAL};
- $dev->{CHANGED}[$myIdx++] = "$maxName: ".$r->{$maxName}{VAL}; ##MH
- $dev->{CHANGED}[$myIdx++] = "$minName: ".$r->{$minName}{VAL}; ##MH
- $r->{$cumName}{VAL} = $secNow*$val;
- $r->{$avgName}{VAL} = $val;
- ##MH set to current value
- $r->{$maxName}{VAL} = sprintf("%0.1f", $val); ##MH
- $r->{$maxName}{TIME} = $tn; ##MH
- $r->{$minName}{VAL} = sprintf("%0.1f", $val); ##MH
- $r->{$minName}{TIME} = $tn; ##MH
+ } else { # day or month changed: create events and reset values
+
+ if($doAvg) {
+ $dev->{CHANGED}[$myIdx++] = "$avgName: ".$r->{$avgName}{VAL};
+ avg_setValTime($r, $cumName, $secNow*$val, $tn);
+ avg_setValTime($r, $avgName, $val, $tn);
+ }
+
+ if($doCounter) {
+ $dev->{CHANGED}[$myIdx++] = "$cumName: ".$r->{$cumName}{VAL};
+ avg_setValTime($r, $cumName, 0, $tn);
+ avg_setValTime($r, $cntName, 0, $tn) if($doAvg);
+
+ } else {
+ avg_setValTime($r, $cumName, $secNow*$val, $tn);
+
+ }
+
+ if($doMMx) {
+ $dev->{CHANGED}[$myIdx++] = "$maxName: ".$r->{$maxName}{VAL};
+ $dev->{CHANGED}[$myIdx++] = "$minName: ".$r->{$minName}{VAL};
+ avg_setValTime($r, $maxName, sprintf($ffmt, $val), $tn);
+ avg_setValTime($r, $minName, sprintf($ffmt, $val), $tn);
+ }
}
- $r->{$cumName}{TIME} = $r->{$avgName}{TIME} = $tn;
}
}
return undef;
@@ -178,7 +211,7 @@ average_Notify($$)
regexp for notify.
If it matches, and the event is of the form "eventname number", then this
module computes the daily and monthly average, maximum and minimum values
- and generates events of the form
+ and sums depending on attribute settings and generates events of the form