95_holiday.pm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. #######################################################################
  2. # $Id: 95_holiday.pm 16293 2018-02-28 21:33:57Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. use POSIX;
  7. sub holiday_refresh($;$$);
  8. #####################################
  9. sub
  10. holiday_Initialize($)
  11. {
  12. my ($hash) = @_;
  13. $hash->{DefFn} = "holiday_Define";
  14. $hash->{GetFn} = "holiday_Get";
  15. $hash->{SetFn} = "holiday_Set";
  16. $hash->{UndefFn} = "holiday_Undef";
  17. $hash->{AttrList} = $readingFnAttributes;
  18. $hash->{FW_detailFn} = "holiday_FW_detailFn";
  19. }
  20. #####################################
  21. sub
  22. holiday_Define($$)
  23. {
  24. my ($hash, $def) = @_;
  25. return holiday_refresh($hash->{NAME}, undef, 1) if($init_done);
  26. InternalTimer(gettimeofday()+1, "holiday_refresh", $hash->{NAME}, 0);
  27. return undef;
  28. }
  29. sub
  30. holiday_Undef($$)
  31. {
  32. my ($hash, $name) = @_;
  33. RemoveInternalTimer($name);
  34. return undef;
  35. }
  36. sub
  37. holiday_refresh($;$$)
  38. {
  39. my ($name, $fordate, $showAvailable) = (@_);
  40. my $hash = $defs{$name};
  41. my $fromTimer=0;
  42. return if(!$hash); # Just deleted
  43. my $nt = gettimeofday();
  44. my @lt = localtime($nt);
  45. my @fd;
  46. if(!$fordate) {
  47. $fromTimer = 1;
  48. $fordate = sprintf("%02d-%02d", $lt[4]+1, $lt[3]);
  49. @fd = @lt;
  50. } else {
  51. my ($m,$d) = split("-", $fordate);
  52. @fd = localtime(mktime(1,1,1,$d,$m-1,$lt[5],0,0,-1));
  53. }
  54. Log3 $name, 5, "holiday_refresh $name called for $fordate ($fromTimer)";
  55. my $dir = $attr{global}{modpath} . "/FHEM";
  56. my ($err, @holidayfile) = FileRead("$dir/$name.holiday");
  57. if($err) {
  58. $dir = $attr{global}{modpath}."/FHEM/holiday";
  59. ($err, @holidayfile) = FileRead("$dir/$name.holiday");
  60. $hash->{READONLY} = 1;
  61. } else {
  62. $hash->{READONLY} = 0;
  63. }
  64. if($err) {
  65. if($showAvailable) {
  66. my @ret;
  67. if(configDBUsed()) {
  68. @ret = cfgDB_FW_fileList($dir,".*.holiday",@ret);
  69. map { s/\.configDB$//;$_ } @ret;
  70. } else {
  71. if(opendir(DH, $dir)) {
  72. @ret = grep { m/\.holiday$/ } readdir(DH);
  73. closedir(DH);
  74. }
  75. }
  76. $err .= "\nAvailable holiday files: ".
  77. join(" ", map { s/.holiday//;$_ } @ret);
  78. } else {
  79. Log 1, "$name: $err";
  80. }
  81. return $err;
  82. }
  83. $hash->{HOLIDAYFILE} = "$dir/$name.holiday";
  84. my @foundList;
  85. foreach my $l (@holidayfile) {
  86. next if($l =~ m/^\s*#/);
  87. next if($l =~ m/^\s*$/);
  88. my $found;
  89. if($l =~ m/^1/) { # Exact date: 1 MM-DD Holiday
  90. my @args = split(" +", $l, 3);
  91. if($args[1] eq $fordate) {
  92. $found = $args[2];
  93. }
  94. } elsif($l =~ m/^2/) { # Easter date: 2 +1 Ostermontag
  95. ###mh new code for easter sunday calc w.o. requirement for
  96. # DateTime::Event::Easter
  97. # replace $a1 with $1 !!!
  98. # split line from file into args '2 <offset from E-sunday> <tagname>'
  99. my @a = split(" ", $l, 3);
  100. # get month & day for E-sunday
  101. my ($Om,$Od) = western_easter(($lt[5]+1900));
  102. my $timex = mktime(0,0,12,$Od,$Om-1, $lt[5],0,0,-1); # gen timevalue
  103. $timex = $timex + $a[1]*86400; # add offset days
  104. my ($msecond, $mminute, $mhour,
  105. $mday, $mmonth, $myear, $mrest) = localtime($timex);
  106. $myear = $myear+1900;
  107. $mmonth = $mmonth+1;
  108. #Log 1, "$name: Ostern:".sprintf("%04d-%02d-%02d", $lt[5]+1900, $Om, $Od).
  109. # " Target:".sprintf("%04d-%02d-%02d", $myear, $mmonth, $mday);
  110. next if($mday != $fd[3] || $mmonth != $fd[4]+1);
  111. $found = $a[2];
  112. Log 4, "$name: Match day: $a[2]\n";
  113. } elsif($l =~ m/^3/) { # Relative date: 3 -1 Mon 03 Holiday
  114. my @a = split(" +", $l, 5);
  115. my %wd = ("Sun"=>0, "Mon"=>1, "Tue"=>2, "Wed"=>3,
  116. "Thu"=>4, "Fri"=>5, "Sat"=>6);
  117. my @md = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  118. $md[1]=29 if(schaltjahr($fd[5]+1900) && $fd[4] == 1);
  119. my $wd = $wd{$a[2]};
  120. if(!defined($wd)) {
  121. Log 1, "Wrong timespec: $l";
  122. next;
  123. }
  124. next if($wd != $fd[6]); # Weekday
  125. next if($a[3] != ($fd[4]+1)); # Month
  126. if($a[1] > 0) { # N'th day from the start
  127. my $d = $fd[3] - ($a[1]-1)*7;
  128. next if($d < 1 || $d > 7);
  129. } elsif($a[1] < 0) { # N'th day from the end
  130. my $d = $fd[3] - ($a[1]+1)*7;
  131. my $md = $md[$fd[4]];
  132. next if($d > $md || $d < $md-6);
  133. }
  134. $found = $a[4];
  135. } elsif($l =~ m/^4/) { # Interval: 4 MM-DD MM-DD Holiday
  136. my @args = split(" +", $l, 4);
  137. if($args[1] le $fordate && $args[2] ge $fordate) {
  138. $found = $args[3];
  139. }
  140. } elsif($l =~ m/^5/) { # nth weekday since MM-DD / before MM-DD
  141. my @a = split(" +", $l, 6);
  142. # arguments: 5 <distance> <weekday> <month> <day> <name>
  143. my %wd = ("Sun"=>0, "Mon"=>1, "Tue"=>2, "Wed"=>3,
  144. "Thu"=>4, "Fri"=>5, "Sat"=>6);
  145. my $wd = $wd{$a[2]};
  146. if(!defined($wd)) {
  147. Log 1, "Wrong weekday spec: $l";
  148. next;
  149. }
  150. next if $wd != $fd[6]; # check wether weekday matches today
  151. my $yday=$fd[7];
  152. # create time object of target date - mktime counts months and their
  153. # days from 0 instead of 1, so subtract 1 from each
  154. my $tgt=mktime(0,0,1,$a[4],$a[3]-1,$fd[5],0,0,-1);
  155. my $tgtmin=$tgt;
  156. my $tgtmax=$tgt;
  157. my $weeksecs=7*24*60*60; # 7 days, 24 hours, 60 minutes, 60seconds each
  158. my $cd=mktime(0,0,1,$fd[3],$fd[4],$fd[5],0,0,-1);
  159. if ( $a[1] =~ /^-([0-9])*$/ ) {
  160. $tgtmin -= $1*$weeksecs; # Minimum: target date minus $1 weeks
  161. $tgtmax = $tgtmin+$weeksecs; # Maximum: one week after minimum
  162. # needs to be lower than max and greater than or equal to min
  163. if( ($cd ge $tgtmin) && ( $cd lt $tgtmax) ) {
  164. $found=$a[5];
  165. }
  166. } elsif ( $a[1] =~ /^\+?([0-9])*$/ ) {
  167. $tgtmin += ($1-1)*$weeksecs; # Minimum: target date plus $1-1 weeks
  168. $tgtmax = $tgtmin+$weeksecs; # Maximum: one week after minimum
  169. # needs to be lower than or equal to max and greater min
  170. if( ($cd gt $tgtmin) && ( $cd le $tgtmax) ) {
  171. $found=$a[5];
  172. }
  173. } else {
  174. Log 1, "Wrong distance spec: $l";
  175. next;
  176. }
  177. }
  178. push @foundList, $found if($found);
  179. }
  180. push @foundList, "none" if(!int(@foundList));
  181. my $found = join(", ", @foundList);
  182. if($fromTimer) {
  183. RemoveInternalTimer($name);
  184. $nt -= ($lt[2]*3600+$lt[1]*60+$lt[0]); # Midnight
  185. $nt += 86400 + 2; # Tomorrow
  186. $hash->{TRIGGERTIME} = $nt;
  187. InternalTimer($nt, "holiday_refresh", $name, 0);
  188. readingsBeginUpdate($hash);
  189. readingsBulkUpdate($hash, 'state', $found);
  190. readingsBulkUpdate($hash, 'yesterday', CommandGet(undef,"$name yesterday"));
  191. readingsBulkUpdate($hash, 'tomorrow', CommandGet(undef,"$name tomorrow"));
  192. readingsEndUpdate($hash,1);
  193. return undef;
  194. } else {
  195. return $found;
  196. }
  197. }
  198. sub
  199. holiday_Set($@)
  200. {
  201. my ($hash, @a) = @_;
  202. my %sets = (
  203. createPrivateCopy => $hash->{READONLY},
  204. deletePrivateCopy => !$hash->{READONLY},
  205. reload => 1
  206. );
  207. return "unknown argument $a[1], choose one of ".
  208. join(" ", map { "$_:noArg" }
  209. grep { $sets{$_} } keys %sets) if(!$sets{$a[1]});
  210. if($a[1] eq "createPrivateCopy") {
  211. return "Already a private version" if(!$hash->{READONLY});
  212. my $fname = $attr{global}{modpath}."/FHEM/holiday/$hash->{NAME}.holiday";
  213. my ($err, @holidayfile) = FileRead($fname);
  214. return $err if($err);
  215. $fname = $attr{global}{modpath}."/FHEM/$hash->{NAME}.holiday";
  216. $err = FileWrite($fname, @holidayfile);
  217. return $err if($err);
  218. holiday_refresh($hash->{NAME});
  219. } elsif($a[1] eq "deletePrivateCopy") {
  220. return "Not a private version" if($hash->{READONLY});
  221. my $err = FileDelete($attr{global}{modpath}."/FHEM/$hash->{NAME}.holiday");
  222. return $err if($err);
  223. holiday_refresh($hash->{NAME});
  224. } elsif($a[1] eq "reload") {
  225. holiday_refresh($hash->{NAME});
  226. }
  227. return undef;
  228. }
  229. sub
  230. holiday_Get($@)
  231. {
  232. my ($hash, @a) = @_;
  233. shift(@a) if($a[1] && $a[1] eq "MM-DD");
  234. return "argument is missing" if(int(@a) < 2);
  235. my $arg;
  236. if($a[1] =~ m/^[01]\d-[0-3]\d/) {
  237. $arg = $a[1];
  238. } elsif($a[1] =~ m/^(yesterday|today|tomorrow)$/) {
  239. my $t = time();
  240. $t += 86400 if($a[1] eq "tomorrow");
  241. $t -= 86400 if($a[1] eq "yesterday");
  242. my @a = localtime($t);
  243. $arg = sprintf("%02d-%02d", $a[4]+1, $a[3]);
  244. } elsif($a[1] eq "days") {
  245. my $t = time() + ($a[2] ? int($a[2]) : 0)*86400;
  246. my @a = localtime($t);
  247. $arg = sprintf("%02d-%02d", $a[4]+1, $a[3]);
  248. } else {
  249. return "unknown argument $a[1], choose one of ".
  250. "yesterday:noArg today:noArg tomorrow:noArg days:2,3,4,5,6,7 MM-DD";
  251. }
  252. return holiday_refresh($hash->{NAME}, $arg);
  253. }
  254. sub
  255. schaltjahr($)
  256. {
  257. my($jahr) = @_;
  258. return 0 if $jahr % 4; # 2009
  259. return 1 unless $jahr % 400; # 2000
  260. return 0 unless $jahr % 100; # 2100
  261. return 1; # 2012
  262. }
  263. ### mh sub western_easter copied from cpan Date::Time::Easter
  264. ### mh changes marked with # mh
  265. ### mh
  266. ### mh calling parameter is 4 digit year
  267. ### mh
  268. sub
  269. western_easter($)
  270. {
  271. my $year = shift;
  272. my $golden_number = $year % 19;
  273. #quasicentury is so named because its a century, only its
  274. # the number of full centuries rather than the current century
  275. my $quasicentury = int($year / 100);
  276. my $epact = ($quasicentury - int($quasicentury/4) -
  277. int(($quasicentury * 8 + 13)/25) + ($golden_number*19) + 15) % 30;
  278. my $interval = $epact - int($epact/28)*
  279. (1 - int(29/($epact+1)) * int((21 - $golden_number)/11) );
  280. my $weekday = ($year + int($year/4) + $interval +
  281. 2 - $quasicentury + int($quasicentury/4)) % 7;
  282. my $offset = $interval - $weekday;
  283. my $month = 3 + int(($offset+40)/44);
  284. my $day = $offset + 28 - 31* int($month/4);
  285. return $month, $day;
  286. }
  287. sub
  288. holiday_FW_detailFn($$$$)
  289. {
  290. my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn.
  291. return "" if($defs{$d}{READONLY});
  292. return FW_pH("cmd=style edit $d.holiday",
  293. "<div class=\"dval\">Edit $d.holiday</div>", 0, "dval", 1);
  294. }
  295. 1;
  296. =pod
  297. =item summary define holidays in a local file
  298. =item summary_DE Urlaubs-/Feiertagskalender aus einer lokalen Datei
  299. =begin html
  300. <a name="holiday"></a>
  301. <h3>holiday</h3>
  302. <ul>
  303. <a name="holidaydefine"></a>
  304. <b>Define</b>
  305. <ul>
  306. <code>define &lt;name&gt; holiday</code>
  307. <br><br>
  308. Define a set of holidays. The module will try to open the file
  309. &lt;name&gt;.holiday in the <a href="#modpath">modpath</a>/FHEM directory
  310. first, then in the modpath/FHEM/holiday directory, the latter containing a
  311. set of predefined files. This list of available holiday files will be shown
  312. if an error occurs at the time of the definition, e.g. if you type "define
  313. help holiday"<br>
  314. If entries in the holiday file match the current day, then the STATE of
  315. this holiday instance displayed in the <a href="#list">list</a> command
  316. will be set to the corresponding values, else the state is set to the text
  317. none. Most probably you'll want to query this value in some perl script:
  318. see Value() in the <a href="#perl">perl</a> section or the global attribute
  319. <a href="#holiday2we"> holiday2we</a>.<br> The file will be reread once
  320. every night, to compute the value for the current day, and by each get
  321. command (see below).<br>
  322. <br>
  323. Holiday file definition:<br>
  324. The file may contain comments (beginning with #) or empty lines.
  325. Significant lines begin with a number (type) and contain some space
  326. separated words, depending on the type. The different types are:<br>
  327. <ul>
  328. <li>1<br>
  329. Exact date. Arguments: &lt;MM-DD&gt; &lt;holiday-name&gt;<br>
  330. Exampe: 1 12-24 Christmas
  331. </li>
  332. <li>2<br>
  333. Easter-dependent date. Arguments: &lt;day-offset&gt;
  334. &lt;holiday-name&gt;.
  335. The offset is counted from Easter-Sunday.
  336. <br>
  337. Exampe: 2 1 Easter-Monday<br>
  338. Sidenote: You can check the easter date with:
  339. fhem> { join("-", western_easter(2011)) }
  340. </li>
  341. <li>3<br>
  342. Month dependent date. Arguments: &lt;nth&gt; &lt;weekday&gt;
  343. &lt;month &lt;holiday-name&gt;.<br>
  344. Examples:<br>
  345. <ul>
  346. 3 1 Mon 05 First Monday In May<br>
  347. 3 2 Mon 05 Second Monday In May<br>
  348. 3 -1 Mon 05 Last Monday In May<br>
  349. 3 0 Mon 05 Each Monday In May<br>
  350. </ul>
  351. </li>
  352. <li>4<br>
  353. Interval. Arguments: &lt;MM-DD&gt; &lt;MM-DD&gt; &lt;holiday-name&gt;
  354. .<br>
  355. Note: An interval cannot contain the year-end.
  356. Example:<br>
  357. <ul>
  358. 4 06-01 06-30 Summer holiday<br>
  359. 4 12-20 01-10 Winter holiday # DOES NOT WORK.
  360. Use the following 2 lines instead:<br>
  361. 4 12-20 12-31 Winter holiday<br>
  362. 4 01-01 01-10 Winter holiday<br>
  363. </ul>
  364. </li>
  365. <li>5<br>
  366. Date relative, weekday fixed holiday. Arguments: &lt;nth&gt;
  367. &lt;weekday&gt; &lt;month&gt; &lt;day&gt; &lt; holiday-name&gt;<br>
  368. Note that while +0 or -0 as offsets are not forbidden, their behaviour
  369. is undefined in the sense that it might change without notice.<br>
  370. Examples:<br>
  371. <ul>
  372. 5 -1 Wed 11 23 Buss und Bettag (first Wednesday before Nov, 23rd)<br>
  373. 5 1 Mon 01 31 First Monday after Jan, 31st (1st Monday in February)<br>
  374. </ul>
  375. </li>
  376. </ul>
  377. </ul>
  378. <br>
  379. <a name="holidayset"></a>
  380. <b>Set</b>
  381. <ul>
  382. <li>createPrivateCopy<br>
  383. <ul>
  384. if the holiday file is opened from the FHEM/holiday directory (which is
  385. refreshed by FHEM-update), then it is readonly, and should not be
  386. modified. With createPrivateCopy the file will be copied to the FHEM
  387. directory, where it can be modified.
  388. </ul></li>
  389. <li>deletePrivateCopy<br>
  390. <ul>
  391. delete the private copy, see createPrivateCopy above
  392. </ul></li>
  393. <li>reload<br>
  394. <ul>
  395. set the state, tomorrow and yesterday readings. Useful after manually
  396. editing the file.
  397. </ul></li>
  398. </ul><br>
  399. <a name="holidayget"></a>
  400. <b>Get</b>
  401. <ul>
  402. <code>get &lt;name&gt; &lt;MM-DD&gt;</code><br>
  403. <code>get &lt;name&gt; yesterday</code><br>
  404. <code>get &lt;name&gt; today</code><br>
  405. <code>get &lt;name&gt; tomorrow</code><br>
  406. <code>get &lt;name&gt; days &lt;offset&gt;</code><br>
  407. <br><br>
  408. Return the holiday name of the specified date or the text none.
  409. <br><br>
  410. </ul>
  411. <br>
  412. <a name="holidayattr"></a>
  413. <b>Attributes</b><ul>N/A</ul><br>
  414. </ul>
  415. =end html
  416. =begin html_DE
  417. <a name="holiday"></a>
  418. <h3>holiday</h3>
  419. <ul>
  420. <a name="holidaydefine"></a>
  421. <b>Define</b>
  422. <ul>
  423. <code>define &lt;name&gt; holiday</code>
  424. <br><br>
  425. Definiert einen Satz mit Urlaubsinformationen. Das Modul versucht die
  426. Datei &lt;name&gt;.holiday erst in <a href="#modpath">modpath</a>/FHEM zu
  427. &ouml;ffnen, und dann in modpath/FHEM/holiday, Letzteres enth&auml;lt eine
  428. Liste von per FHEM-update verteilten Dateien f&uuml;r diverse
  429. (Bundes-)L&auml;nder. Diese Liste wird bei einer Fehlermeldung angezeigt.
  430. Wenn Eintr&auml;ge im der Datei auf den aktuellen Tag passen wird der STATE
  431. der Holiday-Instanz die im <a href="#list">list</a> Befehl angezeigt wird
  432. auf die entsprechenden Werte gesetzt. Andernfalls ist der STATE auf den
  433. Text "none" gesetzt.
  434. Meistens wird dieser Wert mit einem Perl Script abgefragt: siehe Value() im
  435. <a href="#perl">perl</a> Abschnitt oder im globalen Attribut <a
  436. href="#holiday2we"> holiday2we</a>.<br> Die Datei wird jede Nacht neu
  437. eingelesen um den Wert des aktuellen Tages zu erzeugen. Auch jeder "get"
  438. Befehl liest die Datei neu ein.
  439. <br><br>
  440. Holiday file Definition:<br>
  441. Die Datei darf Kommentare, beginnend mit #, und Leerzeilen enthalten. Die
  442. entscheidenden Zeilen beginnen mit einer Zahl (Typ) und enthalten durch
  443. Leerzeichen getrennte W&ouml;rter, je nach Typ. Die verschiedenen Typen
  444. sind:<br>
  445. <ul>
  446. <li>1<br>
  447. Genaues Datum. Argument: &lt;MM-TT&gt; &lt;Feiertag-Name&gt;<br>
  448. Beispiel: 1 12-24 Weihnachten
  449. </li>
  450. <li>2<br>
  451. Oster-abh&auml;ngiges Datum. Argument: &lt;Tag-Offset&gt;
  452. &lt;Feiertag-Name&gt;.
  453. Der Offset wird vom Oster-Sonntag an gez&auml;hlt.
  454. <br>
  455. Beispiel: 2 1 Oster-Montag<br>
  456. Hinweis: Das Osterdatum kann vorher gepr&uuml;ft werden:
  457. fhem> { join("-", western_easter(2011)) }
  458. </li>
  459. <li>3<br>
  460. Monats-abh&auml;ngiges Datum. Argument: &lt;X&gt; &lt;Wochentag&gt;
  461. &lt;Monat&gt; &lt;Feiertag-Name&gt;.<br>
  462. Beispiel:<br>
  463. <ul>
  464. 3 1 Mon 05 Erster Montag In Mai<br>
  465. 3 2 Mon 05 Zweiter Montag In Mai<br>
  466. 3 -1 Mon 05 Letzter Montag In Mai<br>
  467. 3 0 Mon 05 Jeder Montag In Mai<br>
  468. </ul>
  469. </li>
  470. <li>4<br>
  471. Intervall. Argument: &lt;MM-TT&gt; &lt;MM-TT&gt; &lt;Feiertag-Name&gt;
  472. .<br>
  473. Achtung: Ein Intervall darf kein Jahresende enthalten.
  474. Beispiel:<br>
  475. <ul>
  476. 4 06-01 06-30 Sommerferien<br>
  477. 4 12-20 01-10 Winterferien # FUNKTIONIER NICHT,
  478. stattdessen folgendes verwenden:<br>
  479. 4 12-20 12-31 Winterferien<br>
  480. 4 01-01 01-10 Winterferien<br>
  481. </ul>
  482. </li>
  483. <li>5<br>
  484. Datum relativ, Wochentags ein fester Urlaubstag/Feiertag. Argument:
  485. &lt;X&gt; &lt;Wochentag&gt; &lt;Monat&gt; &lt;Tag&gt;
  486. &lt;Feiertag-Name&gt;<br> Hinweis: Da +0 oder -0 als Offset nicht
  487. verboten sind, ist das Verhalten hier nicht definiert, kann sich also
  488. ohne Info &auml;ndern;<br>
  489. Beispiel:<br>
  490. <ul>
  491. 5 -1 Wed 11 23 Buss und Bettag (erster Mittwoch vor dem 23. Nov)<br>
  492. 5 1 Mon 01 31 Erster Montag in Februar<br>
  493. </ul>
  494. </li>
  495. </ul>
  496. </ul>
  497. <br>
  498. <a name="holidayset"></a>
  499. <b>Set</b>
  500. <ul>
  501. <li>createPrivateCopy<br>
  502. <ul>
  503. Falls die Datei in der FHEM/holiday Verzeichnis ge&ouml;ffnet wurde,
  504. dann ist sie nicht beschreibbar, da dieses Verzeichnis mit FHEM
  505. update aktualisiert wird. Mit createPrivateCopy kann eine private Kopie
  506. im FHEM Verzeichnis erstellt werden.
  507. </ul></li>
  508. <li>deletePrivateCopy<br>
  509. <ul>
  510. Entfernt die private Kopie, siehe auch createPrivateCopy
  511. </ul></li>
  512. <li>reload<br>
  513. <ul>
  514. setzt die state, tomorrow und yesterday Readings. Wird nach einem
  515. manuellen Bearbeiten der .holiday Datei ben&ouml;tigt.
  516. </ul></li>
  517. </ul><br>
  518. <a name="holidayget"></a>
  519. <b>Get</b>
  520. <ul>
  521. <code>get &lt;name&gt; &lt;MM-DD&gt;</code><br>
  522. <code>get &lt;name&gt; yesterday</code><br>
  523. <code>get &lt;name&gt; today</code><br>
  524. <code>get &lt;name&gt; tomorrow</code><br>
  525. <code>get &lt;name&gt; days &lt;offset&gt;</code><br>
  526. <br><br>
  527. Gibt den Name des Feiertages zum angebenenen Datum zur&uuml;ck oder den
  528. Text none.
  529. <br><br>
  530. </ul>
  531. <br>
  532. <a name="holidayattr"></a>
  533. <b>Attributes</b><ul>
  534. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  535. </ul><br>
  536. </ul>
  537. =end html_DE
  538. =cut