Hallo zusammen,
ich verwende die im Wiki
http://www.fhemwiki.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen (http://www.fhemwiki.de/wiki/Gleitende_Mittelwerte_berechnen_und_loggen)
beschriebene Moving Average Routine in meiner myutils.
Siehe hier:
###############################################################################
#
# Moving average
#
# Aufruf: movingAverage(devicename,readingname,zeitspanne in s)
#
###############################################################################
sub movingAverage($$$){
my ($name,$reading,$avtime) = @_;
my $hash = $defs{$name};
my @new = my ($val,$time) = ($hash->{READINGS}{$reading}{VAL},$hash->{READINGS}{$reading}{TIME});
my ($cyear, $cmonth, $cday, $chour, $cmin, $csec) = $time =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
my $ctime = $csec+60*$cmin+3600*$chour;
my $num;
my $arr;
#-- initialize if requested
if( ($avtime eq "-1") ){
$hash->{READINGS}{$reading}{"history"}=undef;
}
#-- test for existence
if( !$hash->{READINGS}{$reading}{"history"}){
#Log 1,"ARRAY CREATED";
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
$num = 1;
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
} else {
$num = int(@{$hash->{READINGS}{$reading}{"history"}});
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
my $starttime = $arr->[0][1];
my ($syear, $smonth, $sday, $shour, $smin, $ssec) = $starttime =~ /(\d+)-(\d+)-(\d+)\s(\d+):(\d+):(\d+)/;
my $stime = $ssec+60*$smin+3600*$shour;
#-- correct for daybreak
$stime-=86400
if( $stime > $ctime);
if( ($num < 100)&&( ($ctime-$stime)<$avtime) ){
#Log 1,"ARRAY has $num elements, adding another one";
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
}else{
shift(@{$hash->{READINGS}{$reading}{"history"}});
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
}
}
#-- output and average
my $average = 0;
for(my $i=0;$i<$num;$i++){
$average+=$arr->[$i][0];
Log 4,"[$name moving average] Value = ".$arr->[$i][0]." Time = ".$arr->[$i][1];
}
$average=sprintf( "%5.2f", $average/$num);
#--average
Log 4,"[$name moving average] calculated over $num values is $average";
return $average;
}
Habe den Intervall für meinen Sonnensensor auf 1800 Sekunden gesetzt, das ergibt tagsüber 13 Intervalle. Am Folgetag, steht der Intervall dann allerdings auf 26, weil die Meldungen vom Sonnensensor zwischenzeitlich wahrscheinlich (logge leider nicht mit) erhöht waren.
Die Zeitspanne, entspricht jetzt nicht mehr 1800 Sekunden, sondern 1 Stunde.
Hier mal ein Auszug aus dem Log, bei dem der Intervall noch passt:
2016.08.27 07:35:17 3: [Sonnensensor moving average] calculated over 13 values is 2589.695
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2073.61 Time = 2016-08-27 07:07:37
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2185.48 Time = 2016-08-27 07:10:10
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2288.14 Time = 2016-08-27 07:12:29
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2378.76 Time = 2016-08-27 07:14:33
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2498.31 Time = 2016-08-27 07:17:27
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2606.73 Time = 2016-08-27 07:20:07
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2703.5 Time = 2016-08-27 07:22:32
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2788.87 Time = 2016-08-27 07:24:42
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 2905.87 Time = 2016-08-27 07:27:43
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3006.85 Time = 2016-08-27 07:30:28
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3100.55 Time = 2016-08-27 07:33:00
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3185.54 Time = 2016-08-27 07:35:17
2016.08.27 07:37:19 3: [Sonnensensor moving average] Value = 3257.74 Time = 2016-08-27 07:37:19
2016.08.27 07:37:19 3: [Sonnensensor moving average] calculated over 13 values is 2690.765
Und jetzt (einen Tag später):
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 61524.32 Time = 2016-08-28 09:34:46
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 63085.79 Time = 2016-08-28 09:37:39
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 64410.4 Time = 2016-08-28 09:40:18
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 65594.65 Time = 2016-08-28 09:42:42
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 66831.54 Time = 2016-08-28 09:44:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 67555.26 Time = 2016-08-28 09:47:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 69200.06 Time = 2016-08-28 09:50:35
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 70476.42 Time = 2016-08-28 09:53:06
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 71375.58 Time = 2016-08-28 09:55:22
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 72257.19 Time = 2016-08-28 09:57:23
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 73073.01 Time = 2016-08-28 10:00:14
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 74415.17 Time = 2016-08-28 10:02:51
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 74116.91 Time = 2016-08-28 10:05:13
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 75138.88 Time = 2016-08-28 10:07:21
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 75840.66 Time = 2016-08-28 10:10:18
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 77042.46 Time = 2016-08-28 10:13:01
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 78397.78 Time = 2016-08-28 10:15:30
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 79178.51 Time = 2016-08-28 10:17:44
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 80801.38 Time = 2016-08-28 10:20:48
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 81985.63 Time = 2016-08-28 10:23:37
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 82950.59 Time = 2016-08-28 10:26:12
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 83310.25 Time = 2016-08-28 10:28:32
2016.08.28 10:30:38 3: [Sonnensensor moving average] Value = 84025.19 Time = 2016-08-28 10:30:38
2016.08.28 10:30:38 3: [Sonnensensor moving average] calculated over 23 values is 73590.77
Meines erachtens ist das Problem, dass die Variable $num nur hochgezählt wird, aber nie runter, was natürlich suboptimal bei Sensoren ist, deren Intervallfrequenz sich verändert.
Ist irgendwie täuschend, wenn man beim dazu gehörenden UserReading:
brightness.av:B.* {movingAverage("Sonnensensor","brightness",1800)}
eine halbe Stunde angibt..
Wäre toll, wenn das auch noch funktioniert...
Viele Grüße
Klaus
hi Klaus,
das Problem hatte ich auch!
ich hab einiges geändert, sollte funktionieren, willst du versuchen, bevor ich das Wiki update?
###############################################################################
#
# Moving average
#
# Aufruf: movingAverage(devicename,readingname,zeitspanne in s)
#
# MH changes:
# timestamp handling, delete old entries, delete entries if # >= 24, Log3, ....
###############################################################################
sub movingAverage($$$){
my ($name,$reading,$avtime) = @_;
my $hash = $defs{$name};
my $val = $hash->{READINGS}{$reading}{VAL};
my $time = $hash->{READINGS}{$reading}{TIME};
my $ctime = time_str2num($time);
Log3 $name, 4,"[movingAverage $name] time= $time $ctime reading= $reading value= $val";
my @new = ($val,$ctime);
my $num;
my $arr;
#-- initialize if requested
if( ($avtime eq "-1") ){
$hash->{READINGS}{$reading}{"history"}=undef;
}
#-- test for existence
if( !$hash->{READINGS}{$reading}{"history"}){
Log3 $name, 3,"[movingAverage $name] ARRAY CREATED";
push(@{$hash->{READINGS}{$reading}{"history"}},\@new);
$num = 1;
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
} else {
$num = int(@{$hash->{READINGS}{$reading}{"history"}});
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
my $stime = $arr->[0][1];
while( ($num >= 24) || ((($ctime-$stime) > $avtime) && $num > 1) ){ #delete "old" entries, or more then 24 entries
Log3 $name, 5,"[movingaverage $name] ARRAY has $num elements, deleting one w. Timestamp=" . movingAverageTS($stime);
shift(@{$hash->{READINGS}{$reading}{"history"}});
$num--; # correct # of entries
$arr=\@{$hash->{READINGS}{$reading}{"history"}};
$stime = $arr->[0][1];
}
push(@{$hash->{READINGS}{$reading}{"history"}},\@new); # always push the last one
$num++; # correct # of entries
Log3 $name, 4,"[movingaverage $name] ARRAY has $num elements, added one";
}
#-- output and average
my $average = 0;
for(my $i=0;$i<$num;$i++){
$average+=$arr->[$i][0];
Log3 $name, 5,"[movingaverage $name] Value= ".$arr->[$i][0]." Time= " . movingAverageTS($arr->[$i][1]);
}
$average=sprintf( "%5.3f", $average/$num);
#--average
Log3 $name, 4,"[movingaverage $name] calculated over $num values is $average";
return $average;
}
#return timestring (HH:MM:SS format) from given unix timestamp
sub movingAverageTS($) {
my ($utime) = @_;
my @t = localtime($utime);
my $mytimestr = sprintf("%02d:%02d:%02d", $t[2], $t[1], $t[0]);
return $mytimestr;
}
1;
call syntax ist gleichgeblieben,
Logging: im betreffenden device verbose=5 setzen
have fun
erwin
update: fixed a bug when deleting array entries, keep minimum 1 entry....
Hallo Erwin,
sorry habe den Thread irgendwie verdrängt...
Bin grad am Testen...
Bis jetzt Daumen hoch, werde berichten ..
Viele Grüße
Klaus
Edit1: Bis jetzt super, habe das Log3 angepasst:
# Logging: Steuerung über Verbose vom Device
# 1 - calculated over xx values is xxx.xx
# ARRAY CREATED
# 2 - ARRAY has 11 elements, deleting one w. Timestamp=hh:mm:ss
# ARRAY has 11 elements, added one
# 3 - Value= xxx.xx Time= hh:mm:ss
# 4 - time= year-month-day hh:mm:ss unixtime reading= reading value= xxx.xx
Habe bei meinem Sonnensensor standartmäßig Verbose auf 0
Die Steuerung über Verbose ist eine coole Sache !
... bin begeistert ...
2016.09.23 19:44:04 1: [movingaverage Sonnensensor] calculated over 11 values is 47.16
2016.09.23 19:46:50 1: [movingaverage Sonnensensor] calculated over 11 values is 30.64
2016.09.23 19:49:21 1: [movingaverage Sonnensensor] calculated over 12 values is 28.14
2016.09.23 19:51:38 1: [movingaverage Sonnensensor] calculated over 12 values is 18.98
2016.09.23 19:53:41 1: [movingaverage Sonnensensor] calculated over 13 values is 17.54
2016.09.23 19:56:33 1: [movingaverage Sonnensensor] calculated over 12 values is 7.90
Und es funktioniert ..
bin mal auf morgen früh gespannt ..
DANKE
Hallo Erwin,
über Nacht sieht es so aus ..
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 4.94 Time= 19:38:54
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 3.36 Time= 19:41:04
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 1.95 Time= 19:44:04
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 1.17 Time= 19:46:50
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.63 Time= 19:49:21
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.38 Time= 19:51:38
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.26 Time= 19:53:41
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.14 Time= 19:56:33
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.07 Time= 19:59:11
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.04 Time= 20:01:34
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0.01 Time= 20:03:43
2016.09.23 20:06:41 3: [movingaverage Sonnensensor] Value= 0 Time= 20:06:41
2016.09.23 20:06:41 1: [movingaverage Sonnensensor] calculated over 12 values is 1.08
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 12 elements, deleting one w. Timestamp=19:38:54
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 11 elements, deleting one w. Timestamp=19:41:04
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 10 elements, deleting one w. Timestamp=19:44:04
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 9 elements, deleting one w. Timestamp=19:46:50
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 8 elements, deleting one w. Timestamp=19:49:21
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 7 elements, deleting one w. Timestamp=19:51:38
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 6 elements, deleting one w. Timestamp=19:53:41
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 5 elements, deleting one w. Timestamp=19:56:33
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 4 elements, deleting one w. Timestamp=19:59:11
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 3 elements, deleting one w. Timestamp=20:01:34
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 2 elements, deleting one w. Timestamp=20:03:43
2016.09.24 06:20:22 2: [movingaverage Sonnensensor] ARRAY has 2 elements, added one
2016.09.24 06:20:22 3: [movingaverage Sonnensensor] Value= 0 Time= 20:06:41
2016.09.24 06:20:22 3: [movingaverage Sonnensensor] Value= 0.03 Time= 06:20:22
2016.09.24 06:20:22 1: [movingaverage Sonnensensor] calculated over 2 values is 0.01
2016.09.24 06:23:16 2: [movingaverage Sonnensensor] ARRAY has 2 elements, deleting one w. Timestamp=20:06:41
2016.09.24 06:23:16 2: [movingaverage Sonnensensor] ARRAY has 2 elements, added one
2016.09.24 06:23:16 3: [movingaverage Sonnensensor] Value= 0.03 Time= 06:20:22
2016.09.24 06:23:16 3: [movingaverage Sonnensensor] Value= 0.05 Time= 06:23:16
Würde sagen das passt, obwohl der Sensor in der Nacht immer wieder 0 meldet ...
Sieht so aus, als ob die 0 nicht berücksichtigt wird ...
Viele Grüße
Klaus
EDIT: Problem war event-on-change state, habe mal auf event-on-update state geändert, so konnte er keine events melden.
Von mir ein dreimal JA !!