90_at.pm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. ##############################################
  2. # $Id: 90_at.pm 17561 2018-10-18 14:45:30Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use POSIX;
  7. use Time::HiRes qw(gettimeofday);
  8. #####################################
  9. sub
  10. at_Initialize($)
  11. {
  12. my ($hash) = @_;
  13. $hash->{DefFn} = "at_Define";
  14. $hash->{UndefFn} = "at_Undef";
  15. $hash->{SetFn} = "at_Set";
  16. $hash->{AttrFn} = "at_Attr";
  17. $hash->{StateFn} = "at_State";
  18. $hash->{AttrList} = "disable:0,1 disabledForIntervals $readingFnAttributes ".
  19. "skip_next:0,1 alignTime computeAfterInit";
  20. $hash->{FW_detailFn} = "at_fhemwebFn";
  21. }
  22. my %at_stt;
  23. my $at_detailFnCalled;
  24. sub
  25. at_SecondsTillTomorrow($) # 86400, if tomorrow is no DST change
  26. {
  27. my $t = shift;
  28. my $dayHour = int($t/3600);
  29. if(!$at_stt{$dayHour}) {
  30. my @l1 = localtime($t);
  31. my @l2 = localtime($t+86400);
  32. $at_stt{$dayHour} = 86400+($l1[8]-$l2[8])*3600;
  33. }
  34. return $at_stt{$dayHour};
  35. }
  36. #####################################
  37. sub
  38. at_Define($$)
  39. {
  40. my ($hash, $def) = @_;
  41. my ($name, undef, $tm, $command) = split("[ \t\n]+", $def, 4);
  42. if(!$command) {
  43. if($hash->{OLDDEF}) { # Called from modify, where command is optional
  44. RemoveInternalTimer($hash);
  45. (undef, $command) = split("[ \t]+", $hash->{OLDDEF}, 2);
  46. $hash->{DEF} = "$tm $command";
  47. } else {
  48. return "Usage: define <name> at [timespec or datespec] <command>";
  49. }
  50. }
  51. return "Wrong timespec, use \"[+][*[{count}]]<time or func>\""
  52. if($tm !~ m/^(\+)?(\*(\{\d+\})?)?(.*)$/);
  53. my ($rel, $rep, $cnt, $tspec) = ($1, $2, $3, $4);
  54. my ($abstime, $err, $hr, $min, $sec, $fn);
  55. if($tspec =~ m/^\d{10}$/) {
  56. $abstime = $tspec;
  57. } elsif($tspec =~ m/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/) {
  58. my ($y,$m,$d,$h,$m2,$s) = ($1,$2,$3,$4,$5,$6);
  59. $abstime = mktime($s,$m2,$h,$d,$m-1,$y-1900, 0,0,-1);
  60. } else {
  61. ($err, $hr, $min, $sec, $fn) = GetTimeSpec($tspec);
  62. return $err if($err);
  63. }
  64. return "datespec is not allowed with + or *" if($abstime && ($rel || $rep));
  65. if($hash->{CL}) { # Do not check this for definition
  66. $err = perlSyntaxCheck($command, ());
  67. return $err if($err);
  68. }
  69. $rel = "" if(!defined($rel));
  70. $rep = "" if(!defined($rep));
  71. $cnt = "" if(!defined($cnt));
  72. delete $hash->{VOLATILE} if (defined($hash->{VOLATILE}));
  73. $hash->{RELATIVE} = ($rel ? "yes" : "no");
  74. $hash->{PERIODIC} = ($rep ? "yes" : "no");
  75. $hash->{TIMESPEC} = $tspec;
  76. $hash->{COMMAND} = $command;
  77. my $ot = $data{AT_TRIGGERTIME} ? $data{AT_TRIGGERTIME} : gettimeofday();
  78. $ot = int($ot) if(!$rel); # No way to specify subseconds
  79. my $nt = $ot;
  80. if($abstime) {
  81. $nt = $abstime;
  82. } elsif($rel eq "+") {
  83. $nt += ($hr*3600+$min*60+$sec); # Relative time
  84. } else {
  85. my @lt = localtime($ot);
  86. ($lt[2], $lt[1], $lt[0]) = ($hr+0, $min+0, $sec+0);
  87. $lt[8] = -1; # Forum #52074
  88. $nt = mktime(@lt);
  89. $nt += at_SecondsTillTomorrow($nt) if($ot >= $nt); # Do it tomorrow...
  90. }
  91. my @lt = localtime($nt);
  92. my $ntm = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
  93. if($rep) { # Setting the number of repetitions
  94. $cnt =~ s/[{}]//g;
  95. return undef if($cnt eq "0");
  96. $cnt = 0 if(!$cnt);
  97. $cnt--;
  98. delete($hash->{VOLATILE}); # Modify
  99. $hash->{REP} = $cnt;
  100. } else {
  101. $hash->{VOLATILE} = 1; # Write these entries to the statefile
  102. delete($hash->{REP}); # Modify
  103. }
  104. my $alTime = AttrVal($name, "alignTime", undef);
  105. if(!$data{AT_RECOMPUTE} && $alTime) {
  106. my $ret = at_adjustAlign($hash, $alTime);
  107. return $ret if($ret);
  108. } else {
  109. my $fmt = FmtDateTime($nt);
  110. $hash->{TRIGGERTIME} = $nt;
  111. $hash->{TRIGGERTIME_FMT} = $fmt;
  112. if($hash->{PERIODIC} eq "no") { # Need for restart
  113. $fmt =~ s/ /T/;
  114. $hash->{DEF} = $fmt." ".$hash->{COMMAND};
  115. }
  116. RemoveInternalTimer($hash);
  117. InternalTimer($nt, "at_Exec", $hash, 0);
  118. $hash->{NTM} = $ntm if($rel eq "+" || $fn);
  119. my $d = IsDisabled($name); # 1
  120. my $val = ($d==3 ? "inactive" : ($d ? "disabled":("Next: ".
  121. ($abstime ? FmtDateTime($nt) : FmtTime($nt)) )));
  122. readingsSingleUpdate($hash, "state", $val,
  123. !$hash->{READINGS}{state} || $hash->{READINGS}{state}{VAL} ne $val);
  124. }
  125. return undef;
  126. }
  127. sub
  128. at_Undef($$)
  129. {
  130. my ($hash, $name) = @_;
  131. $hash->{DELETED} = 1;
  132. RemoveInternalTimer($hash);
  133. return undef;
  134. }
  135. sub
  136. at_Exec($)
  137. {
  138. my ($hash) = @_;
  139. return if($hash->{DELETED}); # Just deleted
  140. my $name = $hash->{NAME};
  141. my $skip = AttrVal($name, "skip_next", undef);
  142. delete $attr{$name}{skip_next} if($skip);
  143. $hash->{TEMPORARY} = 1 if($hash->{VOLATILE}); # 68680
  144. delete $hash->{VOLATILE};
  145. if(!$skip && !IsDisabled($name)) {
  146. Log3 $name, 5, "exec at command $name";
  147. my $ret = AnalyzeCommandChain(undef, SemicolonEscape($hash->{COMMAND}));
  148. Log3 $name, 3, "$name: $ret" if($ret);
  149. }
  150. return if($hash->{DELETED}); # Deleted in the Command
  151. my $count = $hash->{REP};
  152. my $def = $hash->{DEF};
  153. # Avoid drift when the timespec is relative
  154. $data{AT_TRIGGERTIME} = $hash->{TRIGGERTIME} if($def =~ m/^\+/);
  155. if($count) {
  156. $def =~ s/\{\d+\}/{$count}/ if($def =~ m/^\+?\*\{\d+\}/); # Replace count
  157. Log3 $name, 5, "redefine at command $name as $def";
  158. $data{AT_RECOMPUTE} = 1; # Tell sunrise compute the next day
  159. at_Define($hash, "$name at $def"); # Recompute the next TRIGGERTIME
  160. delete($data{AT_RECOMPUTE});
  161. } else {
  162. CommandDelete(undef, $name); # We are done
  163. }
  164. delete($data{AT_TRIGGERTIME});
  165. }
  166. sub
  167. at_adjustAlign($$)
  168. {
  169. my($hash, $attrVal) = @_;
  170. my ($tm, $command) = split("[ \t]+", $hash->{DEF}, 2);
  171. $tm =~ m/^(\+)?(\*(\{\d+\})?)?(.*)$/;
  172. my ($rel, $rep, $cnt, $tspec) = ($1, $2, $3, $4);
  173. return "startTimes: $hash->{NAME} is not relative" if(!$rel);
  174. my ($err, $ttime) = computeAlignTime($tspec, $attrVal,$hash->{TRIGGERTIME});
  175. return "$hash->{NAME} $err" if($err);
  176. RemoveInternalTimer($hash);
  177. InternalTimer($ttime, "at_Exec", $hash, 0);
  178. $hash->{TRIGGERTIME} = $ttime;
  179. $hash->{TRIGGERTIME_FMT} = FmtDateTime($ttime);
  180. $hash->{STATE} = "Next: " . FmtTime($ttime);
  181. $hash->{NTM} = FmtTime($ttime);
  182. readingsSingleUpdate($hash, "state", $hash->{STATE}, 1)
  183. if(!IsDisabled($hash->{NAME}));
  184. return undef;
  185. }
  186. sub
  187. at_Set($@)
  188. {
  189. my ($hash, @a) = @_;
  190. my %sets = (modifyTimeSpec=>1, inactive=>0, active=>0, execNow=>0);
  191. my $cmd = join(" ", sort keys %sets);
  192. $cmd =~ s/modifyTimeSpec/modifyTimeSpec:time/ if($at_detailFnCalled);
  193. $at_detailFnCalled = 0;
  194. return "no set argument specified" if(int(@a) < 2);
  195. return "Unknown argument $a[1], choose one of $cmd"
  196. if(!defined($sets{$a[1]}));
  197. if($a[1] eq "modifyTimeSpec") {
  198. my ($err, undef) = GetTimeSpec($a[2]);
  199. return $err if($err);
  200. my $def = ($hash->{RELATIVE} eq "yes" ? "+":"").
  201. ($hash->{PERIODIC} eq "yes" ? "*":"").
  202. $a[2];
  203. $hash->{OLDDEF} = $hash->{DEF};
  204. my $ret = at_Define($hash, "$hash->{NAME} at $def");
  205. delete $hash->{OLDDEF};
  206. return $ret;
  207. } elsif($a[1] eq "inactive") {
  208. readingsSingleUpdate($hash, "state", "inactive", 1);
  209. return undef;
  210. } elsif($a[1] eq "active") {
  211. readingsSingleUpdate($hash,"state","Next: ".FmtTime($hash->{TRIGGERTIME}),1)
  212. if(!AttrVal($hash->{NAME}, "disable", undef));
  213. return undef;
  214. } elsif($a[1] eq "execNow") {
  215. my $name = $hash->{NAME};
  216. my $ret = AnalyzeCommandChain(undef, SemicolonEscape($hash->{COMMAND}));
  217. Log3 $name, 3, "$name: $ret" if($ret);
  218. }
  219. }
  220. sub
  221. at_Attr(@)
  222. {
  223. my ($cmd, $name, $attrName, $attrVal) = @_;
  224. my $do = 0;
  225. my $hash = $defs{$name};
  226. if($cmd eq "set" && $attrName eq "computeAfterInit" &&
  227. $attrVal && !$init_done) {
  228. InternalTimer(1, sub(){
  229. $hash->{OLDDEF} = $hash->{DEF};
  230. at_Define($hash, "$name at $hash->{DEF}");
  231. delete($hash->{OLDDEF});
  232. }, $name, 0);
  233. return undef;
  234. }
  235. if($cmd eq "set" && $attrName eq "alignTime") {
  236. return "alignTime needs a list of timespec parameters" if(!$attrVal);
  237. my $ret = at_adjustAlign($hash, $attrVal);
  238. return $ret if($ret);
  239. }
  240. if($cmd eq "set" && $attrName eq "stateFormat" && !$init_done) {
  241. $attr{$name}{stateFormat} = $attrVal;
  242. evalStateFormat($hash);
  243. return undef;
  244. }
  245. if($cmd eq "set" && $attrName eq "disable") {
  246. $do = (!defined($attrVal) || $attrVal) ? 1 : 2;
  247. }
  248. $do = 2 if($cmd eq "del" && (!$attrName || $attrName eq "disable"));
  249. return if(!$do);
  250. my $val = ($do == 1 ? "disabled" :
  251. "Next: " . FmtTime($hash->{TRIGGERTIME}));
  252. readingsSingleUpdate($hash, "state", $val, 1);
  253. return undef;
  254. }
  255. #############
  256. # Adjust one-time relative at's after reboot, the execution time is stored as
  257. # state
  258. sub
  259. at_State($$$$)
  260. {
  261. my ($hash, $tim, $vt, $val) = @_;
  262. if($vt eq "state" && $val eq "inactive") {
  263. readingsSingleUpdate($hash, "state", "inactive", 1);
  264. }
  265. return undef;
  266. }
  267. #########################
  268. sub
  269. at_fhemwebFn($$$$)
  270. {
  271. my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
  272. my $hash = $defs{$d};
  273. $at_detailFnCalled = 1 if(!$pageHash);
  274. my $ts = $hash->{TIMESPEC}; $ts =~ s/'/\\'/g;
  275. my $isPerl = ($ts =~ m/^{(.*)}/);
  276. $ts = $1 if($isPerl);
  277. my $h1 .= "<div class='makeTable wide'><span>Change wizard</span>".
  278. "<table class='block wide' id='atWizard' nm='$hash->{NAME}' ts='$ts' ".
  279. "rl='$hash->{RELATIVE}' ".
  280. "pr='$hash->{PERIODIC}' ip='$isPerl' class='block wide'>".<<'EOF';
  281. <tr class="even"><td>Change the timespec:</td></tr>
  282. <tr class="odd">
  283. <td>Relative <input type="checkbox" id="aw_rl" value="yes">&nbsp;
  284. Periodic <input type="checkbox" id="aw_pr" value="yes">&nbsp;
  285. Use perl function for timespec <input type="checkbox" id="aw_ip"></td>
  286. </tr><tr class="even"><td><input type="text" name="aw_pts"></td>
  287. </tr><tr class="even"><td><input type="text" name="aw_ts"></td>
  288. </tr><tr class="odd"><td><input type="button" id="aw_md"
  289. value="Change the timespec"></td>
  290. </tr>
  291. EOF
  292. my $j1 = << 'EOF';
  293. <script type="text/javascript">
  294. {
  295. var t=$("#atWizard"), ip=$(t).attr("ip"), ts=$(t).attr("ts");
  296. FW_replaceWidget("[name=aw_ts]", "aw_ts", ["time"], "12:00");
  297. $("[name=aw_ts] input[type=text]").attr("id", "aw_ts");
  298. function ipClick() {
  299. var c = $("#aw_ip").prop("checked");
  300. $("[name=aw_ts]") .closest("tr").css("display",!c ? "table-row" : "none");
  301. $("[name=aw_pts]").closest("tr").css("display", c ? "table-row" : "none");
  302. }
  303. $("#aw_rl").prop("checked", $(t).attr("rl")=="yes");
  304. $("#aw_pr").prop("checked", $(t).attr("pr")=="yes");
  305. $("#aw_ip").prop("checked", ip);
  306. $("[name=aw_ts]").val(ip ? "12:00" : ts);
  307. $("[name=aw_pts]").val(ip ? ts : 'sunset()');
  308. $("#aw_ip").change(ipClick);
  309. ipClick();
  310. $("#aw_md").click(function(){
  311. var nm = $(t).attr("nm");
  312. var def = nm+" ";
  313. def += $("#aw_rl").prop("checked") ? "+":"";
  314. def += $("#aw_pr").prop("checked") ? "*":"";
  315. def += $("#aw_ip").prop("checked") ?
  316. "{"+$("[name=aw_pts]").val()+"}" : $("[name=aw_ts]").val();
  317. def = def.replace(/\+/g, "%2b");
  318. def = def.replace(/;/g, ";;");
  319. location = location.pathname+"?detail="+nm+"&cmd=modify "+addcsrf(def);
  320. });
  321. }
  322. </script>
  323. EOF
  324. my @d = split(" ",$hash->{DEF},2);
  325. LoadModule("notify");
  326. my ($h2, $j2) = notfy_addFWCmd($d, $d[0], 2);
  327. return "$h1$h2</table></div><br>$j1$j2";
  328. }
  329. 1;
  330. =pod
  331. =item summary start an FHEM command at a later time
  332. =item summary_DE FHEM Befehl zu einem sp&auml;teren Zeitpunkt starten
  333. =item helper
  334. =begin html
  335. <a name="at"></a>
  336. <h3>at</h3>
  337. <ul>
  338. Start an arbitrary FHEM command at a later time.<br>
  339. <br>
  340. <a name="atdefine"></a>
  341. <b>Define</b>
  342. <ul>
  343. <code>define &lt;name&gt; at [&lt;timespec&gt;|&lt;datespec&gt;]
  344. &lt;command&gt;</code><br>
  345. <br>
  346. <code>&lt;timespec&gt;</code> format: [+][*{N}]&lt;timedet&gt;<br>
  347. <ul>
  348. The optional <code>+</code> indicates that the specification is
  349. <i>relative</i>(i.e. it will be added to the current time).<br>
  350. The optional <code>*</code> indicates that the command should be
  351. executed <i>repeatedly</i>.<br>
  352. The optional <code>{N}</code> after the * indicates,that the command
  353. should be repeated <i>N-times</i> only.<br>
  354. &lt;timespec&gt; is either HH:MM, HH:MM:SS or {perlfunc()}. perlfunc must
  355. return a string in timedet format. Note: {perlfunc()} may not contain
  356. any spaces or tabs.<br>
  357. &lt;datespec&gt; is either ISO8601 (YYYY-MM-DDTHH:MM:SS) or number of
  358. seconds since 1970.
  359. </ul>
  360. <br>
  361. Examples:
  362. <PRE>
  363. # absolute ones:
  364. define a1 at 17:00:00 set lamp on # fhem command
  365. define a2 at 17:00:00 { Log 1, "Teatime" } # Perl command
  366. define a3 at 17:00:00 "/bin/echo "Teatime" > /dev/console" # shell command
  367. define a4 at *17:00:00 set lamp on # every day
  368. # relative ones
  369. define a5 at +00:00:10 set lamp on # switch on in 10 seconds
  370. define a6 at +00:00:02 set lamp on-for-timer 1 # Blink once in 2 seconds
  371. define a7 at +*{3}00:00:02 set lamp on-for-timer 1 # Blink 3 times
  372. # Blink 3 times if the piri sends a command
  373. define n1 notify piri:on.* define a8 at +*{3}00:00:02 set lamp on-for-timer 1
  374. # Switch the lamp on from sunset to 11 PM
  375. define a9 at +*{sunset_rel()} set lamp on
  376. define a10 at *23:00:00 set lamp off
  377. # More elegant version, works for sunset > 23:00 too
  378. define a11 at +*{sunset_rel()} set lamp on-till 23:00
  379. # Only do this on weekend
  380. define a12 at +*{sunset_rel()} { fhem("set lamp on-till 23:00") if($we) }
  381. # Switch lamp1 and lamp2 on from 7:00 till 10 minutes after sunrise
  382. define a13 at *07:00 set lamp1,lamp2 on-till {sunrise(+600)}
  383. # Switch the lamp off 2 minutes after sunrise each day
  384. define a14 at *{sunrise(+120)} set lamp on
  385. # Switch lamp1 on at sunset, not before 18:00 and not after 21:00
  386. define a15 at *{sunset(0,"18:00","21:00")} set lamp1 on
  387. </PRE>
  388. Notes:<br>
  389. <ul>
  390. <li>if no <code>*</code> is specified, then a command will be executed
  391. only once, and then the <code>at</code> entry will be deleted. In
  392. this case the command will be saved to the statefile (as it
  393. considered volatile, i.e. entered by cronjob) and not to the
  394. configfile (see the <a href="#save">save</a> command.)
  395. </li>
  396. <li>if the current time is greater than the time specified, then the
  397. command will be executed tomorrow.</li>
  398. <li>For even more complex date handling you either have to call fhem from
  399. cron or filter the date in a perl expression, see the last example and
  400. the section <a href="#perl">Perl special</a>.
  401. </li>
  402. </ul>
  403. <br>
  404. </ul>
  405. <a name="atset"></a>
  406. <b>Set</b>
  407. <ul>
  408. <a name="modifyTimeSpec"></a>
  409. <li>modifyTimeSpec &lt;timespec&gt;<br>
  410. Change the execution time. Note: the N-times repetition is ignored.
  411. It is intended to be used in combination with
  412. <a href="#webCmd">webCmd</a>, for an easier modification from the room
  413. overview in FHEMWEB.</li>
  414. <li>inactive<br>
  415. Inactivates the current device. Note the slight difference to the
  416. disable attribute: using set inactive the state is automatically saved
  417. to the statefile on shutdown, there is no explicit save necesary.<br>
  418. This command is intended to be used by scripts to temporarily
  419. deactivate the at.<br>
  420. The concurrent setting of the disable attribute is not recommended.
  421. </li>
  422. <li>active<br>
  423. Activates the current device (see inactive).</li>
  424. <li>execNow<br>
  425. Execute the command associated with the at. The execution of a relative
  426. at is not affected by this command.</li>
  427. </ul><br>
  428. <a name="atget"></a>
  429. <b>Get</b> <ul>N/A</ul><br>
  430. <a name="atattr"></a>
  431. <b>Attributes</b>
  432. <ul>
  433. <a name="alignTime"></a>
  434. <li>alignTime<br>
  435. Applies only to relative at definitions: adjust the time of the next
  436. command execution so, that it will also be executed at the desired
  437. alignTime. The argument is a timespec, see above for the
  438. definition.<br>
  439. Example:<br>
  440. <ul>
  441. # Make sure that it chimes when the new hour begins<br>
  442. define at2 at +*01:00 set Chime on-for-timer 1<br>
  443. attr at2 alignTime 00:00<br>
  444. </ul>
  445. </li><br>
  446. <a name="computeAfterInit"></a>
  447. <li>computeAfterInit<br>
  448. If perlfunc() in the timespec relies on some other/dummy readings, then
  449. it will return a wrong time upon FHEM start, as the at define is
  450. processed before the readings are known. If computeAfterInit is set,
  451. FHEM will recompute timespec after the initialization is finished.
  452. </li><br>
  453. <a name="disable"></a>
  454. <li>disable<br>
  455. Can be applied to at/watchdog/notify/FileLog devices.<br>
  456. Disables the corresponding at/notify or FileLog device. Note:
  457. If applied to an <a href="#at">at</a>, the command will not be executed,
  458. but the next time will be computed.</li><br>
  459. <a name="disabledForIntervals"></a>
  460. <li>disabledForIntervals HH:MM-HH:MM HH:MM-HH:MM ...<br>
  461. Space separated list of HH:MM or D@HH:MM tupels. If the current time is
  462. between the two time specifications, the current device is disabled.
  463. Instead of HH:MM you can also specify HH or HH:MM:SS. D is the day of
  464. the week, with 0 indicating Sunday and 3 indicating Wednesday.
  465. Specifying the day for the "from" part does _not_ specify it for the
  466. "to" part, i.e. 1@00-24 will disable from monday to the end of the
  467. week, but not on sunday (as 1@00 is greater than any time on sunday).
  468. To specify an interval spawning midnight, you have to specify two
  469. intervals, e.g.:
  470. <ul>
  471. 23:00-24:00 00:00-01:00
  472. </ul>
  473. If parts of the attribute value are enclosed in {}, they are evaluated:
  474. <ul>
  475. {sunset_abs()}-24 {sunrise_abs()}-08
  476. </ul>
  477. </li><br>
  478. <a name="skip_next"></a>
  479. <li>skip_next<br>
  480. Used for at commands: skip the execution of the command the next
  481. time.</li><br>
  482. <li><a href="#perlSyntaxCheck">perlSyntaxCheck</a></li>
  483. </ul>
  484. <br>
  485. </ul>
  486. =end html
  487. =begin html_DE
  488. <a name="at"></a>
  489. <h3>at</h3>
  490. <ul>
  491. Startet einen beliebigen FHEM Befehl zu einem sp&auml;teren Zeitpunkt.<br>
  492. <br>
  493. <a name="atdefine"></a>
  494. <b>Define</b>
  495. <ul>
  496. <code>define &lt;name&gt; at [&lt;timespec&gt;|&lt;datespec&gt;]
  497. &lt;command&gt;</code><br>
  498. <br>
  499. <code>&lt;timespec&gt;</code> Format: [+][*{N}]&lt;timedet&gt;<br>
  500. <ul>
  501. Das optionale <code>+</code> zeigt, dass die Angabe <i>relativ</i> ist
  502. (also zur jetzigen Zeit dazugez&auml;hlt wird).<br>
  503. Das optionale <code>*</code> zeigt, dass die Ausf&uuml;hrung
  504. <i>wiederholt</i> erfolgen soll.<br>
  505. Das optionale <code>{N}</code> nach dem * bedeutet, dass der Befehl genau
  506. <i>N-mal</i> wiederholt werden soll.<br>
  507. &lt;timespec&gt; ist entweder HH:MM, HH:MM:SS oder {perlfunc()}. perlfunc
  508. muss ein String in timedet Format zurueckliefern. Achtung: {perlfunc()}
  509. darf keine Leerzeichen enthalten.<br>
  510. &lt;datespec&gt; ist entweder ISO8601 (YYYY-MM-DDTHH:MM:SS) oder Anzahl
  511. der Sekunden seit 1970.
  512. </ul>
  513. <br>
  514. Beispiele:
  515. <PRE>
  516. # Absolute Beispiele:
  517. define a1 at 17:00:00 set lamp on # fhem Befehl
  518. define a2 at 17:00:00 { Log 1, "Teatime" } # Perl Befehl
  519. define a3 at 17:00:00 "/bin/echo "Teatime" > /dev/console" # shell Befehl
  520. define a4 at *17:00:00 set lamp on # Jeden Tag
  521. # Realtive Beispiele:
  522. define a5 at +00:00:10 set lamp on # Einschalten in 10 Sekunden
  523. define a6 at +00:00:02 set lamp on-for-timer 1 # Einmal blinken in 2 Sekunden
  524. define a7 at +*{3}00:00:02 set lamp on-for-timer 1 # Blinke 3 mal
  525. # Blinke 3 mal wenn piri einen Befehl sendet
  526. define n1 notify piri:on.* define a8 at +*{3}00:00:02 set lamp on-for-timer 1
  527. # Lampe von Sonnenuntergang bis 23:00 Uhr einschalten
  528. define a9 at +*{sunset_rel()} set lamp on
  529. define a10 at *23:00:00 set lamp off
  530. # Elegantere Version, ebenfalls von Sonnenuntergang bis 23:00 Uhr
  531. define a11 at +*{sunset_rel()} set lamp on-till 23:00
  532. # Nur am Wochenende ausf&uuml;hren
  533. define a12 at +*{sunset_rel()} { fhem("set lamp on-till 23:00") if($we) }
  534. # Schalte lamp1 und lamp2 ein von 7:00 bis 10 Minuten nach Sonnenaufgang
  535. define a13 at *07:00 set lamp1,lamp2 on-till {sunrise(+600)}
  536. # Schalte lamp jeden Tag 2 Minuten nach Sonnenaufgang aus
  537. define a14 at *{sunrise(+120)} set lamp on
  538. # Schalte lamp1 zum Sonnenuntergang ein, aber nicht vor 18:00 und nicht nach 21:00
  539. define a15 at *{sunset(0,"18:00","21:00")} set lamp1 on
  540. </PRE>
  541. Hinweise:<br>
  542. <ul>
  543. <li>wenn kein <code>*</code> angegeben wird, wird der Befehl nur einmal
  544. ausgef&uuml;hrt und der entsprechende <code>at</code> Eintrag danach
  545. gel&ouml;scht. In diesem Fall wird der Befehl im Statefile gespeichert
  546. (da er nicht statisch ist) und steht nicht im Config-File (siehe auch <a
  547. href="#save">save</a>).</li>
  548. <li>wenn die aktuelle Zeit gr&ouml;&szlig;er ist als die angegebene Zeit,
  549. dann wird der Befehl am folgenden Tag ausgef&uuml;hrt.</li>
  550. <li>F&uuml;r noch komplexere Datums- und Zeitabl&auml;ufe muss man den
  551. Aufruf entweder per cron starten oder Datum/Zeit mit perl weiter
  552. filtern. Siehe hierzu das letzte Beispiel und das <a href="#perl">Perl
  553. special</a>. </li>
  554. </ul>
  555. <br>
  556. </ul>
  557. <a name="atset"></a>
  558. <b>Set</b>
  559. <ul>
  560. <a name="modifyTimeSpec"></a>
  561. <li>modifyTimeSpec &lt;timespec&gt;<br>
  562. &Auml;ndert die Ausf&uuml;hrungszeit. Achtung: die N-malige
  563. Wiederholungseinstellung wird ignoriert. Gedacht zur einfacheren
  564. Modifikation im FHEMWEB Raum&uuml;bersicht, dazu muss man
  565. modifyTimeSpec in <a href="webCmd">webCmd</a> spezifizieren.
  566. </li>
  567. <li>inactive<br>
  568. Deaktiviert das entsprechende Ger&auml;t. Beachte den leichten
  569. semantischen Unterschied zum disable Attribut: "set inactive"
  570. wird bei einem shutdown automatisch in fhem.state gespeichert, es ist
  571. kein save notwendig.<br>
  572. Der Einsatzzweck sind Skripte, um das at tempor&auml;r zu
  573. deaktivieren.<br>
  574. Das gleichzeitige Verwenden des disable Attributes wird nicht empfohlen.
  575. </li>
  576. <li>active<br>
  577. Aktiviert das entsprechende Ger&auml;t, siehe inactive.
  578. </li>
  579. <li>execNow<br>
  580. F&uuml;hrt das mit dem at spezifizierte Befehl aus. Beeinflu&szlig;t
  581. nicht die Ausf&uuml;hrungszeiten relativer Spezifikationen.
  582. </li>
  583. </ul><br>
  584. <a name="atget"></a>
  585. <b>Get</b> <ul>N/A</ul><br>
  586. <a name="atattr"></a>
  587. <b>Attribute</b>
  588. <ul>
  589. <a name="alignTime"></a>
  590. <li>alignTime<br>
  591. Nur f&uuml;r relative Definitionen: Stellt den Zeitpunkt der
  592. Ausf&uuml;hrung des Befehls so, dass er auch zur alignTime
  593. ausgef&uuml;hrt wird. Dieses Argument ist ein timespec. Siehe oben
  594. f&uuml; die Definition<br>
  595. Beispiel:<br>
  596. <ul>
  597. # Stelle sicher das es gongt wenn eine neue Stunde beginnt.<br>
  598. define at2 at +*01:00 set Chime on-for-timer 1<br>
  599. attr at2 alignTime 00:00<br>
  600. </ul>
  601. </li><br>
  602. <a name="computeAfterInit"></a>
  603. <li>computeAfterInit<br>
  604. Falls perlfunc() im timespec Readings or Statusinformationen
  605. ben&ouml;gt, dann wird sie eine falsche Zeit beim FHEM-Start
  606. zurueckliefern, da zu diesem Zeitpunkt die Readings noch nicht aktiv
  607. sind. Mit gesetztem computeAfterInit wird perlfunc nach Setzen aller
  608. Readings erneut ausgefuehrt. (Siehe Forum #56706)
  609. </li><br>
  610. <a name="disable"></a>
  611. <li>disable<br>
  612. Deaktiviert das entsprechende Ger&auml;t.<br>
  613. Hinweis: Wenn angewendet auf ein <a href="#at">at</a>, dann wird der
  614. Befehl nicht ausgef&uuml;hrt, jedoch die n&auml;chste
  615. Ausf&uuml;hrungszeit berechnet.</li><br>
  616. <a name="disabledForIntervals"></a>
  617. <li>disabledForIntervals HH:MM-HH:MM HH:MM-HH:MM ...<br>
  618. Das Argument ist eine Leerzeichengetrennte Liste von Minuszeichen-
  619. getrennten HH:MM oder D@HH:MM Paaren. Falls die aktuelle Uhrzeit
  620. zwischen diesen Werten f&auml;llt, dann wird die Ausf&uuml;hrung, wie
  621. beim disable, ausgesetzt. Statt HH:MM kann man auch HH oder HH:MM:SS
  622. angeben. D ist der Tag der Woche, mit 0 als Sonntag and 3 als
  623. Mittwoch. Die Angabe des Wochentags f&uuml;r den "von" Wert impliziert
  624. _nicht_ den gleichen Tag f&uuml;r den "bis" Wert, z.Bsp. deaktiviert
  625. 1@00-24 die Asf&uuml;hrung von Montag bis Ende der Woche, aber nicht
  626. Sonntag (da alle Zeitangaben am Montag vor 1@00 liegen).
  627. Um einen Intervall um Mitternacht zu spezifizieren, muss man
  628. zwei einzelne angeben, z.Bsp.:
  629. <ul>
  630. 23:00-24:00 00:00-01:00
  631. </ul>
  632. Falls Teile des Wertes in {} eingeschlossen sind, dann werden sie als
  633. ein Perl Ausdruck ausgewertet:
  634. <ul>
  635. {sunset_abs()}-24 {sunrise_abs()}-08
  636. </ul>
  637. </li><br>
  638. <a name="skip_next"></a>
  639. <li>skip_next<br>
  640. Wird bei at Befehlen verwendet um die n&auml;chste Ausf&uuml;hrung zu
  641. &uuml;berspringen</li><br>
  642. <li><a href="#perlSyntaxCheck">perlSyntaxCheck</a></li>
  643. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  644. </ul>
  645. <br>
  646. </ul>
  647. =end html_DE
  648. =cut