FHEM Forum

FHEM => Sonstiges => Thema gestartet von: Happy Fhem User am 21 Februar 2016, 15:08:17

Titel: Reihenfolge der Berechnung von userReadings
Beitrag von: Happy Fhem User am 21 Februar 2016, 15:08:17
Weil ich gerade versuchte die letzte Öffnungs- & Schließzeit per userReadings zu realisieren, bin ich wie andere (http://forum.fhem.de/index.php/topic,11794.msg180986.html (http://forum.fhem.de/index.php/topic,11794.msg180986.html) und Suche "userReadings Reihenfolge") drüber gestolpert, dass mehrere userReadings in einem Device in keiner definierten Reihenfolge ausgeführt werden.

Um die userReadings in der definierten Reihenfolge auszuführen, benötigt es nur 3 neue Codezeilen und eine geänderte.
Wäre super Klasse, wenn die Änderung in den Upstream einfliessen würde.

Unified Diff gegen die fhem.pl SVN Version vom 2016-02-08

--- fhem_2016-02-08.pl 2016-02-21 14:42:52.157959939 +0100
+++ fhem.pl 2016-02-21 14:53:35.882467759 +0100
@@ -2481,6 +2481,7 @@
       my $regexo= '^(' . $regexi . ')(,\s*(.*))*$';

       #Log 1, "arg is $arg";
+      my $rNo=0;

       while($arg =~ /$regexo/s) {
         my $userReading= $2;
@@ -2495,6 +2496,8 @@
           $userReadings{$userReading}{trigger}= $trigger;
           $userReadings{$userReading}{modifier}= $modifier;
           $userReadings{$userReading}{perlCode}= $perlCode;
+          $rNo++;
+          $userReadings{$userReading}{readingNo}= $rNo;
         } else {
           push @rets, "$sdev: unknown modifier $modifier for ".
                 "userReading $userReading, this userReading will be ignored";
@@ -3870,7 +3873,7 @@
   # process user readings
   if(defined($hash->{'.userReadings'})) {
     my %userReadings= %{$hash->{'.userReadings'}};
-    foreach my $userReading (keys %userReadings) {
+    foreach my $userReading (sort { $userReadings{$a}->{'readingNo'} <=> $userReadings{$b}->{'readingNo'}} keys %userReadings) {

       my $trigger = $userReadings{$userReading}{trigger};
       if(defined($trigger)) {
Titel: Antw:Reihenfolge der Berechnung von userReadings
Beitrag von: rudolfkoenig am 21 Februar 2016, 18:28:44
Habs eingecheckt.
Titel: Antw:Reihenfolge der Berechnung von userReadings
Beitrag von: justme1968 am 21 Februar 2016, 20:24:55
wäre es nicht besser für $hash->{.userReadings} gleich ein array stat dem aktuellen hash zu verwenden?

dann wird die reihenfolge ein mal beim setzen des attributes fest gelegt und nicht bei jedem readings update neu sortiert.

wenn man das wie unten vorgeschlagen macht spart man auch gleich noch mehrere mehrstufige hash lookups bei jedem durchlauf:Index: fhem.pl
===================================================================
--- fhem.pl (revision 10910)
+++ fhem.pl (working copy)
@@ -2472,7 +2472,7 @@

     if($attrName eq "userReadings") {

-      my %userReadings;
+      my @userReadings;
       # myReading1[:trigger1] [modifier1] { codecodecode1 }, ...
       my $arg= $a[2];

@@ -2482,7 +2482,7 @@
       my $rNo=0;

       while($arg =~ /$regexo/s) {
-        my $userReading= $2;
+        my $reading= $2;
         my $trigger= $3 ? $3 : undef;
         my $modifier= $5 ? $5 : "none";
         my $perlCode= $6;
@@ -2491,17 +2491,15 @@
         if(grep { /$modifier/ }
                 qw(none difference differential offset monotonic integral)) {
           $trigger =~ s/^:// if($trigger);
-          $userReadings{$userReading}{trigger}= $trigger;
-          $userReadings{$userReading}{modifier}= $modifier;
-          $userReadings{$userReading}{perlCode}= $perlCode;
-          $userReadings{$userReading}{readingNo}= $rNo++;
+          my %userReading = ( reading => $reading, trigger => $trigger, modifier => $modifier, perlCode => $perlCode );
+          push @userReadings, \%userReading;
         } else {
           push @rets, "$sdev: unknown modifier $modifier for ".
-                "userReading $userReading, this userReading will be ignored";
+                "userReading $reading, this userReading will be ignored";
         }
         $arg= defined($8) ? $8 : "";
       }
-      $hash->{'.userReadings'}= \%userReadings;
+      $hash->{'.userReadings'}= \@userReadings;
     }

     if($attrName eq "IODev" && (!$a[2] || !defined($defs{$a[2]}))) {
@@ -3869,29 +3867,27 @@

   # process user readings
   if(defined($hash->{'.userReadings'})) {
-    my %userReadings= %{$hash->{'.userReadings'}};
-    foreach my $userReading (sort { $userReadings{$a}{readingNo} <=>
-                                    $userReadings{$b}{readingNo} }
-                             keys %userReadings) {
+    foreach my $userReading (@{$hash->{'.userReadings'}}) {

-      my $trigger = $userReadings{$userReading}{trigger};
+      my $trigger = $userReading->{trigger};
       if(defined($trigger)) {
         my @fnd = grep { $_ && $_ =~ m/^$trigger/ } @{$hash->{CHANGED}};
         next if(!@fnd);
       }

-      my $modifier= $userReadings{$userReading}{modifier};
-      my $perlCode= $userReadings{$userReading}{perlCode};
-      my $oldvalue= $userReadings{$userReading}{value};
-      my $oldt= $userReadings{$userReading}{t};
-      #Debug "Evaluating " . $userReadings{$userReading};
+      my $reading= $userReading->{reading};
+      my $modifier= $userReading->{modifier};
+      my $perlCode= $userReading->{perlCode};
+      my $oldvalue= $userReading->{value};
+      my $oldt= $userReading->{t};
+      #Debug "Evaluating " . $reading;
       $cmdFromAnalyze = $perlCode;      # For the __WARN__ sub
       my $value= eval $perlCode;
       $cmdFromAnalyze = undef;
       my $result;
       # store result
       if($@) {
-        $value = "Error evaluating $name userReading $userReading: $@";
+        $value = "Error evaluating $name userReading $reading: $@";
         Log 1, $value;
         $result= $value;
       } elsif($modifier eq "none") {
@@ -3908,25 +3904,25 @@
         if(defined($oldt) && defined($oldvalue)) {
           my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
           my $avgval= ($value + $oldvalue) / 2;
-          $result = ReadingsVal($name,$userReading,$value);
+          $result = ReadingsVal($name,$reading,$value);
           if(defined($deltat) && $deltat>= 1.0) {
             $result+= $avgval*$deltat;
           }
         }
       } elsif($modifier eq "offset") {
         $oldvalue = $value if( !defined($oldvalue) );
-        $result = ReadingsVal($name,$userReading,0);
+        $result = ReadingsVal($name,$reading,0);
         $result += $oldvalue if( $value < $oldvalue );
       } elsif($modifier eq "monotonic") {
         $oldvalue = $value if( !defined($oldvalue) );
-        $result = ReadingsVal($name,$userReading,$value);
+        $result = ReadingsVal($name,$reading,$value);
         $result += $value - $oldvalue if( $value > $oldvalue );
       }
-      readingsBulkUpdate($hash,$userReading,$result,1) if(defined($result));
+      readingsBulkUpdate($hash,$reading,$result,1) if(defined($result));
       # store value
-      $hash->{'.userReadings'}{$userReading}{TIME}= $hash->{".updateTimestamp"};
-      $hash->{'.userReadings'}{$userReading}{t}= $hash->{".updateTime"};
-      $hash->{'.userReadings'}{$userReading}{value}= $value;
+      $userReading->{TIME}= $hash->{".updateTimestamp"};
+      $userReading->{t}= $hash->{".updateTime"};
+      $userReading->{value}= $value;
     }
   }
   evalStateFormat($hash);


der diff ändert zwar mehr als drei zeilen unterm strich ist das ergebniss aber etwas kürzer und es sollte auch effizienter sein.

gruss
  andre
Titel: Antw:Reihenfolge der Berechnung von userReadings
Beitrag von: rudolfkoenig am 22 Februar 2016, 09:18:15
Andre: kannst du bitte dein Patch gegen die aktuelle Version erstellen? Ich kriege ein Haufen Hunk FAILED:
Zitatpatching file fhem.pl
Hunk #3 FAILED at 2491.
Hunk #4 FAILED at 3867.
Hunk #5 FAILED at 3904.
und will nicht deine Arbeit verdoppeln.
Titel: Antw:Reihenfolge der Berechnung von userReadings
Beitrag von: justme1968 am 22 Februar 2016, 09:25:47
der patch war gegen die aktuelle version. schau mal ob es mit dem angehängten file besser geht.

Titel: Antw:Reihenfolge der Berechnung von userReadings
Beitrag von: rudolfkoenig am 22 Februar 2016, 09:39:31
Dieser Patch funktioniert einwandfrei.
Habs kurz getestet und eingecheckt.