90_at.pm 25 KB

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