Probleme mit myAverage() und UserReading

Begonnen von Rampler, 26 August 2016, 13:15:09

Vorheriges Thema - Nächstes Thema

Rampler

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
3 HMUART (2 via ESP8266), 1 DUOFERN, 9 ESP8266, RPI2 (Bullseye), ZWAVE, HM-Classic, und hoch zufrieden ...
Danke an alle, die was dazu beigetragen haben !!

Hans Franz

#1
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
Raspi
CUL, Nano-CUL
FHT8V, FHT80B, S300TH
WM1000WZ, ELRO
LW12, LD382,DS18B20

Rampler

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 ..
3 HMUART (2 via ESP8266), 1 DUOFERN, 9 ESP8266, RPI2 (Bullseye), ZWAVE, HM-Classic, und hoch zufrieden ...
Danke an alle, die was dazu beigetragen haben !!

Hans Franz

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
Raspi
CUL, Nano-CUL
FHT8V, FHT80B, S300TH
WM1000WZ, ELRO
LW12, LD382,DS18B20

Rampler

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
3 HMUART (2 via ESP8266), 1 DUOFERN, 9 ESP8266, RPI2 (Bullseye), ZWAVE, HM-Classic, und hoch zufrieden ...
Danke an alle, die was dazu beigetragen haben !!

felixm

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