diff --git a/fhem/FHEM/01_FHEMWEB.pm b/fhem/FHEM/01_FHEMWEB.pm index 145c2fc70..ec6f50ce4 100644 --- a/fhem/FHEM/01_FHEMWEB.pm +++ b/fhem/FHEM/01_FHEMWEB.pm @@ -3112,6 +3112,7 @@ FW_Notify($$) #Add READINGS if($events) { # It gets deleted sometimes (?) my $tn = TimeNow(); + my $ct = $dev->{CHANGETIME}; my $max = int(@{$events}); for(my $i = 0; $i < $max; $i++) { if($events->[$i] !~ /: /) { @@ -3127,7 +3128,8 @@ FW_Notify($$) next if($readingName !~ m/^[A-Za-z\d_\.\-\/:]+$/); # Forum #70608,70844 push @data, FW_longpollInfo($h->{fmt}, "$dn-$readingName", $readingVal,$readingVal); - push @data, FW_longpollInfo($h->{fmt}, "$dn-$readingName-ts", $tn, $tn); + my $t = (($ct && $ct->[$i]) ? $ct->[$i] : $tn); + push @data, FW_longpollInfo($h->{fmt}, "$dn-$readingName-ts", $t, $t); } } } diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html index 605b36b3c..69b78ef7d 100644 --- a/fhem/docs/commandref_frame.html +++ b/fhem/docs/commandref_frame.html @@ -1279,12 +1279,14 @@ The following local attributes are used by a wider range of devices: <a name="setreading"></a> <h3>setreading</h3> <ul> - <code>setreading <devspec> <reading> <value></code> + <code>setreading <devspec> [YYYY-MM-DD HH:MM:SS] <reading> + <value></code> <br><br> Set the reading <reading> for the device <code><name></code> to <value> without sending out commands to the device, but triggering events and eventMap/stateFormat transformations as usual. See the set - command documentation for replacement description. + command documentation for replacement description.<br> + If the timespec is omitted (default) the current time will be used. <br><br> Examples: <ul> diff --git a/fhem/docs/commandref_frame_DE.html b/fhem/docs/commandref_frame_DE.html index 0286f12b7..45c533bd1 100644 --- a/fhem/docs/commandref_frame_DE.html +++ b/fhem/docs/commandref_frame_DE.html @@ -1361,12 +1361,14 @@ Die folgenden lokalen Attribute werden von mehreren Geräten verwendet: <a name="setreading"></a> <h3>setreading</h3> <ul> - <code>setreading <devspec> <reading> <value></code> + <code>setreading <devspec> [YYYY-MM-DD HH:MM:SS] <reading> + <value></code> <br><br> Der Befehl setzt das Reading <reading> auf den Wert <value> ohne Signale an das betroffene Gerät zu senden, generiert aber Ereignisse und die übliche eventMap und stateFormat Umwandlung wird auch - durchgeführt. + durchgeführt.<br> + Falls keine Zeit spezifiziert wurde, wird die aktuelle Uhrzeit verwendet. <br> Siehe den Abschnitt über <a href="#devspec">Geräte-Spezifikation</a> für Details der <devspec> und die Beschreibung des set Befehls diff --git a/fhem/fhem.pl b/fhem/fhem.pl index 7e140be5d..7647f7896 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -111,7 +111,7 @@ sub TimeNow(); sub Value($); sub WriteStatefile(); sub XmlEscape($); -sub addEvent($$); +sub addEvent($$;$); sub addToDevAttrList($$); sub applyGlobalAttrFromEnv(); sub delFromDevAttrList($$); @@ -150,7 +150,7 @@ sub perlSyntaxCheck($%); sub readingsBeginUpdate($); sub readingsBulkUpdate($$$@); sub readingsEndUpdate($$); -sub readingsSingleUpdate($$$$); +sub readingsSingleUpdate($$$$;$); sub readingsDelete($$); sub redirectStdinStdErr(); sub rejectDuplicate($$$); @@ -457,7 +457,8 @@ my %ra = ( "set" => { Fn=>"CommandSet", Hlp=>"<devspec> <type-specific>,transmit code for <devspec>" }, "setreading" => { Fn=>"CommandSetReading", - Hlp=>"<devspec> <reading> <value>,set reading for <devspec>" }, + Hlp=>"<devspec> [YYYY-MM-DD HH:MM:SS] <reading> <value>,". + "set reading for <devspec>" }, "setstate"=> { Fn=>"CommandSetstate", Hlp=>"<devspec> <state>,set the state shown in the command list" }, "setuuid" => { Fn=>"CommandSetuuid", Hlp=>"" }, @@ -2416,9 +2417,16 @@ sub CommandSetReading($$) { my ($cl, $def) = @_; + my $timestamp; + + if($def =~ m/^([^ ]+) +(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d) +([^ ]+) +(.*)$/) { + $def = "$1 $3 $4"; + $timestamp = $2; + } my @a = split(" ", $def, 3); - return "Usage: setreading <name> <reading> <value>\n$namedef" if(@a != 3); + return "Usage: setreading <name> [YYYY-MM-DD HH:MM:SS] <reading> <value>\n". + $namedef if(@a != 3); my $err; my @b = @a; @@ -2443,7 +2451,7 @@ CommandSetReading($$) Log 1, "'setreading $def' called form userReadings is prohibited"; return; } else { - readingsSingleUpdate($hash, $b1, $b[2], 1); + readingsSingleUpdate($hash, $b1, $b[2], 1, $timestamp); } } return join("\n", @rets); @@ -3732,6 +3740,12 @@ DoTrigger($$@) ################ # Inform if($hash->{CHANGED}) { # It gets deleted sometimes (?) + my $tn = $now; + if($attr{global}{mseclog}) { + my ($seconds, $microseconds) = gettimeofday(); + $tn .= sprintf(".%03d", $microseconds/1000); + } + my $ct = $hash->{CHANGETIME}; foreach my $c (keys %inform) { my $dc = $defs{$c}; if(!$dc || $dc->{NR} != $inform{$c}{NR}) { @@ -3739,18 +3753,14 @@ DoTrigger($$@) next; } next if($inform{$c}{type} eq "raw"); - my $tn = $now; - if($attr{global}{mseclog}) { - my ($seconds, $microseconds) = gettimeofday(); - $tn .= sprintf(".%03d", $microseconds/1000); - } my $re = $inform{$c}{regexp}; my $events = deviceEvents($hash, $inform{$c}{type} =~ m/WithState/); $max = int(@{$events}); for(my $i = 0; $i < $max; $i++) { my $event = $events->[$i]; + my $t = (($ct && $ct->[$i]) ? $ct->[$i] : $tn); next if($re && !($dev =~ m/$re/ || "$dev:$event" =~ m/$re/)); - addToWritebuffer($dc,($inform{$c}{type} eq "timer" ? "$tn " : ""). + addToWritebuffer($dc,($inform{$c}{type} eq "timer" ? "$t " : ""). "$hash->{TYPE} $dev $event\n"); } } @@ -4612,10 +4622,14 @@ setReadingsVal($$$$) } sub -addEvent($$) +addEvent($$;$) { - my ($hash,$event) = @_; + my ($hash,$event,$timestamp) = @_; push(@{$hash->{CHANGED}}, $event); + if($timestamp) { + $hash->{CHANGETIME} = [] if(!defined($hash->{CHANGETIME})); + $hash->{CHANGETIME}->[@{$hash->{CHANGED}}-1] = $timestamp; + } } sub @@ -4817,7 +4831,7 @@ readingsBulkUpdateIfChanged($$$@) # Forum #58797 sub readingsBulkUpdate($$$@) { - my ($hash,$reading,$value,$changed)= @_; + my ($hash,$reading,$value,$changed,$timestamp)= @_; my $name= $hash->{NAME}; return if(!defined($reading) || !defined($value)); @@ -4947,7 +4961,8 @@ readingsBulkUpdate($$$@) } - setReadingsVal($hash, $reading, $value, $hash->{".updateTimestamp"}) + setReadingsVal($hash, $reading, $value, + $timestamp ? $timestamp : $hash->{".updateTimestamp"}) if($update_timestamp); my $rv = "$reading: $value"; @@ -4956,7 +4971,7 @@ readingsBulkUpdate($$$@) $rv = $value; $hash->{CHANGEDWITHSTATE} = []; } - addEvent($hash, $rv); + addEvent($hash, $rv, $timestamp); } return $rv; } @@ -4965,11 +4980,11 @@ readingsBulkUpdate($$$@) # this is a shorthand call # sub -readingsSingleUpdate($$$$) +readingsSingleUpdate($$$$;$) { - my ($hash,$reading,$value,$dotrigger)= @_; + my ($hash,$reading,$value,$dotrigger,$timestamp)= @_; readingsBeginUpdate($hash); - my $rv = readingsBulkUpdate($hash,$reading,$value); + my $rv = readingsBulkUpdate($hash, $reading, $value, undef, $timestamp); readingsEndUpdate($hash,$dotrigger); return $rv; }