Hallo zusammen,
ich möchte diese Routine (aus dem Wiki) für Bildung meiner Mittelwerte des Sonnensensors (HM-Sen-LI-O) verwenden:
###############################################################################
#
# 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 3,"[$name moving average] Value = ".$arr->[$i][0]." Time = ".$arr->[$i][1];
}
$average=sprintf( "%5.3f", $average/$num);
#--average
Log 3,"[$name moving average] calculated over $num values is $average";
return $average;
Mit dem Usereading soll jedesmal das reading brightness.av neu geschrieben werden.
attr Sonnensensor userReadings brightness.av {movingAverage("Sonnensensor","brightness",1800)}
Das funktioniert auch tadellos, wenn ich einen "setreading Sonnensensor brightness xxxxx absetze. Wenn allerdings der Sonnensensor das Reading aktualisiert, wird die Routine mehrmals aufgerufen. Folglich bekomme ich mehrere Einträge:
2016.08.26 13:04:02 3: [Sonnensensor moving average] Value = 118136.15 Time = 2016-08-26 13:04:02
2016.08.26 13:04:02 3: [Sonnensensor moving average] Value = 118136.15 Time = 2016-08-26 13:04:02
2016.08.26 13:04:02 3: [Sonnensensor moving average] Value = 118136.15 Time = 2016-08-26 13:04:02
2016.08.26 13:04:02 3: [Sonnensensor moving average] calculated over 26 values is 97729.871
Die MovingAverage wird also mehrmals durch das UserReading aufgerufen.. Habe schon einiges versucht, immer wieder mehrmalige aufrufe mit dem userreading. Hat jemand einen Tipp für mich ?
Viele grüße
Klaus
Am pragmatischten ist es, wenn du das letzte Log 3 durch Log 4 ersetzt.
Alternativ könntest du noch eine Abfrage auf das Alter des Readings einbauen a la:
Log 3,"[$name moving average] calculated over $num values is $average" if (ReadingsAge($name,$reading,0) > 2);
ungetestet.
Gruß
Hans
Zitat von: Hans Franz am 26 August 2016, 13:45:18
Am pragmatischten ist es, wenn du das letzte Log 3 durch Log 4 ersetzt.
Alternativ könntest du noch eine Abfrage auf das Alter des Readings einbauen a la:
Log 3,"[$name moving average] calculated over $num values is $average" if (ReadingsAge($name,$reading,0) > 2);
ungetestet.
Ja, hatte ich ja, doch sind die Werte halt ziemlich daneben, da jeder Wert mit dem faktor drei eingeht, wenn er dreimal gelogt wird ..
Ach so, ich dachte, es ginge nur um die Logeinträge.
Du kannst doch aber am Anfang der Routine mittels ReadingAge entscheiden, ob du sofort zurückkehrst oder den Mittelwert berechnest.
Gruß
Hans
Habe meinen Fehler gefunden...
UserrReading mit Angabe von device:reading funktioniert nur, wenn auch Event's erzeugt werden, also aufpassen bei event-on-change ...
DANKE nochmal für die Unterstützung
Hallo Rampler,
könntest du die Lösung für deinen Fehler (bzw. den Fehler) noch etwas genauer beschreiben?
Ich bin gerade am gleichen Problem verzweifelt und habe es jetzt gelöst indem ich im Perl Modul eine Prüfung eingebaut habe die den Timestamp vergleicht. Schöner wäre natürlich wenn es nur einmal aufgerufen würde. Ich steige allerdings noch nicht ganz durch die Trigger durch (gerade bei mehreren Userreadings in einem Device).
Grüße
Felix