98_alarmclock.pm 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593
  1. # $Id: 98_alarmclock.pm 14771 2017-07-23 10:05:19Z FlorianZ $
  2. ########################################################################################
  3. #
  4. # 98_alarmclock.pm
  5. # Fhem Modul to set up a Alarmclock
  6. #
  7. # 2017 Florian Zetlmeisl
  8. #
  9. # Parts of the holiday and vacation identification
  10. # are written by Prof. Dr. Peter A. Henning
  11. #
  12. # This programm is free software; you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation; either version 2 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # The GNU General Public License can be found at
  18. # http://www.gnu.org/copyleft/gpl.html.
  19. # A copy is found in the textfile GPL.txt and important notices to the license
  20. # from the author is found in LICENSE.txt distributed with these scripts.
  21. #
  22. # This script is distributed in the hope that it will be useful,
  23. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. # GNU General Public License for more details.
  26. #
  27. ########################################################################################
  28. package main;
  29. use strict;
  30. use warnings;
  31. ########################################################################################
  32. #
  33. # Globale Variablen
  34. #
  35. ########################################################################################
  36. my %alarmclock_sets =
  37. (
  38. "AlarmTime1_Monday" => "09:00",
  39. "AlarmTime2_Tuesday" => "09:00",
  40. "AlarmTime3_Wednesday" => "09:00",
  41. "AlarmTime4_Thursday" => "09:00",
  42. "AlarmTime5_Friday" => "09:00",
  43. "AlarmTime6_Saturday" => "10:00",
  44. "AlarmTime7_Sunday" => "10:00",
  45. "AlarmTime8_Holiday" => "10:00",
  46. "AlarmTime9_Vacation" => "10:00",
  47. "AlarmOff" => "NONE",
  48. "AlarmTime_Weekdays" => "09:00",
  49. "AlarmTime_Weekend" => "09:00",
  50. "stop" => "NONE",
  51. "skip" => "NONE",
  52. "save" => "NONE",
  53. "load" => "NONE",
  54. "disable" => "0"
  55. );
  56. my %alarmday =
  57. (
  58. "1" => "AlarmTime1_Monday",
  59. "2" => "AlarmTime2_Tuesday",
  60. "3" => "AlarmTime3_Wednesday",
  61. "4" => "AlarmTime4_Thursday",
  62. "5" => "AlarmTime5_Friday",
  63. "6" => "AlarmTime6_Saturday",
  64. "0" => "AlarmTime7_Sunday",
  65. "8" => "AlarmTime8_Holiday",
  66. "9" => "AlarmTime9_Vacation"
  67. );
  68. my @mapping_attrs =
  69. qw(
  70. AlarmRoutine:textField-long
  71. AlarmRoutineOff:textField-long
  72. PreAlarmRoutine:textField-long
  73. OffRoutine:textField-long
  74. HardAlarmRoutine:textField-long
  75. SnoozeRoutine:textField-long
  76. RepRoutine1:textField-long
  77. RepRoutine2:textField-long
  78. RepRoutine3:textField-long
  79. );
  80. ########################################################################################
  81. #
  82. # Alarmclock Initialize
  83. #
  84. ########################################################################################
  85. sub alarmclock_Initialize($)
  86. {
  87. my ($hash) = @_;
  88. $hash->{DefFn} = "alarmclock_Define";
  89. $hash->{UndefFn} = "alarmclock_Undefine";
  90. $hash->{SetFn} = "alarmclock_Set";
  91. $hash->{AttrFn} = "alarmclock_Attr";
  92. $hash->{NotifyFn} = "alarmclock_Notify";
  93. $hash->{AttrList} = " "
  94. . join( " ", @mapping_attrs )
  95. . " PreAlarmRoutine"
  96. . " AlarmRoutine"
  97. . " AlarmRoutineOff"
  98. . " PreAlarmTimeInSec"
  99. . " EventForSnooze"
  100. . " EventForAlarmOff"
  101. . " SnoozeTimeInSec"
  102. . " OffDefaultTime"
  103. . " OffRoutine"
  104. . " HardAlarmTimeInSec"
  105. . " HardAlarmRoutine"
  106. . " MaxAlarmDurationInSec"
  107. . " SnoozeRoutine"
  108. . " HolidayDevice"
  109. . " HolidayCheck:1,0"
  110. . " HolidayDays"
  111. . " VacationDevice"
  112. . " VacationCheck:1,0"
  113. . " VacationDays"
  114. . " PresenceDevice"
  115. . " PresenceCheck:1,0"
  116. . " RepRoutine1"
  117. . " RepRoutine1WaitInSec"
  118. . " RepRoutine1Repeats"
  119. . " RepRoutine1Mode:Alarm,PreAlarm,off"
  120. . " RepRoutine1Stop:Snooze,off"
  121. . " RepRoutine2"
  122. . " RepRoutine2WaitInSec"
  123. . " RepRoutine2Repeats"
  124. . " RepRoutine2Mode:Alarm,PreAlarm,off"
  125. . " RepRoutine2Stop:Snooze,off"
  126. . " RepRoutine3"
  127. . " RepRoutine3WaitInSec"
  128. . " RepRoutine3Repeats"
  129. . " RepRoutine3Mode:Alarm,PreAlarm,off"
  130. . " RepRoutine3Stop:Snooze,off"
  131. . " WeekprofileName"
  132. . " disable:1,0"
  133. . " $readingFnAttributes";
  134. }
  135. ########################################################################################
  136. #
  137. # Alarmclock Define
  138. #
  139. ########################################################################################
  140. sub alarmclock_Define($$)
  141. {
  142. my ($hash, $def) = @_;
  143. my @a = split("[ \t][ \t]*", $def);
  144. my ($name, $type) = @a;
  145. return "Wrong syntax: use define <name> alarmclock" if(int(@a) != 2);
  146. $hash->{helper}{Repeat1} = 0;
  147. $hash->{helper}{Repeat2} = 0;
  148. $hash->{helper}{Repeat3} = 0;
  149. $hash->{helper}{Today} = 0;
  150. $hash->{helper}{Tomorrow} = 0;
  151. return undef;
  152. }
  153. ########################################################################################
  154. #
  155. # Alarmclock Undefine
  156. #
  157. ########################################################################################
  158. sub alarmclock_Undefine($$)
  159. {
  160. my ($hash,$arg) = @_;
  161. RemoveInternalTimer($hash);
  162. return undef;
  163. }
  164. ########################################################################################
  165. #
  166. # Alarmclock Set
  167. #
  168. ########################################################################################
  169. sub alarmclock_Set($$)
  170. {
  171. my ($hash, @param) = @_;
  172. my $name = shift @param;
  173. my $opt = shift @param;
  174. my $value = join("", @param);
  175. my $Weekprofile = AttrVal($hash->{NAME},"WeekprofileName","Weekprofile_1,Weekprofile_2,Weekprofile_3,Weekprofile_4,Weekprofile_5");
  176. if(!defined($alarmclock_sets{$opt})) {
  177. my $list = " AlarmTime1_Monday"
  178. ." AlarmTime2_Tuesday"
  179. ." AlarmTime3_Wednesday"
  180. ." AlarmTime4_Thursday"
  181. ." AlarmTime5_Friday"
  182. ." AlarmTime6_Saturday"
  183. ." AlarmTime7_Sunday"
  184. ." AlarmTime8_Holiday"
  185. ." AlarmTime9_Vacation"
  186. ." AlarmOff:1_Monday,2_Tuesday,3_Wednesday,4_Thursday,5_Friday,6_Saturday,7_Sunday,8_Holiday,9_Vacation,Weekdays,Weekend,All"
  187. ." AlarmTime_Weekdays"
  188. ." AlarmTime_Weekend"
  189. ." stop:Alarm"
  190. ." skip:NextAlarm,None"
  191. ." save:$Weekprofile"
  192. ." load:$Weekprofile"
  193. ." disable:1,0";
  194. return "Unknown argument $opt, choose one of $list";
  195. }
  196. ### AlarmTime ###
  197. if ($opt =~ /^AlarmTime(1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation)/)
  198. {
  199. if ($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/)
  200. {
  201. readingsSingleUpdate( $hash, $opt, $value, 1 );
  202. alarmclock_createtimer($hash);
  203. }
  204. elsif (!($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/))
  205. {
  206. return "Please Set $opt HH:MM" ;
  207. }
  208. }
  209. ### AlarmOff ###
  210. if ($opt eq "AlarmOff")
  211. {
  212. if ($value =~ /^(1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation)$/)
  213. {
  214. readingsSingleUpdate( $hash, "AlarmTime$value", "off", 1 );
  215. alarmclock_createtimer($hash);
  216. }
  217. elsif ($value eq "Weekdays")
  218. {
  219. readingsBeginUpdate($hash);
  220. readingsBulkUpdate( $hash, "AlarmTime1_Monday", "off");
  221. readingsBulkUpdate( $hash, "AlarmTime2_Tuesday", "off");
  222. readingsBulkUpdate( $hash, "AlarmTime3_Wednesday", "off");
  223. readingsBulkUpdate( $hash, "AlarmTime4_Thursday", "off");
  224. readingsBulkUpdate( $hash, "AlarmTime5_Friday", "off");
  225. readingsEndUpdate($hash,1);
  226. alarmclock_createtimer($hash);
  227. }
  228. elsif ($value eq "Weekend")
  229. {
  230. readingsBeginUpdate($hash);
  231. readingsBulkUpdate( $hash, "AlarmTime6_Saturday", "off");
  232. readingsBulkUpdate( $hash, "AlarmTime7_Sunday", "off");
  233. readingsEndUpdate($hash,1);
  234. alarmclock_createtimer($hash);
  235. }
  236. elsif ($value eq "All")
  237. {
  238. readingsBeginUpdate($hash);
  239. readingsBulkUpdate( $hash, "AlarmTime1_Monday", "off");
  240. readingsBulkUpdate( $hash, "AlarmTime2_Tuesday", "off");
  241. readingsBulkUpdate( $hash, "AlarmTime3_Wednesday", "off");
  242. readingsBulkUpdate( $hash, "AlarmTime4_Thursday", "off");
  243. readingsBulkUpdate( $hash, "AlarmTime5_Friday", "off");
  244. readingsBulkUpdate( $hash, "AlarmTime6_Saturday", "off");
  245. readingsBulkUpdate( $hash, "AlarmTime7_Sunday", "off");
  246. readingsBulkUpdate( $hash, "AlarmTime8_Holiday", "off");
  247. readingsBulkUpdate( $hash, "AlarmTime9_Vacation", "off");
  248. readingsEndUpdate($hash,1);
  249. alarmclock_createtimer($hash);
  250. }
  251. elsif (!($value =~ /^(1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation|Weekdays|Weekend|All)$/))
  252. {
  253. return "Please Set $opt (1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation|Weekdays|Weekend|All)";
  254. }
  255. }
  256. ### AlarmTime_Weekdays ###
  257. if ($opt eq "AlarmTime_Weekdays")
  258. {
  259. if ($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/)
  260. {
  261. readingsBeginUpdate($hash);
  262. readingsBulkUpdate( $hash, "AlarmTime1_Monday", $value);
  263. readingsBulkUpdate( $hash, "AlarmTime2_Tuesday", $value);
  264. readingsBulkUpdate( $hash, "AlarmTime3_Wednesday", $value);
  265. readingsBulkUpdate( $hash, "AlarmTime4_Thursday", $value);
  266. readingsBulkUpdate( $hash, "AlarmTime5_Friday", $value);
  267. readingsEndUpdate($hash,1);
  268. alarmclock_createtimer($hash);
  269. }
  270. elsif (!($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/))
  271. {
  272. return "Please Set $opt HH:MM" ;
  273. }
  274. }
  275. ### AlarmTime_Weekend ###
  276. if ($opt eq "AlarmTime_Weekend")
  277. {
  278. if ($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/)
  279. {
  280. readingsBeginUpdate($hash);
  281. readingsBulkUpdate( $hash, "AlarmTime6_Saturday", $value);
  282. readingsBulkUpdate( $hash, "AlarmTime7_Sunday", $value);
  283. readingsEndUpdate($hash,1);
  284. alarmclock_createtimer($hash);
  285. }
  286. elsif (!($value =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):[0-5]?[0-9]$/))
  287. {
  288. return "Please Set $opt HH:MM" ;
  289. }
  290. }
  291. ### stop Alarm ###
  292. if ($opt eq "stop")
  293. {
  294. if (($value eq "Alarm") && ((ReadingsVal($hash->{NAME},"state",0)) =~ /^(Alarm is running|Snooze for.*)/))
  295. {
  296. alarmclock_alarmroutine_stop($hash);
  297. }
  298. }
  299. ### save Weekprofile ###
  300. if ($opt eq "save")
  301. {
  302. my $time1 = ReadingsVal($hash->{NAME},"AlarmTime1_Monday","off");
  303. my $time2 = ReadingsVal($hash->{NAME},"AlarmTime2_Tuesday","off");
  304. my $time3 = ReadingsVal($hash->{NAME},"AlarmTime3_Wednesday","off");
  305. my $time4 = ReadingsVal($hash->{NAME},"AlarmTime4_Thursday","off");
  306. my $time5 = ReadingsVal($hash->{NAME},"AlarmTime5_Friday","off");
  307. my $time6 = ReadingsVal($hash->{NAME},"AlarmTime6_Saturday","off");
  308. my $time7 = ReadingsVal($hash->{NAME},"AlarmTime7_Sunday","off");
  309. readingsSingleUpdate( $hash, $value,"$time1,$time2,$time3,$time4,$time5,$time6,$time7", 1 );
  310. }
  311. ### load Weekprofile ###
  312. if ($opt eq "load")
  313. {
  314. my @time = split(/,/, ReadingsVal($hash->{NAME}, $value,""));
  315. readingsBeginUpdate($hash);
  316. readingsBulkUpdate( $hash, "AlarmTime1_Monday", $time[0]);
  317. readingsBulkUpdate( $hash, "AlarmTime2_Tuesday", $time[1]);
  318. readingsBulkUpdate( $hash, "AlarmTime3_Wednesday", $time[2]);
  319. readingsBulkUpdate( $hash, "AlarmTime4_Thursday", $time[3]);
  320. readingsBulkUpdate( $hash, "AlarmTime5_Friday", $time[4]);
  321. readingsBulkUpdate( $hash, "AlarmTime6_Saturday", $time[5]);
  322. readingsBulkUpdate( $hash, "AlarmTime7_Sunday", $time[6]);
  323. readingsEndUpdate($hash,1);
  324. alarmclock_createtimer($hash);
  325. }
  326. ### skip ###
  327. if ($opt eq "skip")
  328. {
  329. if ($value eq "NextAlarm")
  330. {
  331. readingsBeginUpdate($hash);
  332. readingsBulkUpdate( $hash, "state", "skip next Alarm");
  333. readingsBulkUpdate( $hash, "skip", "next Alarm");
  334. readingsEndUpdate($hash,1);
  335. alarmclock_createtimer($hash);
  336. }
  337. if ($value eq "None")
  338. {
  339. readingsSingleUpdate( $hash, "skip", "none", 1 );
  340. alarmclock_createtimer($hash);
  341. }
  342. }
  343. ### disable ###
  344. if ($opt eq "disable")
  345. {
  346. if ($value eq "1")
  347. {
  348. RemoveInternalTimer($hash);
  349. readingsSingleUpdate( $hash,"state", "deactivated", 1 );
  350. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - deactivated";
  351. }
  352. if ($value eq "0")
  353. {
  354. readingsSingleUpdate( $hash,"state", "activated", 1 );
  355. alarmclock_createtimer($hash);
  356. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - activated";
  357. }
  358. }
  359. return undef;
  360. }
  361. ########################################################################################
  362. #
  363. # Alarmclock Attr
  364. #
  365. ########################################################################################
  366. sub alarmclock_Attr(@)
  367. {
  368. my ($cmd,$name,$attr_name,$attrVal) = @_;
  369. my $hash = $defs{$name};
  370. if(($attr_name eq "OffDefaultTime")
  371. && ($attrVal =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):([0-5]?[0-9])$/))
  372. {
  373. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  374. }
  375. if(($attr_name eq "PreAlarmTimeInSec")
  376. && ($attrVal =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/))
  377. {
  378. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  379. }
  380. ###disable###
  381. if($attr_name eq "disable")
  382. {
  383. if( $cmd eq "set" )
  384. {
  385. if($attrVal eq "1")
  386. {
  387. RemoveInternalTimer($hash);
  388. readingsSingleUpdate( $hash,"state", "deactivated", 1 );
  389. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - deactivated";
  390. }
  391. elsif($attrVal eq "0")
  392. {
  393. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  394. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - activated";
  395. }
  396. }
  397. elsif( $cmd eq "del" )
  398. {
  399. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  400. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - activated";
  401. }
  402. }
  403. ###Holiday###
  404. if($attr_name eq "HolidayCheck")
  405. {
  406. RemoveInternalTimer($hash);
  407. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  408. }
  409. ###Vacation###
  410. if($attr_name eq "VacationCheck")
  411. {
  412. RemoveInternalTimer($hash);
  413. InternalTimer(gettimeofday()+1, "alarmclock_createtimer", $hash, 0);
  414. }
  415. return undef;
  416. }
  417. ########################################################################################
  418. #
  419. # Timer für die heutige Alarmzeit wird erstellt
  420. #
  421. ########################################################################################
  422. sub alarmclock_createtimer($)
  423. {
  424. my ($hash) = @_;
  425. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  426. $hash->{helper}{Today} = $WDayNow;
  427. if ($WDayNow =~ /^(0|1|2|3|4|5)/)
  428. {
  429. $hash->{helper}{Tomorrow} = $WDayNow + 1;
  430. }
  431. else
  432. {
  433. $hash->{helper}{Tomorrow} = 0;
  434. }
  435. my $HourinSec = $HourNow * 3600;
  436. my $MininSec = $MinNow * 60;
  437. my $NowinSec = $HourinSec + $MininSec + $SecNow;
  438. if ((AttrVal($hash->{NAME}, "disable", 0 ) ne "1" ) && (ReadingsVal($hash->{NAME},"state","activated") ne "deactivated"))
  439. {
  440. ### Vacation ###
  441. alarmclock_vacation_check($hash);
  442. ### Holiday ###
  443. alarmclock_holiday_check($hash);
  444. my $alarmtimetoday = $alarmday{$hash->{helper}{Today}};
  445. my $alarmtimetomorrow = $alarmday{$hash->{helper}{Tomorrow}};
  446. if ((ReadingsVal($hash->{NAME},$alarmtimetoday,"NONE")) =~ /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/)
  447. {
  448. ReadingsVal($hash->{NAME},$alarmtimetoday,"NONE") =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):([0-5]?[0-9])$/;
  449. my $AlarmHour = 0;
  450. my $AlarmMin = 0;
  451. $AlarmHour = $1;
  452. $AlarmMin = $2;
  453. my $AlarmHourinSec = $AlarmHour * 3600;
  454. my $AlarmMininSec = $AlarmMin * 60;
  455. my $AlarminSec = $AlarmHourinSec + $AlarmMininSec;
  456. if(($NowinSec < $AlarminSec) && (ReadingsVal($hash->{NAME},"skip","none") eq "none"))
  457. {
  458. my $AlarmIn = $AlarminSec - $NowinSec;
  459. RemoveInternalTimer($hash);
  460. InternalTimer(gettimeofday()+$AlarmIn, "alarmclock_alarmroutine_start", $hash, 0);
  461. readingsSingleUpdate( $hash,"state", "next Alarm at $AlarmHour:$AlarmMin", 1 );
  462. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - alarm-timer created with $AlarmIn sec";
  463. ### PreAlarm ###
  464. if((AttrVal($hash->{NAME},"PreAlarmTimeInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  465. {
  466. my $PreAlarmTime = AttrVal($hash->{NAME},"PreAlarmTimeInSec","NONE");
  467. if($NowinSec < $AlarminSec - $PreAlarmTime)
  468. {
  469. my $PreAlarmIn = $AlarmIn - $PreAlarmTime;
  470. InternalTimer(gettimeofday()+$PreAlarmIn, "alarmclock_prealarmroutine_start", $hash, 0);
  471. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - pre-alarm timer created with $PreAlarmIn sec";
  472. }
  473. else
  474. {
  475. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - pre-alarm time has been in the past";
  476. }
  477. }
  478. else
  479. {
  480. Log3 $hash->{NAME}, 4, "alarmclock: $hash->{NAME} - no PreAlarmTimeInSec is set";
  481. }
  482. ### End PreAlarm ###
  483. }
  484. ### skip next Alarmtime ###
  485. elsif(($NowinSec < $AlarminSec) && (ReadingsVal($hash->{NAME},"skip","none") ne "none"))
  486. {
  487. my $AlarmIn2 = $AlarminSec - $NowinSec;
  488. RemoveInternalTimer($hash);
  489. InternalTimer(gettimeofday()+$AlarmIn2, "alarmclock_skip", $hash, 0);
  490. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - skip next Alarm";
  491. }
  492. ### End skip next Alarmtime ###
  493. else
  494. {
  495. alarmclock_midnight_timer($hash);
  496. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - alarm time today has been in the past => midnight-timer started.";
  497. }
  498. }
  499. ### OffDefaultTime ###
  500. elsif((ReadingsVal($hash->{NAME},$alarmtimetoday,"NONE")) eq "off")
  501. {
  502. if((AttrVal($hash->{NAME},"OffDefaultTime","NONE")) =~ /^([0-9]|0[0-9]|1?[0-9]|2[0-3]):([0-5]?[0-9])$/)
  503. {
  504. my $OffDefaultTimeHour = 0;
  505. my $OffDefaultTimeMin = 0;
  506. $OffDefaultTimeHour = $1;
  507. $OffDefaultTimeMin = $2;
  508. my $OffDefaultTimeHourinSec = $OffDefaultTimeHour * 3600;
  509. my $OffDefaultTimeMininSec = $OffDefaultTimeMin * 60;
  510. my $OffDefaultTimeinSec = $OffDefaultTimeHourinSec + $OffDefaultTimeMininSec;
  511. if($NowinSec < $OffDefaultTimeinSec)
  512. {
  513. my $OffDefaultTimeIn = $OffDefaultTimeinSec - $NowinSec;
  514. RemoveInternalTimer($hash);
  515. InternalTimer(gettimeofday()+$OffDefaultTimeIn, "alarmclock_offroutine_start", $hash, 0);
  516. readingsSingleUpdate( $hash,"state", "next OffRoutine at $OffDefaultTimeHour:$OffDefaultTimeMin", 1 );
  517. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - off-routine-timer created with $OffDefaultTimeIn sec";
  518. }
  519. else
  520. {
  521. alarmclock_midnight_timer($hash);
  522. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - OffDefaultTime has been in the past";
  523. }
  524. }
  525. else
  526. {
  527. alarmclock_midnight_timer($hash);
  528. Log3 $hash->{NAME}, 4, "alarmclock: $hash->{NAME} - no OffDefaultTime is set";
  529. }
  530. }
  531. ### End OffDefaultTime ###
  532. else
  533. {
  534. alarmclock_midnight_timer($hash);
  535. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - no alarm today => midnight-timer started";
  536. }
  537. ### Alarm Reading ###
  538. my $AlarmToday = ReadingsVal($hash->{NAME},$alarmtimetoday," ");
  539. my $AlarmTomorrow = ReadingsVal($hash->{NAME},$alarmtimetomorrow," ");
  540. readingsBeginUpdate($hash);
  541. readingsBulkUpdate( $hash, "AlarmToday", $AlarmToday);
  542. readingsBulkUpdate( $hash, "AlarmTomorrow", $AlarmTomorrow);
  543. readingsEndUpdate($hash,1);
  544. }
  545. }
  546. ########################################################################################
  547. #
  548. # Midnight-timer + 5 seconds
  549. #
  550. ########################################################################################
  551. sub alarmclock_midnight_timer($)
  552. {
  553. my ($hash) = @_;
  554. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  555. my $HourinSec = $HourNow * 3600;
  556. my $MininSec = $MinNow * 60;
  557. my $NowinSec = $HourinSec + $MininSec + $SecNow;
  558. my $SectoMidnight = 86405 - $NowinSec;
  559. if ((AttrVal($hash->{NAME}, "disable", 0 ) ne "1" ) && (ReadingsVal($hash->{NAME},"state","activated") ne "deactivated"))
  560. {
  561. RemoveInternalTimer($hash);
  562. InternalTimer(gettimeofday()+$SectoMidnight, "alarmclock_createtimer", $hash, 0);
  563. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - midnight-timer created with $SectoMidnight sec.";
  564. if (ReadingsVal($hash->{NAME},"skip","none") ne "none")
  565. {
  566. readingsSingleUpdate( $hash, "state", "skip next Alarm", 1);
  567. }
  568. else
  569. {
  570. readingsSingleUpdate( $hash,"state", "OK", 1 );
  571. }
  572. }
  573. }
  574. ########################################################################################
  575. #
  576. # Alarm-Routine start
  577. #
  578. ########################################################################################
  579. sub alarmclock_alarmroutine_start($)
  580. {
  581. my ($hash) = @_;
  582. my $Mode = "Alarm";
  583. if (alarmclock_presence_check($hash))
  584. {
  585. fhem("".AttrVal($hash->{NAME},"AlarmRoutine",""));
  586. readingsSingleUpdate( $hash,"state", "Alarm is running", 1 );
  587. alarmclock_hardalarm_timer($hash);
  588. alarmclock_maxalarmduration_timer($hash);
  589. alarmclock_reproutine($hash, $Mode);
  590. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - AlarmRoutine started.";
  591. }
  592. else
  593. {
  594. alarmclock_createtimer($hash);
  595. }
  596. }
  597. ########################################################################################
  598. #
  599. # Alarm-Routine stop
  600. #
  601. ########################################################################################
  602. sub alarmclock_alarmroutine_stop($)
  603. {
  604. my ($hash) = @_;
  605. fhem("".AttrVal($hash->{NAME},"AlarmRoutineOff",""));
  606. readingsSingleUpdate( $hash,"state", "Alarm stopped", 1 );
  607. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - alarmroutine stopped.";
  608. RemoveInternalTimer($hash, "alarmclock_hardalarmroutine_start");
  609. RemoveInternalTimer($hash, "alarmclock_alarmroutine_stop");
  610. alarmclock_createtimer($hash);
  611. }
  612. ########################################################################################
  613. #
  614. # Pre-Alarm-Routine start
  615. #
  616. ########################################################################################
  617. sub alarmclock_prealarmroutine_start($)
  618. {
  619. my ($hash) = @_;
  620. my $Mode = "PreAlarm";
  621. if (alarmclock_presence_check($hash))
  622. {
  623. fhem("".AttrVal($hash->{NAME},"PreAlarmRoutine",""));
  624. readingsSingleUpdate( $hash,"state", "PreAlarm is running", 1 );
  625. alarmclock_reproutine($hash, $Mode);
  626. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - PreAlarmRoutine started.";
  627. }
  628. }
  629. ########################################################################################
  630. #
  631. # Alarm Snooze
  632. #
  633. ########################################################################################
  634. sub alarmclock_snooze_start($)
  635. {
  636. my ($hash) = @_;
  637. my $Mode = "Snooze";
  638. if((AttrVal($hash->{NAME},"SnoozeTimeInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  639. {
  640. my $SnoozeTime = AttrVal($hash->{NAME},"SnoozeTimeInSec","");
  641. fhem("".AttrVal($hash->{NAME},"SnoozeRoutine",""));
  642. InternalTimer(gettimeofday()+$SnoozeTime, "alarmclock_alarmroutine_start", $hash, 0);
  643. readingsSingleUpdate( $hash,"state", "Snooze for $SnoozeTime sec", 1 );
  644. RemoveInternalTimer($hash, "alarmclock_hardalarmroutine_start");
  645. RemoveInternalTimer($hash, "alarmclock_alarmroutine_stop");
  646. alarmclock_reproutine_stop($hash, $Mode);
  647. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - snooze-timer created with $SnoozeTime sec.";
  648. }
  649. else
  650. {
  651. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - no SnoozeTimeInSec is set.";
  652. }
  653. }
  654. ########################################################################################
  655. #
  656. # Alarm OffRoutine
  657. #
  658. ########################################################################################
  659. sub alarmclock_offroutine_start($)
  660. {
  661. my ($hash) = @_;
  662. fhem("".AttrVal($hash->{NAME},"OffRoutine",""));
  663. readingsSingleUpdate( $hash,"state", "OffRoutine is running", 1 );
  664. alarmclock_createtimer($hash);
  665. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - OffRoutine started.";
  666. }
  667. ########################################################################################
  668. #
  669. # HardAlarm Timer
  670. #
  671. ########################################################################################
  672. sub alarmclock_hardalarm_timer($)
  673. {
  674. my ($hash) = @_;
  675. if((AttrVal($hash->{NAME},"HardAlarmTimeInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  676. {
  677. my $HardAlarmTime = AttrVal($hash->{NAME},"HardAlarmTimeInSec","");
  678. InternalTimer(gettimeofday()+$HardAlarmTime, "alarmclock_hardalarmroutine_start", $hash, 0);
  679. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - HardAlarm created with $HardAlarmTime sec.";
  680. }
  681. else
  682. {
  683. Log3 $hash->{NAME}, 4, "alarmclock: $hash->{NAME} - no HardAlarmTimeInSec is set.";
  684. }
  685. }
  686. ########################################################################################
  687. #
  688. # MaxAlarmDuration
  689. #
  690. ########################################################################################
  691. sub alarmclock_maxalarmduration_timer($)
  692. {
  693. my ($hash) = @_;
  694. if((AttrVal($hash->{NAME},"MaxAlarmDurationInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  695. {
  696. my $MaxAlarmDuration = AttrVal($hash->{NAME},"MaxAlarmDurationInSec","");
  697. InternalTimer(gettimeofday()+$MaxAlarmDuration, "alarmclock_alarmroutine_stop", $hash, 0);
  698. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - MaxAlarmDuration created with $MaxAlarmDuration sec.";
  699. }
  700. }
  701. ########################################################################################
  702. #
  703. # HardAlarm start
  704. #
  705. ########################################################################################
  706. sub alarmclock_hardalarmroutine_start($)
  707. {
  708. my ($hash) = @_;
  709. fhem("".AttrVal($hash->{NAME},"HardAlarmRoutine",""));
  710. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - HardAlarmRoutine started.";
  711. }
  712. ########################################################################################
  713. #
  714. # RepRoutine
  715. #
  716. ########################################################################################
  717. sub alarmclock_reproutine($$)
  718. {
  719. my ($hash, $Mode) = @_;
  720. if(((AttrVal($hash->{NAME},"RepRoutine1","NONE")) ne "NONE") &&
  721. (AttrVal($hash->{NAME},"RepRoutine1Mode","off")) eq $Mode)
  722. {
  723. $hash->{helper}{Repeat1} = 0;
  724. my $WaitTime1 = AttrVal($hash->{NAME},"RepRoutine1WaitInSec","10");
  725. InternalTimer(gettimeofday()+$WaitTime1, "alarmclock_reproutine1_start", $hash, 0);
  726. }
  727. if(((AttrVal($hash->{NAME},"RepRoutine2","NONE")) ne "NONE") &&
  728. (AttrVal($hash->{NAME},"RepRoutine2Mode","off")) eq $Mode)
  729. {
  730. $hash->{helper}{Repeat2} = 0;
  731. my $WaitTime2 = AttrVal($hash->{NAME},"RepRoutine2WaitInSec","10");
  732. InternalTimer(gettimeofday()+$WaitTime2, "alarmclock_reproutine2_start", $hash, 0);
  733. }
  734. if(((AttrVal($hash->{NAME},"RepRoutine3","NONE")) ne "NONE") &&
  735. (AttrVal($hash->{NAME},"RepRoutine3Mode","off")) eq $Mode)
  736. {
  737. $hash->{helper}{Repeat3} = 0;
  738. my $WaitTime3 = AttrVal($hash->{NAME},"RepRoutine3WaitInSec","10");
  739. InternalTimer(gettimeofday()+$WaitTime3, "alarmclock_reproutine3_start", $hash, 0);
  740. }
  741. }
  742. ########################################################################################
  743. #
  744. # RepRoutine stop
  745. #
  746. ########################################################################################
  747. sub alarmclock_reproutine_stop($$)
  748. {
  749. my ($hash, $Mode) = @_;
  750. if((AttrVal($hash->{NAME},"RepRoutine1Stop","Snooze")) eq $Mode)
  751. {
  752. RemoveInternalTimer($hash, "alarmclock_reproutine1_start");
  753. }
  754. if((AttrVal($hash->{NAME},"RepRoutine2Stop","Snooze")) eq $Mode)
  755. {
  756. RemoveInternalTimer($hash, "alarmclock_reproutine2_start");
  757. }
  758. if((AttrVal($hash->{NAME},"RepRoutine3Stop","Snooze")) eq $Mode)
  759. {
  760. RemoveInternalTimer($hash, "alarmclock_reproutine3_start");
  761. }
  762. }
  763. ########################################################################################
  764. #
  765. # RepRoutine1 start
  766. #
  767. ########################################################################################
  768. sub alarmclock_reproutine1_start($)
  769. {
  770. my ($hash) = @_;
  771. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine1WaitInSec","10");
  772. my $Repeats = AttrVal($hash->{NAME},"RepRoutine1Repeats","2");
  773. my $RNow = $hash->{helper}{Repeat1};
  774. if ($Repeats > $RNow)
  775. {
  776. my $RNext = $RNow + 1;
  777. $hash->{helper}{Repeat1} = $RNext;
  778. fhem("".AttrVal($hash->{NAME},"RepRoutine1",""));
  779. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine1_start", $hash, 0);
  780. }
  781. }
  782. ########################################################################################
  783. #
  784. # RepRoutine2 start
  785. #
  786. ########################################################################################
  787. sub alarmclock_reproutine2_start($)
  788. {
  789. my ($hash) = @_;
  790. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine2WaitInSec","10");
  791. my $Repeats = AttrVal($hash->{NAME},"RepRoutine2Repeats","2");
  792. my $RNow = $hash->{helper}{Repeat2};
  793. if ($Repeats > $RNow)
  794. {
  795. my $RNext = $RNow + 1;
  796. $hash->{helper}{Repeat2} = $RNext;
  797. fhem("".AttrVal($hash->{NAME},"RepRoutine2",""));
  798. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine2_start", $hash, 0);
  799. }
  800. }
  801. ########################################################################################
  802. #
  803. # RepRoutine3 start
  804. #
  805. ########################################################################################
  806. sub alarmclock_reproutine3_start($)
  807. {
  808. my ($hash) = @_;
  809. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine3WaitInSec","10");
  810. my $Repeats = AttrVal($hash->{NAME},"RepRoutine3Repeats","2");
  811. my $RNow = $hash->{helper}{Repeat3};
  812. if ($Repeats > $RNow)
  813. {
  814. my $RNext = $RNow + 1;
  815. $hash->{helper}{Repeat3} = $RNext;
  816. fhem("".AttrVal($hash->{NAME},"RepRoutine3",""));
  817. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine3_start", $hash, 0);
  818. }
  819. }
  820. ########################################################################################
  821. #
  822. # Presence Check
  823. #
  824. ########################################################################################
  825. sub alarmclock_presence_check($)
  826. {
  827. my ($hash) = @_;
  828. if ((AttrVal($hash->{NAME}, "PresenceDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "PresenceCheck", "1" ) ne "0" ))
  829. {
  830. my @Presence = split(/\|/, AttrVal($hash->{NAME},"PresenceDevice",""));
  831. my $a = 0;
  832. my $b = scalar(@Presence);
  833. while ($a < $b)
  834. {
  835. my @PresenceDevice = split(/:/,$Presence[$a]);
  836. if (scalar(@PresenceDevice) eq "1")
  837. {
  838. if (ReadingsVal($PresenceDevice[0],"state","present") ne "present")
  839. {
  840. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  841. return 0;
  842. }
  843. }
  844. elsif (scalar(@PresenceDevice) eq "2")
  845. {
  846. if (ReadingsVal($PresenceDevice[0],"state","NONE") eq $PresenceDevice[1])
  847. {
  848. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  849. return 0;
  850. }
  851. }
  852. elsif (scalar(@PresenceDevice) eq "3")
  853. {
  854. my $PresenceEvent = $PresenceDevice[2];
  855. $PresenceEvent =~ s/ //g;
  856. if (ReadingsVal($PresenceDevice[0],$PresenceDevice[1],"NONE") eq $PresenceEvent)
  857. {
  858. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  859. return 0;
  860. }
  861. }
  862. $a ++;
  863. }
  864. }
  865. return 1;
  866. }
  867. ########################################################################################
  868. #
  869. # Holiday Check
  870. #
  871. ########################################################################################
  872. sub alarmclock_holiday_check($)
  873. {
  874. my ($hash) = @_;
  875. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  876. my $WDayToday = $WDayNow;
  877. my $WDayTomorrow = $WDayNow + 1;
  878. if ($WDayToday == 0)
  879. {
  880. $WDayToday = 7;
  881. }
  882. if ((AttrVal($hash->{NAME}, "HolidayDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "HolidayCheck", "1" ) ne "0" ))
  883. {
  884. my @HolidayDays = split(/\|/, AttrVal($hash->{NAME},"HolidayDays","1|2|3|4|5|6|7"));
  885. my $DayToday = grep {$_==$WDayToday;} @HolidayDays;
  886. my $DayTomorrow = grep {$_==$WDayTomorrow;} @HolidayDays;
  887. my @Holiday = split(/\|/, AttrVal($hash->{NAME},"HolidayDevice",""));
  888. my $a = 0;
  889. my $b = scalar(@Holiday);
  890. while ($a < $b)
  891. {
  892. my @HolidayDevice = split(/:/,$Holiday[$a]);
  893. if (scalar(@HolidayDevice) eq "1")
  894. {
  895. if( IsDevice( $HolidayDevice[0], "holiday" ))
  896. {
  897. my $today = strftime("%2m-%2d", localtime(time));
  898. my $tomorrow = strftime("%2m-%2d", localtime(time+86400));
  899. my $todayevent = holiday_refresh($HolidayDevice[0],$today);
  900. if (($todayevent ne "none") && ($DayToday == 1))
  901. {
  902. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $todayevent";
  903. $hash->{helper}{Today} = 8;
  904. }
  905. my $tomorrowevent = holiday_refresh($HolidayDevice[0],$tomorrow);
  906. if (($tomorrowevent ne "none") && ($DayTomorrow == 1))
  907. {
  908. $hash->{helper}{Tomorrow} = 8;
  909. }
  910. }
  911. elsif( IsDevice($HolidayDevice[0], "Calendar" ))
  912. {
  913. my $stoday = strftime("%2d.%2m.%2y", localtime(time));
  914. my $stomorrow = strftime("%2d.%2m.%2y", localtime(time+86400));
  915. my $line = Calendar_Get($defs{$HolidayDevice[0]},"get","text","mode=alarm|start|upcoming");
  916. if ($line)
  917. {
  918. chomp($line);
  919. my @lines = split('\n',$line);
  920. foreach $line (@lines)
  921. {
  922. chomp($line);
  923. my $date = substr($line,0,8);
  924. if (($date eq $stoday) && ($DayToday == 1))
  925. {
  926. my $todaydesc = substr($line,15);
  927. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $todaydesc";
  928. $hash->{helper}{Today} = 8;
  929. }
  930. if (($date eq $stomorrow) && ($DayTomorrow == 1))
  931. {
  932. $hash->{helper}{Tomorrow} = 8;
  933. }
  934. }
  935. }
  936. }
  937. }
  938. elsif (scalar(@HolidayDevice) eq "2")
  939. {
  940. if ((ReadingsVal($HolidayDevice[0],"state","NONE") eq $HolidayDevice[1]) && ($DayToday == 1))
  941. {
  942. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $HolidayDevice[1]";
  943. $hash->{helper}{Today} = 8;
  944. }
  945. }
  946. elsif (scalar(@HolidayDevice) eq "3")
  947. {
  948. my $HolidayEvent = $HolidayDevice[2];
  949. $HolidayEvent =~ s/ //g;
  950. if ((ReadingsVal($HolidayDevice[0],$HolidayDevice[1],"NONE") eq $HolidayEvent) && ($DayToday == 1))
  951. {
  952. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $HolidayDevice[1] - $HolidayEvent";
  953. $hash->{helper}{Today} = 8;
  954. }
  955. }
  956. $a ++;
  957. }
  958. }
  959. }
  960. ########################################################################################
  961. #
  962. # Vacation Check
  963. #
  964. ########################################################################################
  965. sub alarmclock_vacation_check($)
  966. {
  967. my ($hash) = @_;
  968. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  969. my $WDayToday = $WDayNow;
  970. my $WDayTomorrow = $WDayNow + 1;
  971. if ($WDayToday == 0)
  972. {
  973. $WDayToday = 7;
  974. }
  975. if ((AttrVal($hash->{NAME}, "VacationDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "VacationCheck", "1" ) ne "0" ))
  976. {
  977. my @VacationDays = split(/\|/, AttrVal($hash->{NAME},"VacationDays","1|2|3|4|5|6|7"));
  978. my $DayToday = grep {$_==$WDayToday;} @VacationDays;
  979. my $DayTomorrow = grep {$_==$WDayTomorrow;} @VacationDays;
  980. my @Vacation = split(/\|/, AttrVal($hash->{NAME},"VacationDevice",""));
  981. my $a = 0;
  982. my $b = scalar(@Vacation);
  983. while ($a < $b)
  984. {
  985. my @VacationDevice = split(/:/,$Vacation[$a]);
  986. if (scalar(@VacationDevice) eq "1")
  987. {
  988. if( IsDevice( $VacationDevice[0], "holiday" ))
  989. {
  990. my $today = strftime("%2m-%2d", localtime(time));
  991. my $tomorrow = strftime("%2m-%2d", localtime(time+86400));
  992. my $todayevent = holiday_refresh($VacationDevice[0],$today);
  993. if (($todayevent ne "none") && ($DayToday == 1))
  994. {
  995. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $todayevent";
  996. $hash->{helper}{Today} = 9;
  997. }
  998. my $tomorrowevent = holiday_refresh($VacationDevice[0],$tomorrow);
  999. if (($tomorrowevent ne "none") && ($DayTomorrow == 1))
  1000. {
  1001. $hash->{helper}{Tomorrow} = 9;
  1002. }
  1003. }
  1004. elsif( IsDevice($VacationDevice[0], "Calendar" ))
  1005. {
  1006. my $stoday = strftime("%2d.%2m.%2y", localtime(time));
  1007. my $stomorrow = strftime("%2d.%2m.%2y", localtime(time+86400));
  1008. my @tday = split('\.',$stoday);
  1009. my @tmor = split('\.',$stomorrow);
  1010. my $fline = Calendar_Get($defs{$VacationDevice[0]},"get","full","mode=alarm|start|upcoming");
  1011. my @lines = split('\n',$fline);
  1012. foreach $fline (@lines)
  1013. {
  1014. chomp($fline);
  1015. my @chunks = split(' ',$fline);
  1016. my @sday = split('\.',$chunks[2]);
  1017. my @eday = split('\.',substr($chunks[3],9,10));
  1018. my $rets = ($sday[2]-$tday[2]-2000)*365+($sday[1]-$tday[1])*31+($sday[0]-$tday[0]);
  1019. my $rete = ($eday[2]-$tday[2]-2000)*365+($eday[1]-$tday[1])*31+($eday[0]-$tday[0]);
  1020. if (($rete>=0) && ($rets<=0) && ($DayToday == 1))
  1021. {
  1022. my $todaydesc = $chunks[5];
  1023. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $todaydesc";
  1024. $hash->{helper}{Today} = 9;
  1025. }
  1026. $rets = ($sday[2]-$tmor[2]-2000)*365+($sday[1]-$tmor[1])*31+($sday[0]-$tmor[0]);
  1027. $rete = ($eday[2]-$tmor[2]-2000)*365+($eday[1]-$tmor[1])*31+($eday[0]-$tmor[0]);
  1028. if (($rete>=0) && ($rets<=0) && ($DayTomorrow == 1))
  1029. {
  1030. $hash->{helper}{Tomorrow} = 9;
  1031. }
  1032. }
  1033. }
  1034. }
  1035. elsif (scalar(@VacationDevice) eq "2")
  1036. {
  1037. if ((ReadingsVal($VacationDevice[0],"state","NONE") eq $VacationDevice[1]) && ($DayToday == 1))
  1038. {
  1039. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $VacationDevice[1]";
  1040. $hash->{helper}{Today} = 9;
  1041. }
  1042. }
  1043. elsif (scalar(@VacationDevice) eq "3")
  1044. {
  1045. my $VacationEvent = $VacationDevice[2];
  1046. $VacationEvent =~ s/ //g;
  1047. if ((ReadingsVal($VacationDevice[0],$VacationDevice[1],"NONE") eq $VacationEvent)&& ($DayToday == 1))
  1048. {
  1049. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $VacationDevice[1] - $VacationEvent";
  1050. $hash->{helper}{Today} = 9;
  1051. }
  1052. }
  1053. $a ++;
  1054. }
  1055. }
  1056. }
  1057. ########################################################################################
  1058. #
  1059. # skip
  1060. #
  1061. ########################################################################################
  1062. sub alarmclock_skip($)
  1063. {
  1064. my ($hash) = @_;
  1065. readingsSingleUpdate( $hash, "skip", "none", 1 );
  1066. alarmclock_createtimer($hash);
  1067. }
  1068. ########################################################################################
  1069. #
  1070. # Notify
  1071. #
  1072. ########################################################################################
  1073. sub alarmclock_Notify($$)
  1074. {
  1075. my ($hash, $devhash) = @_;
  1076. return "" if(IsDisabled($hash->{NAME})); # Return without any further action if the module is disabled
  1077. my $devName = $devhash->{NAME}; # Device that created the events
  1078. my $events = deviceEvents($devhash,0);
  1079. return if( !$events );
  1080. ### alarmclock_createtimer wird nach dem start von fhem aufgerufen ###
  1081. if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
  1082. {
  1083. alarmclock_createtimer($hash);
  1084. }
  1085. ### Notify Alarm off ###
  1086. if((ReadingsVal($hash->{NAME},"state",0)) =~ /^(Alarm is running|Snooze for.*)/)
  1087. {
  1088. if(my @AlarmOffDevice = split(/\|/, AttrVal($hash->{NAME},"EventForAlarmOff","")))
  1089. {
  1090. foreach my $AlarmOffDevice(@AlarmOffDevice)
  1091. {
  1092. my @AlarmOffDevicePart = split(/:/, $AlarmOffDevice,2);
  1093. if(($devName eq $AlarmOffDevicePart[0]) && (grep { $AlarmOffDevicePart[1] eq $_ } @{$events}))
  1094. {
  1095. alarmclock_alarmroutine_stop($hash);
  1096. }
  1097. }
  1098. }
  1099. }
  1100. ### Notify Snooze ###
  1101. if((ReadingsVal($hash->{NAME},"state",0)) eq "Alarm is running")
  1102. {
  1103. if(my @SnoozeDevice = split(/\|/, AttrVal($hash->{NAME},"EventForSnooze","")))
  1104. {
  1105. foreach my $SnoozeDevice(@SnoozeDevice)
  1106. {
  1107. my @SnoozeDevicePart = split(/:/, $SnoozeDevice,2);
  1108. if(($devName eq $SnoozeDevicePart[0]) && (grep { $SnoozeDevicePart[1] eq $_ } @{$events}))
  1109. {
  1110. alarmclock_snooze_start($hash);
  1111. }
  1112. }
  1113. }
  1114. }
  1115. }
  1116. 1;
  1117. =pod
  1118. =item helper
  1119. =item summary Fhem Modul to set up a Alarmclock
  1120. =item summary_DE Fhem Weckermodul
  1121. =begin html
  1122. <a name="alarmclock"></a>
  1123. <h3>alarmclock</h3>
  1124. <ul>
  1125. Fhem Modul to set up a Alarmclock
  1126. <br><br>
  1127. <a name="alarmclock_Define"></a>
  1128. <b>Define</b>
  1129. <ul>
  1130. <code>define &lt;name&gt; alarmclock</code>
  1131. <br>
  1132. Example: <code>define Wecker alarmclock</code>
  1133. <br>
  1134. </ul>
  1135. <br>
  1136. <a name="alarmclock_Set"></a>
  1137. <b>Set</b><br>
  1138. <ul>
  1139. <li><b>AlarmTime(1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation)</b> HH:MM<br>
  1140. Sets a alarm time for each day.
  1141. </li>
  1142. <li><b>AlarmTime_Weekdays</b> HH:MM<br>
  1143. Sets the same alarm time for each working day.
  1144. </li>
  1145. <li><b>AlarmTime_Weekend</b> HH:MM<br>
  1146. Sets the same alarm time for Saturday and Sunday.
  1147. </li>
  1148. <li><b>AlarmOff</b> (1_Monday|2_Tuesday|3_Wednesday|4_Thursday|5_Friday|6_Saturday|7_Sunday|8_Holiday|9_Vacation|Weekdays|Weekend|All)<br>
  1149. Sets the alarm time of the respective day to off.
  1150. </li>
  1151. <li><b>stop</b> (Alarm)<br>
  1152. Stops a running alarm.
  1153. </li>
  1154. <li><b>save</b> (Weekprofile_1|Weekprofile_2|Weekprofile_3|Weekprofile_4|Weekprofile_5)<br>
  1155. Save alarm times in a profile.
  1156. </li>
  1157. <li><b>load</b> (Weekprofile_1|Weekprofile_2|Weekprofile_3|Weekprofile_4|Weekprofile_5)<br>
  1158. Load alarm times from profile.
  1159. </li>
  1160. <li><b>skip</b> (NextAlarm|None)<br>
  1161. Skips the next alarm.
  1162. </li>
  1163. <li><b>disable</b> (1|0|)<br>
  1164. Deactivated/Activated the alarmclock.
  1165. </li>
  1166. </ul>
  1167. <br>
  1168. <br>
  1169. <a name="alarmclock_Attr"></a>
  1170. <b>Attributes</b>
  1171. <ul>
  1172. <li><b>AlarmRoutine</b> <br>
  1173. A list separated by semicolon (;) which Fhem should run at the alarm time.<br>
  1174. Example: attr &lt;name&gt; AlarmRoutine set Licht on;set Radio on
  1175. </li>
  1176. <li><b>AlarmRoutineOff</b> <br>
  1177. A list separated by semicolon (;) which Fhem should execute to terminate the alarm.<br>
  1178. Example: attr &lt;name&gt; AlarmRoutineOff set Licht off;set Radio off
  1179. </li>
  1180. <li><b>EventForAlarmOff</b> <br>
  1181. Fhem-event to end the alarm.<br>
  1182. There are 2 possibilities:<br>
  1183. 1.Trigger on state.<br>
  1184. &lt;devicename&gt;:&lt;state&gt; Example: attr &lt;name&gt; EventForAlarmOff Taster:off <br>
  1185. 2.Trigger on reading. <br>
  1186. &lt;devicename&gt;:&lt;readingname&gt;: &lt;value&gt; Example: attr &lt;name&gt; EventForAlarmOff Taster:cSceneSet: on <br>
  1187. </li>
  1188. <li><b>EventForSnooze</b> <br>
  1189. Fhem-event to interrupt the alarm.<br>
  1190. The syntax is identical to EventForAlarmOff.<br>
  1191. Example: attr &lt;name&gt; EventForSnooze Taster:cSceneSet: off <br>
  1192. </li>
  1193. <li><b>SnoozeRoutine</b> <br>
  1194. A list separated by semicolon (;) which Fhem operate to interrupt the running alarm.<br>
  1195. Example: attr &lt;name&gt; SnoozeRoutine set Licht off;set Radio off
  1196. </li>
  1197. <li><b>SnoozeTimeInSec</b> <br>
  1198. Time in seconds how long the alarm should be interrupted.<br>
  1199. Example: attr &lt;name&gt; SnoozeTimeInSec 240 <br>
  1200. </li>
  1201. <li><b>PreAlarmRoutine</b> <br>
  1202. A list separated by semicolon (;) which Fhem operate at the pre-alarm.<br>
  1203. Example: attr &lt;name&gt; PreAlarmRoutine set Licht dim 30;set Radio on
  1204. </li>
  1205. <li><b>PreAlarmTimeInSec</b> <br>
  1206. Time in seconds between the alarm and the pre-alarm.<br>
  1207. Example: attr &lt;name&gt; PreAlarmTimeInSec 300<br>
  1208. In the example, the PreAlarmRoutine is executed 5 minutes before the regular alarm.
  1209. </li>
  1210. <li><b>HardAlarmRoutine</b> <br>
  1211. A list separated by semicolon (;) which is to be executed to force the awakening.<br>
  1212. Example: attr &lt;name&gt; HardAlarmRoutine set Sonos_Schlafzimmer Volume 40;set Licht dim 90
  1213. </li>
  1214. <li><b>HardAlarmTimeInSec</b> <br>
  1215. Here you can specify in seconds how long the alarm can "run" until HardAlarmRoutine is started.<br>
  1216. Example: attr &lt;name&gt; HardAlarmTimeInSec 300
  1217. </li>
  1218. <li><b>OffRoutine</b> <br>
  1219. A list separated by semicolon (;) which Fhem operate at the OffDefaultTime.<br>
  1220. Example: attr &lt;name&gt; OffRoutine set rr_Florian home;set Heizung on
  1221. </li>
  1222. <li><b>OffDefaultTime</b> <br>
  1223. Default time for the OffRoutine.<br>
  1224. Example: attr &lt;name&gt; OffDefaultTime 07:30
  1225. </li>
  1226. <li><b>MaxAlarmDurationInSec</b> <br>
  1227. Duration in seconds to stop automatically the running alarm.<br>
  1228. Example: attr &lt;name&gt; MaxAlarmDurationInSec 120
  1229. </li>
  1230. <li><b>RepRoutine</b> <br>
  1231. A list separated by semicolon (;) which is to be repeated.<br>
  1232. Example: attr &lt;name&gt; RepRoutine1 set Licht_Schlafzimmer dim 1
  1233. </li>
  1234. <li><b>RepRoutineWaitInSec</b> <br>
  1235. Time in seconds between the repetitions from RepRoutine.<br>
  1236. Example: attr &lt;name&gt; RepRoutine1WaitInSec 20
  1237. </li>
  1238. <li><b>RepRoutineRepeats</b> <br>
  1239. Number of repetitions of RepRoutine.<br>
  1240. Example: attr &lt;name&gt; RepRoutine1Repeats 15
  1241. </li>
  1242. <li><b>RepRoutineMode(Alarm|PreAlarm|off)</b> <br>
  1243. Alarm:Reproutine is started with the alarm.<br>
  1244. PreAlarm:Reproutine is started with the pre-alarm.<br>
  1245. off:Reproutine is deactivated.
  1246. </li>
  1247. <li><b>RepRoutineStop(Snooze|off)</b> <br>
  1248. Snooze:Reproutine is stopped with snooze.<br>
  1249. off:Reproutine is not stopped with snooze.
  1250. </li>
  1251. <li><b>HolidayDevice</b> <br>
  1252. Name of the holiday device.<br>
  1253. There are 3 possibilities:<br>
  1254. 1.holiday device from typ holiday or Calendar.<br>
  1255. &lt;devicename&gt;<br>
  1256. Example: attr &lt;name&gt; HolidayDevice Feiertage <br>
  1257. 2.On state of a device.For example a dummy <br>
  1258. &lt;devicename&gt;:&lt;value&gt; <br>
  1259. Example: attr &lt;name&gt; HolidayDevice MyDummy:Holiday <br>
  1260. Here the AlarmTime 8_Holiday takes effect when the state of the dummy has the value Holiday <br>
  1261. 3.On a reading of a device. <br>
  1262. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt;<br>
  1263. Example: attr &lt;name&gt; HolidayDevice MyDummy:Today:Holiday <br>
  1264. </li>
  1265. <li><b>HolidayCheck</b> <br>
  1266. 0 disables monitoring the holiday device<br>
  1267. 1 activates monitoring
  1268. </li>
  1269. <li><b>HolidayDays</b> <br>
  1270. List of days on which the alarmtime 8_Holiday may take effect<br>
  1271. Example: attr &lt;name&gt; HolidayDays 1|2|3|4|5 <br>
  1272. Default: 1|2|3|4|5|6|7
  1273. </li>
  1274. <li><b>VacationDevice</b> <br>
  1275. Name of the vacation device.<br>
  1276. There are 3 possibilities:<br>
  1277. 1.vacation device from typ holiday or Calendar.<br>
  1278. &lt;devicename&gt; <br>
  1279. Example: attr &lt;name&gt; VacationDevice Ferien <br>
  1280. 2.On state of a device.For example a dummy <br>
  1281. &lt;devicename&gt;:&lt;value&gt; <br>
  1282. Example: attr &lt;name&gt; VacationDevice MyDummy:Vacation <br>
  1283. Here the AlarmTime 9_Vacation takes effect when the state of the dummy has the value Vacation <br>
  1284. 3.On a reading of a device. <br>
  1285. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt; <br>
  1286. Example: attr &lt;name&gt; VacationDevice MyDummy:Today:Vacation <br>
  1287. </li>
  1288. <li><b>VacationCheck</b> <br>
  1289. 0 disables monitoring the vacation device<br>
  1290. 1 activates monitoring
  1291. </li>
  1292. <li><b>VacationDays</b> <br>
  1293. List of days on which the alarmtime 9_Vacation may take effect<br>
  1294. Example: attr &lt;name&gt; VacationDays 1|2|3|4|5 <br>
  1295. Default: 1|2|3|4|5|6|7
  1296. </li>
  1297. <li><b>PresenceDevice</b> <br>
  1298. Name of the presence device.<br>
  1299. There are 3 possibilities:<br>
  1300. 1.presence device from Typ presence.<br>
  1301. &lt;devicename&gt; <br>
  1302. Example: attr &lt;name&gt; PresenceDevice Presence <br>
  1303. Alarmclock cancel alarm when state is absent <br>
  1304. 2.On state of a device.For example a dummy <br>
  1305. &lt;devicename&gt;:&lt;value&gt; <br>
  1306. Example: attr &lt;name&gt; PresenceDevice MyDummy:absent <br>
  1307. Here the Alarmclock cancel alarm when the state of the dummy has the value absent <br>
  1308. 3.On a reading of a device. <br>
  1309. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt; <br>
  1310. Example: attr &lt;name&gt; PresenceDevice MyDummy:user:notathome <br>
  1311. </li>
  1312. <li><b>PresenceCheck</b> <br>
  1313. 0 disables monitoring the presence device<br>
  1314. 1 activates monitoring
  1315. </li>
  1316. <li><b>WeekprofileName</b> <br>
  1317. Optional list with name for storing the week profiles<br>
  1318. Example: attr &lt;name&gt; WeekprofileName MyWeek1,MyWeek2,MyWeek3 <br>
  1319. </li>
  1320. <li><b>disable</b> <br>
  1321. 1 disables all alarms<br>
  1322. 0 activates this again
  1323. </li>
  1324. </ul>
  1325. </ul>
  1326. =end html
  1327. =cut