diff --git a/fhem/CHANGED b/fhem/CHANGED index 1571d8ae0..3bab4acd2 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -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) diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html index 4801074a1..feb89688f 100644 --- a/fhem/docs/commandref_frame.html +++ b/fhem/docs/commandref_frame.html @@ -384,18 +384,30 @@ A line ending with \ will be concatenated with the next one, so long lines
  • userReadings
    - A comma-separated list of user-defined readings. Each definition has the form - <reading> { <perl code> }. After a single or bulk + 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 myPowerMeter userReadings power { ReadingsVal("myPowerMeter","count.A",0)/1250.0;; }
    - attr myMultiMeter userReadings power1 { ReadingsVal("myMultiMeter","count.A",0)/1250.0;; }, - power2 { ReadingsVal("myMultiMeter","count.B",0)/1250.0;; } + 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: +
    + 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!

  • -
    diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html index f5986fef1..c5b070058 100644 --- a/fhem/docs/commandref_frame_DE.html +++ b/fhem/docs/commandref_frame_DE.html @@ -394,16 +394,29 @@ Zeilen erstreckende Befehle, indem man keine \ am Zeilenende eingeben muss.

  • userReadings
    - A comma-separated list of user-defined readings. Each definition has the form - <reading> { <perl code> }. After a single or bulk + 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 myPowerMeter userReadings power { ReadingsVal("myPowerMeter","count.A",0)/1250.0;; }
    - attr myMultiMeter userReadings power1 { ReadingsVal("myMultiMeter","count.A",0)/1250.0;; }, - power2 { ReadingsVal("myMultiMeter","count.B",0)/1250.0;; } + 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: +
    + 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!

  • diff --git a/fhem/fhem.pl b/fhem/fhem.pl index 0a1eefa4a..2da250eb5 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -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"};