2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 16:56:54 +00:00

fhem.pl: sleep can now wait for an event (Forum #100306)

git-svn-id: https://svn.fhem.de/fhem/trunk@19374 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2019-05-11 17:48:03 +00:00
parent 6e8848d460
commit ae6859a3bd
4 changed files with 72 additions and 31 deletions

View File

@ -67,7 +67,8 @@ notify_Define($$)
$hash->{".COMMAND"} = $command; $hash->{".COMMAND"} = $command;
my $doTrigger = ($name !~ m/^$re$/); # Forum #34516 my $doTrigger = ($name !~ m/^$re$/); # Forum #34516
readingsSingleUpdate($hash, "state", "active", $doTrigger); readingsSingleUpdate($hash, "state", "active", $doTrigger)
if(!$hash->{TEMPORARY});
InternalTimer(0, sub(){ notifyRegexpChanged($hash, $re); }, $hash); InternalTimer(0, sub(){ notifyRegexpChanged($hash, $re); }, $hash);
return undef; return undef;

View File

@ -737,7 +737,7 @@ The following local attributes are used by a wider range of devices:
<ul> <ul>
<code>cancel [&lt;id&gt; [quiet]]</code> <code>cancel [&lt;id&gt; [quiet]]</code>
<br><br> <br><br>
Cancels a named <a href="#sleep">sleep</a>. List named sleeps or cancel a named <a href="#sleep">sleep</a>.
</ul> </ul>
<!-- cancel end --> <!-- cancel end -->
@ -1357,12 +1357,17 @@ The following local attributes are used by a wider range of devices:
<a name="sleep"></a> <a name="sleep"></a>
<h3>sleep</h3> <h3>sleep</h3>
<ul> <ul>
<code>sleep &lt;sec&gt; [&lt;id&gt;] [quiet]</code> <code>sleep &lt;sec|timespec|regex&gt; [&lt;id&gt;] [quiet]</code>
<br><br> <br><br>
sleep followed by another command is comparable to a nameless <a sleep followed by another command is comparable to a nameless <a
href="#at">at</a>, it executes the following commands after waiting the href="#at">at</a> or <a href="#notify">notify</a>, it executes the
specified time. The unit is seconds, with millisecond accuracy, as you can following commands after waiting for the specified time or an event matching
specify decimal places.<br><br> &lt;regex&gt;. The delay can be given<ul>
<li>in seconds, with millisecond accuracy, as you can specify decimal places,
</li>
<li>as a timespec (HH:MM or HH::MM::SS or {perlfunc})</li>
<li>or as a regex (devicename or devicename:event)</li></ul><br>
A sleep with an &lt;id&gt; will replace a sleep with the same &lt;id&gt; A sleep with an &lt;id&gt; will replace a sleep with the same &lt;id&gt;
and can be canceled by <a href="#cancel">cancel</a>. and can be canceled by <a href="#cancel">cancel</a>.

View File

@ -757,7 +757,7 @@ Die folgenden lokalen Attribute werden von mehreren Ger&auml;ten verwendet:
<ul> <ul>
<code>cancel [&lt;id&gt; [quiet]]</code> <code>cancel [&lt;id&gt; [quiet]]</code>
<br><br> <br><br>
Entfernt ein benanntes <a href="#sleep">sleep</a>. Listet benannte sleeps oder entfernt ein benanntes <a href="#sleep">sleep</a>.
</ul> </ul>
<!-- cancel end --> <!-- cancel end -->
@ -1444,13 +1444,18 @@ Die folgenden lokalen Attribute werden von mehreren Ger&auml;ten verwendet:
<a name="sleep"></a> <a name="sleep"></a>
<h3>sleep</h3> <h3>sleep</h3>
<ul> <ul>
<code>sleep &lt;sec&gt; [&lt;id&gt;] [quiet]</code> <code>sleep &lt;sec|timespec|suchmuster&gt; [&lt;id&gt;] [quiet]</code>
<br><br> <br><br>
sleep gefolgt von weiteren Befehlen ist vergleichbar mit einem namenlosen <a sleep gefolgt von weiteren Befehlen ist vergleichbar mit einem namenlosen <a
href="#at">at</a> Kommando, es f&uuml;hrt die nachfolgenden Befehle aus, href="#at">at</a> oder <a href="#notify">notify</a> Kommando, es f&uuml;hrt
nachdem es die spezifizierte Zeitspanne gewartet hat. Die Einheit ist die nachfolgenden Befehle aus, nachdem es die spezifizierte Zeitspanne
Sekunde, Millisekunden genau, da man Nachkommastellen spezifizieren gewartet hat bzw. ein Event welches dem &lt;suchmuster&gt; entspricht
kann.<br><br> aufgetreten ist. Die verz&ouml;gerung kann<ul>
<li>in Sekunden (Millisekunden genau, da man Nachkommastellen spezifizieren
kann)</li>
<li> als timespec (HH:MM or HH::MM::SS oder {perlfunc})</li>
<li>oder als suchmuster (Ger&auml;tename oder Ger&auml;tename:Event)</li>
</ul> angegeben werden.<br>
Ein sleep mit einer &lt;id&gt; ersetzt ein sleep mit der gleichen &lt;id&gt; Ein sleep mit einer &lt;id&gt; ersetzt ein sleep mit der gleichen &lt;id&gt;
and can mit <a href="#cancel">cancel</a> entfernt werden. and can mit <a href="#cancel">cancel</a> entfernt werden.

View File

@ -106,7 +106,6 @@ sub SemicolonEscape($);
sub SignalHandling(); sub SignalHandling();
sub TimeNow(); sub TimeNow();
sub Value($); sub Value($);
sub WakeUpFn($);
sub WriteStatefile(); sub WriteStatefile();
sub XmlEscape($); sub XmlEscape($);
sub addEvent($$); sub addEvent($$);
@ -2059,6 +2058,7 @@ CommandDefine($$)
if($currcfgfile ne AttrVal("global", "configfile", "") && if($currcfgfile ne AttrVal("global", "configfile", "") &&
!configDBUsed()); !configDBUsed());
$hash{CL} = $cl; $hash{CL} = $cl;
$hash{TEMPORARY} = 1 if($temporary);
# If the device wants to issue initialization gets/sets, then it needs to be # If the device wants to issue initialization gets/sets, then it needs to be
# in the global hash. # in the global hash.
@ -2073,7 +2073,6 @@ CommandDefine($$)
} else { } else {
delete $hash{CL}; delete $hash{CL};
$hash{TEMPORARY} = 1 if($temporary);
foreach my $da (sort keys (%defaultattr)) { # Default attributes foreach my $da (sort keys (%defaultattr)) { # Default attributes
CommandAttr($cl, "$name $da $defaultattr{$da}"); CommandAttr($cl, "$name $da $defaultattr{$da}");
} }
@ -2082,8 +2081,10 @@ CommandDefine($$)
$modules{$m}{NotifyOrderPrefix} : "50-") . $name; $modules{$m}{NotifyOrderPrefix} : "50-") . $name;
} }
%ntfyHash = (); %ntfyHash = ();
addStructChange("define", $name, $def); if(!$temporary && !$init_done) {
DoTrigger("global", "DEFINED $name", 1) if($init_done); addStructChange("define", $name, $def);
DoTrigger("global", "DEFINED $name", 1);
}
} }
return ($ret && $ignoreErr ? return ($ret && $ignoreErr ?
"Cannot define $name, remove -ignoreErr for details" : $ret); "Cannot define $name, remove -ignoreErr for details" : $ret);
@ -3133,15 +3134,19 @@ CommandTrigger($$)
##################################### #####################################
sub sub
WakeUpFn($) sleep_WakeUpFn($)
{ {
my $h = shift; my $id = shift;
delete $sleepers{$h->{id}} if( $h->{id} ); my $h = $sleepers{$id};
return if(!$h);
delete $sleepers{$id};
CommandDelete($h->{cl}, $h->{name}) if(!defined($h->{sec}));
$evalSpecials = $h->{evalSpecials}; $evalSpecials = $h->{evalSpecials};
my $ret = AnalyzeCommandChain($h->{cl}, $h->{cmd}); my $ret = AnalyzeCommandChain($h->{cl}, $h->{cmd});
Log 2, "After sleep: $ret" if($ret && !$h->{quiet}); Log 2, "After sleep: $ret" if($ret && !$h->{quiet});
} }
sub sub
CommandCancel($$) CommandCancel($$)
{ {
@ -3151,16 +3156,18 @@ CommandCancel($$)
if( !$id ) { if( !$id ) {
my $ret; my $ret;
foreach $id (keys %sleepers) { foreach $id (sort keys %sleepers) {
my $h = $sleepers{$id};
$ret .= "\n" if( $ret ); $ret .= "\n" if( $ret );
$ret .= sprintf( "%-10s %s", $id, $sleepers{$id}->{cmd} ); $ret .= sprintf( "%-12s %-19s %s", $id, $h->{till}, $h->{cmd} );
} }
$ret = "no pending sleeps" if( !$ret ); $ret = "no pending sleeps" if(!$ret);
return $ret; return $ret;
} elsif( my $h = $sleepers{$id} ) { } elsif( my $h = $sleepers{$id} ) {
RemoveInternalTimer( $h ); RemoveInternalTimer($id, "sleep_WakeUpFn") if(defined($h->{sec}));
delete $sleepers{$h->{id}}; CommandDelete($cl, $h->{name}) if(!defined($h->{sec}));
delete $sleepers{$id};
} else { } else {
return "no such id: $id" if( !$quiet ); return "no such id: $id" if( !$quiet );
@ -3179,24 +3186,47 @@ CommandSleep($$)
$quiet = $id; $quiet = $id;
$id = undef; $id = undef;
} }
return "Argument missing" if(!defined($sec)); return "Argument missing" if(!defined($sec));
return "Cannot interpret $sec as seconds" if($sec !~ m/^[0-9\.]+$/);
return "Last parameter must be quiet" if($quiet && $quiet ne "quiet"); return "Last parameter must be quiet" if($quiet && $quiet ne "quiet");
Log 4, "sleeping for $sec"; my $name = ".sleep_".(++$intAtCnt);
$id = $name if(!$id);
my $till;
if($sec !~ m/^[0-9\.]+$/) {
my ($err, $hr,$min,$s, $fn) = GetTimeSpec($sec);
if($err) { # not a valid timespec => treat as regex
if(@cmdList && $init_done) {
CommandDelete($cl, $name) if($defs{$name});
$err = CommandDefine($cl,
"-temporary $name notify $sec {sleep_WakeUpFn('$id')}");
$attr{$name}{ignore} = 1;
return $err if($err);
}
$till = $sec;
$sec = undef;
} else {
$sec = 3600*$hr+60*$min+$s;
}
}
$till = gettimeofday()+$sec if(defined($sec));
if(@cmdList && $init_done) { if(@cmdList && $init_done) {
my %h = (cmd => join(";", @cmdList), my %h = (cmd => join(";", @cmdList),
evalSpecials => $evalSpecials, evalSpecials => $evalSpecials,
quiet => $quiet, quiet => $quiet,
till => defined($sec) ? FmtDateTime($till) : $till,
sec => $sec,
name => $name,
cl => $cl, cl => $cl,
id => $id); id => $id);
if( $id ) { if(defined($sec)) {
RemoveInternalTimer( $sleepers{$id} ) if( $sleepers{$id} ); RemoveInternalTimer($id, "sleep_WakeUpFn");
$sleepers{$id} = \%h; InternalTimer($till, "sleep_WakeUpFn", $id, 0);
} }
InternalTimer(gettimeofday()+$sec, "WakeUpFn", \%h, 0); $sleepers{$id} = \%h;
@cmdList=(); @cmdList=();
} else { } else {