2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 06:39:11 +00:00

modifiers for userReadings

git-svn-id: https://svn.fhem.de/fhem/trunk@2679 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
borisneubert 2013-02-10 09:57:02 +00:00
parent f09c7e91f3
commit b1c0e6064f
4 changed files with 77 additions and 23 deletions

View File

@ -55,6 +55,7 @@
OWFS
- feature: stateFormat (readingsFn modules) and showInternalValues attributes
- feature: new readingsFn modules: FS20 CUL_WS HMS CUL_EM CUL_TX EnOcean ZWave
- change: BS, USF1000, ECMDDevice, Weather, dummy migrated to readingsFN (Boris)
- feature: telnet client mode
- bugfix: FHEMWEB longpoll misses initial state change (HM: set_on vs. on)
- change: 20_OWFS.pm, 21_OWTEMP modules flagged as "deprecated". These
@ -66,8 +67,8 @@
- feature: added new command 'notice'. (M. Fischer)
- change: update supports the display and confirmation of system messages
via the new notice command (M. Fischer)
- change: BS, USF1000, dummy migrated to readingsFN (Boris)
- feature: added new set commands and basicauth to 49_IPCAM.pm (M. Fischer)
- feature: userReadings
- feature: average supports more than one value in combined readings (T:x H:y)

View File

@ -384,18 +384,30 @@ A line ending with \ will be concatenated with the next one, so long lines
<a name="userReadings"></a>
<li>userReadings<br>
A comma-separated list of user-defined readings. Each definition has the form
<code>&lt;reading&gt; { &lt;perl code&gt; }</code>. After a single or bulk
A comma-separated list of definitions of user-defined readings. Each definition has the form
<code>&lt;reading&gt; [&lt;modifier&gt;] { &lt;perl code&gt; }</code>. After a single or bulk
readings update, the user-defined readings are set by evaluating the <a href="#perl">
perl code</a>
<code>{ &lt;perl code&gt; }</code> for all definitions and setting the value of
the respective user-defined reading <code>&lt;reading&gt;</code> to the result.<br><br>
Examples:<br>
<code>attr myPowerMeter userReadings power { ReadingsVal("myPowerMeter","count.A",0)/1250.0;; }</code><br>
<code>attr myMultiMeter userReadings power1 { ReadingsVal("myMultiMeter","count.A",0)/1250.0;; },
power2 { ReadingsVal("myMultiMeter","count.B",0)/1250.0;; }</code>
<code>attr myEnergyMeter userReadings energy { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }</code><br>
<code>attr myMultiMeter userReadings energy1 { ReadingsVal("myMultiMeter","counters.A",0)/1250.0;; },
energy2 { ReadingsVal("myMultiMeter","counters.B",0)/1250.0;; }</code>
<br><br>
<code>&lt;modifier&gt;</code> can take one of these values:
<ul>
<li>none: the same as it would not have been given at all.</li>
<li>difference: the reading is set to the difference between the current and the previously evaluated value.</li>
<li>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.</li>
</ul><br>
Example:<br>
<code>attr myPowerMeter userReadings power differential { ReadingsVal("myPowerMeter","counters.A",0)/1250.0;; }</code><br><br>
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!
</li><br>
</ul>
<br>

View File

@ -394,16 +394,29 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.</p>
<a name="userReadings"></a>
<li>userReadings<br>
A comma-separated list of user-defined readings. Each definition has the form
<code>&lt;reading&gt; { &lt;perl code&gt; }</code>. After a single or bulk
A comma-separated list of definitions of user-defined readings. Each definition has the form
<code>&lt;reading&gt; [&lt;modifier&gt;] { &lt;perl code&gt; }</code>. After a single or bulk
readings update, the user-defined readings are set by evaluating the <a href="#perl">
perl code</a>
<code>{ &lt;perl code&gt; }</code> for all definitions and setting the value of
the respective user-defined reading <code>&lt;reading&gt;</code> to the result.<br><br>
Examples:<br>
<code>attr myPowerMeter userReadings power { ReadingsVal("myPowerMeter","count.A",0)/1250.0;; }</code><br>
<code>attr myMultiMeter userReadings power1 { ReadingsVal("myMultiMeter","count.A",0)/1250.0;; },
power2 { ReadingsVal("myMultiMeter","count.B",0)/1250.0;; }</code>
<code>attr myEnergyMeter userReadings energy { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }</code><br>
<code>attr myMultiMeter userReadings energy1 { ReadingsVal("myMultiMeter","counters.A",0)/1250.0;; },
energy2 { ReadingsVal("myMultiMeter","counters.B",0)/1250.0;; }</code>
<br><br>
<code>&lt;modifier&gt;</code> can take one of these values:
<ul>
<li>none: the same as it would not have been given at all.</li>
<li>difference: the reading is set to the difference between the current and the previously evaluated value.</li>
<li>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.</li>
</ul><br>
Example:<br>
<code>attr myPowerMeter userReadings power differential { ReadingsVal("myPowerMeter","counters.A",0)/1250.0;; }</code><br><br>
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!
</li><br>
</ul>

