Reihenfolge der Berechnung von userReadings

Begonnen von Happy Fhem User, 21 Februar 2016, 15:08:17

Vorheriges Thema - Nächstes Thema

Happy Fhem User

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 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)) {

rudolfkoenig


justme1968

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
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

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.

justme1968

der patch war gegen die aktuelle version. schau mal ob es mit dem angehängten file besser geht.

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Dieser Patch funktioniert einwandfrei.
Habs kurz getestet und eingecheckt.