diff --git a/fhem/CHANGED b/fhem/CHANGED
index 03bd5b736..e94f45cd8 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,7 +1,9 @@
# Add changes at the top of the list. Keep it in ASCII
- SVN
+ - feature: userReadings may have a filter
- feature: HUEBridge: allow starting of bridge firmware update
- - change: EnOcean: profil PM101 changed, old profiles FAH, FBH, FTF, SR04 removed
+ - change: EnOcean: profil PM101 changed, old profiles FAH, FBH, FTF, SR04
+ removed
- feature: TCM: new attr blockSenderID:
Block receiving telegrams with a TCM SenderID sent by repeaters
- feature: TCM: For TCM120 Transceiver now the transmission of RPS and 4BS
diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html
index d8e100879..5e14ea9a5 100644
--- a/fhem/docs/commandref_frame.html
+++ b/fhem/docs/commandref_frame.html
@@ -396,29 +396,47 @@ A line ending with \ will be concatenated with the next one, so long lines
userReadings
- A comma-separated list of definitions of user-defined readings. Each definition has the form
- <reading> [<modifier>] { <perl code> }
. After a single or bulk
- readings update, the user-defined readings are set by evaluating the
- perl code
- { <perl code> }
for all definitions and setting the value of
- the respective user-defined reading <reading>
to the result.
- Examples:
- attr myEnergyMeter userReadings energy { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }
- attr myMultiMeter userReadings energy1 { ReadingsVal("myMultiMeter","counters.A",0)/1250.0;; },
- energy2 { ReadingsVal("myMultiMeter","counters.B",0)/1250.0;; }
-
+ A comma-separated list of definitions of user-defined readings. Each
+ definition has the form:
+
+
+ <reading>[:<trigger>] [<modifier>] { <perl code> }
+
+
+ After a single or bulk readings update, the user-defined readings are set
+ by evaluating the perl code { <perl code>
+ }
for all definitions and setting the value of the respective
+ user-defined reading <reading>
to the result. If
+ <trigger> is given, then all processing for this specific user
+ reading is only done if one of the just updated "reading: value"
+ combinations matches <trigger>, which is treated as a regexp.
+
+ Examples:
+
+ attr myEnergyMeter userReadings energy
+ { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }
+ attr myMultiMeter userReadings
+ energy1:counters.A { ReadingsVal("myMultiMeter","counters.A",0)/1250.0;; },
+ energy2:counters.B { ReadingsVal("myMultiMeter","counters.B",0)/1250.0;; }
+
<modifier>
can take one of these values:
- none: the same as it would not have been given at all.
- - difference: the reading is set to the difference between the current and the previously evaluated value.
- - differential: the reading is set to the difference between the current and the previously evaluated value divided
- by the time in seconds between the current and the previous evaluation. Granularity of time is one second. No
- value is calculated if the time past is below one second. Useful to calculate rates.
-
+ difference: the reading is set to the difference between the current
+ and the previously evaluated value.
+ differential: the reading is set to the difference between the
+ current and the previously evaluated value divided by the time in
+ seconds between the current and the previous evaluation. Granularity
+ of time is one second. No value is calculated if the time past is
+ below one second. Useful to calculate rates.
+
Example:
- attr myPowerMeter userReadings power differential { ReadingsVal("myPowerMeter","counters.A",0)/1250.0;; }
- Note: user readings with modifiers difference and differential store the calculated values internally. The user reading is
- set earliest at the second evaluation. Beware of stale values when changing definitions!
+ attr myPowerMeter userReadings power
+ differential { ReadingsVal("myPowerMeter","counters.A",0)/1250.0;; }
+
+ Note: user readings with modifiers difference and differential store the
+ calculated values internally. The user reading is set earliest at the
+ second evaluation. Beware of stale values when changing definitions!
diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html
index a0f50dc13..138f0d4f5 100644
--- a/fhem/docs/commandref_frame_DE.html
+++ b/fhem/docs/commandref_frame_DE.html
@@ -398,31 +398,49 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.
userReadings
- A comma-separated list of definitions of user-defined readings. Each definition has the form
- <reading> [<modifier>] { <perl code> }
. After a single or bulk
- readings update, the user-defined readings are set by evaluating the
- perl code
- { <perl code> }
for all definitions and setting the value of
- the respective user-defined reading <reading>
to the result.
- Examples:
- attr myEnergyMeter userReadings energy { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }
- attr myMultiMeter userReadings energy1 { ReadingsVal("myMultiMeter","counters.A",0)/1250.0;; },
- energy2 { ReadingsVal("myMultiMeter","counters.B",0)/1250.0;; }
-
- <modifier>
can take one of these values:
+ Komma getrennte Liste von benutzerdefinierten Readings. Jede Definition hat
+ folgendes Format:
+
+ <reading>[:<trigger>] [<modifier>] { <perl code> }
+
+ Diese benutzerdefinierte Readings werden bei jeder Aktualisierung der
+ Gerätereadings gesetzt, indem das spezifizierte perl
+ code { <perl code> }
ausgeführt wird, und
+ dessen Wert dem Reading zugewiesen wird.
+
+ Falls <trigger> spezifiziert ist, dann findet diese Ausführung
+ nur dann statt, falls einer der aktualisierten Readings dem regexp
+ <trigger> entspricht (matched).
+ Beispiele:
+
+ attr myEnergyMeter userReadings energy
+ { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }
+ attr myMultiMeter userReadings
+ energy1:counters.A {ReadingsVal("myMultiMeter","counters.A",0)/1250.0},
+ energy2:counters.B {ReadingsVal("myMultiMeter","counters.B",0)/1250.0}
+
+ <modifier>
kann die folgenden Werte haben:
- - none: the same as it would not have been given at all.
- - difference: the reading is set to the difference between the current and the previously evaluated value.
- - differential: the reading is set to the difference between the current and the previously evaluated value divided
- by the time in seconds between the current and the previous evaluation. Granularity of time is one second. No
- value is calculated if the time past is below one second. Useful to calculate rates.
-
- Example:
- attr myPowerMeter userReadings power differential { ReadingsVal("myPowerMeter","counters.A",0)/1250.0;; }
- Note: user readings with modifiers difference and differential store the calculated values internally. The user reading is
- set earliest at the second evaluation. Beware of stale values when changing definitions!
+ none: als ob man es gar nicht spezifiziert hätte.
+ difference: das Reading wird auf die Differenz zw. dem aktuellen und
+ dem vorherigen Wert gesetzt.
+ differential: das Reading wird auf die Differenz zw. dem aktuellen und
+ dem vorherigen Wert, geteilt durch die Sekunden zw. der aktuellen Zeit
+ und der letzten Auswertung, sekundengenau. Kein Wert wird berechnet,
+ falls der Unterschied unter eine Sekunde liegt.
+
+
+ Beispiel:
+
+ attr myPowerMeter userReadings power differential
+ { ReadingsVal("myPowerMeter","counters.A",0)/1250.0}
+
+ Achtung: Falls difference oder differential spezifiziert ist, dann werden
+ für die Berechnung ältere Werte benötigt, d.h. der Wert wird
+ frühestens beim zweiten Änderung gesetzt.
+
diff --git a/fhem/fhem.pl b/fhem/fhem.pl
index 7872029d4..4f4cf5681 100755
--- a/fhem/fhem.pl
+++ b/fhem/fhem.pl
@@ -1459,7 +1459,6 @@ CommandDeleteAttr($$)
$a[0] = $sdev;
if($a[1] eq "userReadings") {
- #Debug "Deleting userReadings for $sdev";
delete($defs{$sdev}{'.userReadings'});
}
@@ -1868,26 +1867,32 @@ CommandAttr($$)
if($a[1] eq "userReadings") {
my %userReadings;
- # myReading1 [modifier1] { codecodecode1 }, myReading2 [modifier2] { codecodecode2 }, ...
+ # myReading1[:trigger1] [modifier1] { codecodecode1 }, ...
my $arg= $a[2];
- my $regexi= '\s*(\w+)\s+((\w+)\s+)?({.*?})\s*'; # matches myReading1 { codecode1 }
+ # matches myReading1[:trigger2] { codecode1 }
+ my $regexi= '\s*(\w+)(:\S*)?\s+((\w+)\s+)?({.*?})\s*';
my $regexo= '^(' . $regexi . ')(,\s*(.*))*$';
- #Debug "arg is $arg";
+ #Log 1, "arg is $arg";
while($arg =~ /$regexo/) {
my $userReading= $2;
- my $modifier= $4 ? $4 : "none";
- my $perlCode= $5;
- #Debug sprintf("userReading %s has perlCode %s with modifier %s",$userReading,$perlCode,$modifier);
+ my $trigger= $3 ? $3 : undef;
+ my $modifier= $5 ? $5 : "none";
+ my $perlCode= $6;
+ #Log 1, sprintf("userReading %s has perlCode %s with modifier %s%s",
+ # $userReading,$perlCode,$modifier,$trigger?" and trigger $trigger":"");
if(grep { /$modifier/ } qw(none difference differential)) {
+ $trigger =~ s/^:// if($trigger);
+ $userReadings{$userReading}{trigger}= $trigger;
$userReadings{$userReading}{modifier}= $modifier;
$userReadings{$userReading}{perlCode}= $perlCode;
} else {
- push @rets, "$sdev: unknown modifier $modifier for userReading $userReading, this userReading will be ignored";
+ push @rets, "$sdev: unknown modifier $modifier for ".
+ "userReading $userReading, this userReading will be ignored";
}
- $arg= defined($7) ? $7 : "";
+ $arg= defined($8) ? $8 : "";
}
$hash->{'.userReadings'}= \%userReadings;
}
@@ -2915,7 +2920,7 @@ addEvent($$)
sub
getInterfaces($) {
my ($hash)= @_;
- #Debug "getInterfaces(" . $hash->{NAME} .")= " . $hash->{internals}{interfaces};
+ #Debug "getInterfaces(" . $hash->{NAME} .")= ".$hash->{internals}{interfaces};
if(defined($hash->{internals}{interfaces})) {
return split(/:/, $hash->{internals}{interfaces});
} else {
@@ -3133,6 +3138,13 @@ readingsEndUpdate($$)
if(defined($hash->{'.userReadings'})) {
my %userReadings= %{$hash->{'.userReadings'}};
foreach my $userReading (keys %userReadings) {
+
+ my $trigger = $userReadings{$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};