View File

@ -1809,24 +1809,28 @@ CommandAttr($$)
if($a[1] eq "userReadings") {
my %userReadings;
# myReading1 { codecodecode1 }, myReading2 { codecodecode2 }, ...
# myReading1 [modifier1] { codecodecode1 }, myReading2 [modifier2] { codecodecode2 }, ...
my $arg= $a[2];
my $regexi= '\s*(\w+)\s+({.*?})\s*'; # matches myReading1 { codecode1 }
my $regexi= '\s*(\w+)\s+((\w+)\s+)?({.*?})\s*'; # matches myReading1 { codecode1 }
my $regexo= '^(' . $regexi . ')(,\s*(.*))*$';
#Debug "arg is $arg";
while($arg =~ /$regexo/) {
my $userReading= $2;
my $perlCode= $3;
#Debug sprintf("userReading %s has perlCode %s",$userReading,$perlCode);
$userReadings{$userReading}= $perlCode;
$arg= defined($5) ? $5 : "";
my $modifier= $4 ? $4 : "none";
my $perlCode= $5;
#Debug sprintf("userReading %s has perlCode %s with modifier %s",$userReading,$perlCode,$modifier);
if(grep { /$modifier/ } qw(none difference differential)) {
$userReadings{$userReading}{modifier}= $modifier;
$userReadings{$userReading}{perlCode}= $perlCode;
} else {
push @rets, "$sdev: unknown modifier $modifier for userReading $userReading, this userReading will be ignored";
}
$arg= defined($7) ? $7 : "";
}
$hash->{fhem}{'.userReadings'}= \%userReadings;
}
if($a[1] eq "IODev" && (!$a[2] || !defined($defs{$a[2]}))) {
@ -2990,6 +2994,7 @@ readingsBeginUpdate($)
# get timestamp
my $now = TimeNow();
$hash->{".updateTime"} = time(); # in seconds since the epoch
$hash->{".updateTimestamp"} = $now;
my $attreocr= AttrVal($name, "event-on-change-reading", undef);
@ -3053,19 +3058,42 @@ readingsEndUpdate($$)
if(defined($hash->{fhem}{'.userReadings'})) {
my %userReadings= %{$hash->{fhem}{'.userReadings'}};
foreach my $userReading (keys %userReadings) {
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 $value= eval $userReadings{$userReading};
# evaluate perl code
my $value= eval $perlCode;
my $result;
# store result
if($@) {
$value = "Error evaluating $name userReading $userReading: $@";
Log 1, $value;
}
readingsBulkUpdate($hash,$userReading,$value,1);
$result= $value;
} elsif($modifier eq "none") {
$result= $value;
} elsif($modifier eq "difference") {
$result= $value - $oldvalue if(defined($oldvalue));
} elsif($modifier eq "differential") {
my $deltav= $value - $oldvalue if(defined($oldvalue));
my $deltat= $hash->{".updateTime"} - $oldt if(defined($oldt));
if(defined($deltav) && defined($deltat) && ($deltat>= 1.0)) {
$result= $deltav/$deltat;
}
}
readingsBulkUpdate($hash,$userReading,$result,1) if(defined($result));
# store value
$hash->{fhem}{'.userReadings'}{$userReading}{TIME}= $hash->{".updateTimestamp"};
$hash->{fhem}{'.userReadings'}{$userReading}{t}= $hash->{".updateTime"};
$hash->{fhem}{'.userReadings'}{$userReading}{value}= $value;
}
}
evalStateFormat($hash);
# turn off updating mode
delete $hash->{".updateTimestamp"};
delete $hash->{".updateTime"};
delete $hash->{".attreour"};
delete $hash->{".attreocr"};