98_alarmclock.pm 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592
  1. # $Id: 98_alarmclock.pm 16981 2018-07-14 09:35:07Z 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|PreAlarm 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);
  609. alarmclock_midnight_timer($hash);
  610. }
  611. ########################################################################################
  612. #
  613. # Pre-Alarm-Routine start
  614. #
  615. ########################################################################################
  616. sub alarmclock_prealarmroutine_start($)
  617. {
  618. my ($hash) = @_;
  619. my $Mode = "PreAlarm";
  620. if (alarmclock_presence_check($hash))
  621. {
  622. fhem("".AttrVal($hash->{NAME},"PreAlarmRoutine",""));
  623. readingsSingleUpdate( $hash,"state", "PreAlarm is running", 1 );
  624. alarmclock_reproutine($hash, $Mode);
  625. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - PreAlarmRoutine started.";
  626. }
  627. }
  628. ########################################################################################
  629. #
  630. # Alarm Snooze
  631. #
  632. ########################################################################################
  633. sub alarmclock_snooze_start($)
  634. {
  635. my ($hash) = @_;
  636. my $Mode = "Snooze";
  637. if((AttrVal($hash->{NAME},"SnoozeTimeInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  638. {
  639. my $SnoozeTime = AttrVal($hash->{NAME},"SnoozeTimeInSec","");
  640. fhem("".AttrVal($hash->{NAME},"SnoozeRoutine",""));
  641. InternalTimer(gettimeofday()+$SnoozeTime, "alarmclock_alarmroutine_start", $hash, 0);
  642. readingsSingleUpdate( $hash,"state", "Snooze for $SnoozeTime sec", 1 );
  643. RemoveInternalTimer($hash, "alarmclock_hardalarmroutine_start");
  644. RemoveInternalTimer($hash, "alarmclock_alarmroutine_stop");
  645. alarmclock_reproutine_stop($hash, $Mode);
  646. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - snooze-timer created with $SnoozeTime sec.";
  647. }
  648. else
  649. {
  650. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - no SnoozeTimeInSec is set.";
  651. }
  652. }
  653. ########################################################################################
  654. #
  655. # Alarm OffRoutine
  656. #
  657. ########################################################################################
  658. sub alarmclock_offroutine_start($)
  659. {
  660. my ($hash) = @_;
  661. fhem("".AttrVal($hash->{NAME},"OffRoutine",""));
  662. readingsSingleUpdate( $hash,"state", "OffRoutine is running", 1 );
  663. alarmclock_createtimer($hash);
  664. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - OffRoutine started.";
  665. }
  666. ########################################################################################
  667. #
  668. # HardAlarm Timer
  669. #
  670. ########################################################################################
  671. sub alarmclock_hardalarm_timer($)
  672. {
  673. my ($hash) = @_;
  674. if((AttrVal($hash->{NAME},"HardAlarmTimeInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  675. {
  676. my $HardAlarmTime = AttrVal($hash->{NAME},"HardAlarmTimeInSec","");
  677. InternalTimer(gettimeofday()+$HardAlarmTime, "alarmclock_hardalarmroutine_start", $hash, 0);
  678. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - HardAlarm created with $HardAlarmTime sec.";
  679. }
  680. else
  681. {
  682. Log3 $hash->{NAME}, 4, "alarmclock: $hash->{NAME} - no HardAlarmTimeInSec is set.";
  683. }
  684. }
  685. ########################################################################################
  686. #
  687. # MaxAlarmDuration
  688. #
  689. ########################################################################################
  690. sub alarmclock_maxalarmduration_timer($)
  691. {
  692. my ($hash) = @_;
  693. if((AttrVal($hash->{NAME},"MaxAlarmDurationInSec","NONE")) =~ /^([0-9]?[0-9]?[0-9]?[0-9])$/)
  694. {
  695. my $MaxAlarmDuration = AttrVal($hash->{NAME},"MaxAlarmDurationInSec","");
  696. InternalTimer(gettimeofday()+$MaxAlarmDuration, "alarmclock_alarmroutine_stop", $hash, 0);
  697. Log3 $hash->{NAME}, 5, "alarmclock: $hash->{NAME} - MaxAlarmDuration created with $MaxAlarmDuration sec.";
  698. }
  699. }
  700. ########################################################################################
  701. #
  702. # HardAlarm start
  703. #
  704. ########################################################################################
  705. sub alarmclock_hardalarmroutine_start($)
  706. {
  707. my ($hash) = @_;
  708. fhem("".AttrVal($hash->{NAME},"HardAlarmRoutine",""));
  709. Log3 $hash->{NAME}, 3, "alarmclock: $hash->{NAME} - HardAlarmRoutine started.";
  710. }
  711. ########################################################################################
  712. #
  713. # RepRoutine
  714. #
  715. ########################################################################################
  716. sub alarmclock_reproutine($$)
  717. {
  718. my ($hash, $Mode) = @_;
  719. if(((AttrVal($hash->{NAME},"RepRoutine1","NONE")) ne "NONE") &&
  720. (AttrVal($hash->{NAME},"RepRoutine1Mode","off")) eq $Mode)
  721. {
  722. $hash->{helper}{Repeat1} = 0;
  723. my $WaitTime1 = AttrVal($hash->{NAME},"RepRoutine1WaitInSec","10");
  724. InternalTimer(gettimeofday()+$WaitTime1, "alarmclock_reproutine1_start", $hash, 0);
  725. }
  726. if(((AttrVal($hash->{NAME},"RepRoutine2","NONE")) ne "NONE") &&
  727. (AttrVal($hash->{NAME},"RepRoutine2Mode","off")) eq $Mode)
  728. {
  729. $hash->{helper}{Repeat2} = 0;
  730. my $WaitTime2 = AttrVal($hash->{NAME},"RepRoutine2WaitInSec","10");
  731. InternalTimer(gettimeofday()+$WaitTime2, "alarmclock_reproutine2_start", $hash, 0);
  732. }
  733. if(((AttrVal($hash->{NAME},"RepRoutine3","NONE")) ne "NONE") &&
  734. (AttrVal($hash->{NAME},"RepRoutine3Mode","off")) eq $Mode)
  735. {
  736. $hash->{helper}{Repeat3} = 0;
  737. my $WaitTime3 = AttrVal($hash->{NAME},"RepRoutine3WaitInSec","10");
  738. InternalTimer(gettimeofday()+$WaitTime3, "alarmclock_reproutine3_start", $hash, 0);
  739. }
  740. }
  741. ########################################################################################
  742. #
  743. # RepRoutine stop
  744. #
  745. ########################################################################################
  746. sub alarmclock_reproutine_stop($$)
  747. {
  748. my ($hash, $Mode) = @_;
  749. if((AttrVal($hash->{NAME},"RepRoutine1Stop","Snooze")) eq $Mode)
  750. {
  751. RemoveInternalTimer($hash, "alarmclock_reproutine1_start");
  752. }
  753. if((AttrVal($hash->{NAME},"RepRoutine2Stop","Snooze")) eq $Mode)
  754. {
  755. RemoveInternalTimer($hash, "alarmclock_reproutine2_start");
  756. }
  757. if((AttrVal($hash->{NAME},"RepRoutine3Stop","Snooze")) eq $Mode)
  758. {
  759. RemoveInternalTimer($hash, "alarmclock_reproutine3_start");
  760. }
  761. }
  762. ########################################################################################
  763. #
  764. # RepRoutine1 start
  765. #
  766. ########################################################################################
  767. sub alarmclock_reproutine1_start($)
  768. {
  769. my ($hash) = @_;
  770. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine1WaitInSec","10");
  771. my $Repeats = AttrVal($hash->{NAME},"RepRoutine1Repeats","2");
  772. my $RNow = $hash->{helper}{Repeat1};
  773. if ($Repeats > $RNow)
  774. {
  775. my $RNext = $RNow + 1;
  776. $hash->{helper}{Repeat1} = $RNext;
  777. fhem("".AttrVal($hash->{NAME},"RepRoutine1",""));
  778. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine1_start", $hash, 0);
  779. }
  780. }
  781. ########################################################################################
  782. #
  783. # RepRoutine2 start
  784. #
  785. ########################################################################################
  786. sub alarmclock_reproutine2_start($)
  787. {
  788. my ($hash) = @_;
  789. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine2WaitInSec","10");
  790. my $Repeats = AttrVal($hash->{NAME},"RepRoutine2Repeats","2");
  791. my $RNow = $hash->{helper}{Repeat2};
  792. if ($Repeats > $RNow)
  793. {
  794. my $RNext = $RNow + 1;
  795. $hash->{helper}{Repeat2} = $RNext;
  796. fhem("".AttrVal($hash->{NAME},"RepRoutine2",""));
  797. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine2_start", $hash, 0);
  798. }
  799. }
  800. ########################################################################################
  801. #
  802. # RepRoutine3 start
  803. #
  804. ########################################################################################
  805. sub alarmclock_reproutine3_start($)
  806. {
  807. my ($hash) = @_;
  808. my $WaitTime = AttrVal($hash->{NAME},"RepRoutine3WaitInSec","10");
  809. my $Repeats = AttrVal($hash->{NAME},"RepRoutine3Repeats","2");
  810. my $RNow = $hash->{helper}{Repeat3};
  811. if ($Repeats > $RNow)
  812. {
  813. my $RNext = $RNow + 1;
  814. $hash->{helper}{Repeat3} = $RNext;
  815. fhem("".AttrVal($hash->{NAME},"RepRoutine3",""));
  816. InternalTimer(gettimeofday()+$WaitTime, "alarmclock_reproutine3_start", $hash, 0);
  817. }
  818. }
  819. ########################################################################################
  820. #
  821. # Presence Check
  822. #
  823. ########################################################################################
  824. sub alarmclock_presence_check($)
  825. {
  826. my ($hash) = @_;
  827. if ((AttrVal($hash->{NAME}, "PresenceDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "PresenceCheck", "1" ) ne "0" ))
  828. {
  829. my @Presence = split(/\|/, AttrVal($hash->{NAME},"PresenceDevice",""));
  830. my $a = 0;
  831. my $b = scalar(@Presence);
  832. while ($a < $b)
  833. {
  834. my @PresenceDevice = split(/:/,$Presence[$a]);
  835. if (scalar(@PresenceDevice) eq "1")
  836. {
  837. if (ReadingsVal($PresenceDevice[0],"state","present") ne "present")
  838. {
  839. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  840. return 0;
  841. }
  842. }
  843. elsif (scalar(@PresenceDevice) eq "2")
  844. {
  845. if (ReadingsVal($PresenceDevice[0],"state","NONE") eq $PresenceDevice[1])
  846. {
  847. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  848. return 0;
  849. }
  850. }
  851. elsif (scalar(@PresenceDevice) eq "3")
  852. {
  853. my $PresenceEvent = $PresenceDevice[2];
  854. $PresenceEvent =~ s/ //g;
  855. if (ReadingsVal($PresenceDevice[0],$PresenceDevice[1],"NONE") eq $PresenceEvent)
  856. {
  857. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - absent";
  858. return 0;
  859. }
  860. }
  861. $a ++;
  862. }
  863. }
  864. return 1;
  865. }
  866. ########################################################################################
  867. #
  868. # Holiday Check
  869. #
  870. ########################################################################################
  871. sub alarmclock_holiday_check($)
  872. {
  873. my ($hash) = @_;
  874. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  875. my $WDayToday = $WDayNow;
  876. my $WDayTomorrow = $WDayNow + 1;
  877. if ($WDayToday == 0)
  878. {
  879. $WDayToday = 7;
  880. }
  881. if ((AttrVal($hash->{NAME}, "HolidayDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "HolidayCheck", "1" ) ne "0" ))
  882. {
  883. my @HolidayDays = split(/\|/, AttrVal($hash->{NAME},"HolidayDays","1|2|3|4|5|6|7"));
  884. my $DayToday = grep {$_==$WDayToday;} @HolidayDays;
  885. my $DayTomorrow = grep {$_==$WDayTomorrow;} @HolidayDays;
  886. my @Holiday = split(/\|/, AttrVal($hash->{NAME},"HolidayDevice",""));
  887. my $a = 0;
  888. my $b = scalar(@Holiday);
  889. while ($a < $b)
  890. {
  891. my @HolidayDevice = split(/:/,$Holiday[$a]);
  892. if (scalar(@HolidayDevice) eq "1")
  893. {
  894. if( IsDevice( $HolidayDevice[0], "holiday" ))
  895. {
  896. my $today = strftime("%2m-%2d", localtime(time));
  897. my $tomorrow = strftime("%2m-%2d", localtime(time+86400));
  898. my $todayevent = holiday_refresh($HolidayDevice[0],$today);
  899. if (($todayevent ne "none") && ($DayToday == 1))
  900. {
  901. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $todayevent";
  902. $hash->{helper}{Today} = 8;
  903. }
  904. my $tomorrowevent = holiday_refresh($HolidayDevice[0],$tomorrow);
  905. if (($tomorrowevent ne "none") && ($DayTomorrow == 1))
  906. {
  907. $hash->{helper}{Tomorrow} = 8;
  908. }
  909. }
  910. elsif( IsDevice($HolidayDevice[0], "Calendar" ))
  911. {
  912. my $stoday = strftime("%2d.%2m.20%2y", localtime(time));
  913. my $stomorrow = strftime("%2d.%2m.20%2y", localtime(time+86400));
  914. my $line = Calendar_Get($defs{$HolidayDevice[0]},"get","events","format:text");
  915. if ($line)
  916. {
  917. chomp($line);
  918. my @lines = split('\n',$line);
  919. foreach $line (@lines)
  920. {
  921. chomp($line);
  922. my $date = substr($line,0,10);
  923. if (($date eq $stoday) && ($DayToday == 1))
  924. {
  925. my $todaydesc = substr($line,15);
  926. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $todaydesc";
  927. $hash->{helper}{Today} = 8;
  928. }
  929. if (($date eq $stomorrow) && ($DayTomorrow == 1))
  930. {
  931. $hash->{helper}{Tomorrow} = 8;
  932. }
  933. }
  934. }
  935. }
  936. }
  937. elsif (scalar(@HolidayDevice) eq "2")
  938. {
  939. if ((ReadingsVal($HolidayDevice[0],"state","NONE") eq $HolidayDevice[1]) && ($DayToday == 1))
  940. {
  941. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $HolidayDevice[1]";
  942. $hash->{helper}{Today} = 8;
  943. }
  944. }
  945. elsif (scalar(@HolidayDevice) eq "3")
  946. {
  947. my $HolidayEvent = $HolidayDevice[2];
  948. $HolidayEvent =~ s/ //g;
  949. if ((ReadingsVal($HolidayDevice[0],$HolidayDevice[1],"NONE") eq $HolidayEvent) && ($DayToday == 1))
  950. {
  951. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - holiday => $HolidayDevice[0] - $HolidayDevice[1] - $HolidayEvent";
  952. $hash->{helper}{Today} = 8;
  953. }
  954. }
  955. $a ++;
  956. }
  957. }
  958. }
  959. ########################################################################################
  960. #
  961. # Vacation Check
  962. #
  963. ########################################################################################
  964. sub alarmclock_vacation_check($)
  965. {
  966. my ($hash) = @_;
  967. my ($SecNow, $MinNow, $HourNow, $DayNow, $MonthNow, $YearNow, $WDayNow, $YDNow, $SumTimeNow) = localtime(time);
  968. my $WDayToday = $WDayNow;
  969. my $WDayTomorrow = $WDayNow + 1;
  970. if ($WDayToday == 0)
  971. {
  972. $WDayToday = 7;
  973. }
  974. if ((AttrVal($hash->{NAME}, "VacationDevice", "NONE" ) ne "NONE" ) && (AttrVal($hash->{NAME}, "VacationCheck", "1" ) ne "0" ))
  975. {
  976. my @VacationDays = split(/\|/, AttrVal($hash->{NAME},"VacationDays","1|2|3|4|5|6|7"));
  977. my $DayToday = grep {$_==$WDayToday;} @VacationDays;
  978. my $DayTomorrow = grep {$_==$WDayTomorrow;} @VacationDays;
  979. my @Vacation = split(/\|/, AttrVal($hash->{NAME},"VacationDevice",""));
  980. my $a = 0;
  981. my $b = scalar(@Vacation);
  982. while ($a < $b)
  983. {
  984. my @VacationDevice = split(/:/,$Vacation[$a]);
  985. if (scalar(@VacationDevice) eq "1")
  986. {
  987. if( IsDevice( $VacationDevice[0], "holiday" ))
  988. {
  989. my $today = strftime("%2m-%2d", localtime(time));
  990. my $tomorrow = strftime("%2m-%2d", localtime(time+86400));
  991. my $todayevent = holiday_refresh($VacationDevice[0],$today);
  992. if (($todayevent ne "none") && ($DayToday == 1))
  993. {
  994. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $todayevent";
  995. $hash->{helper}{Today} = 9;
  996. }
  997. my $tomorrowevent = holiday_refresh($VacationDevice[0],$tomorrow);
  998. if (($tomorrowevent ne "none") && ($DayTomorrow == 1))
  999. {
  1000. $hash->{helper}{Tomorrow} = 9;
  1001. }
  1002. }
  1003. elsif( IsDevice($VacationDevice[0], "Calendar" ))
  1004. {
  1005. my $stoday = strftime("%2d.%2m.%2y", localtime(time));
  1006. my $stomorrow = strftime("%2d.%2m.%2y", localtime(time+86400));
  1007. my @tday = split('\.',$stoday);
  1008. my @tmor = split('\.',$stomorrow);
  1009. my $fline = Calendar_Get($defs{$VacationDevice[0]},"get","events","format:full");
  1010. my @lines = split('\n',$fline);
  1011. foreach $fline (@lines)
  1012. {
  1013. chomp($fline);
  1014. my @chunks = split(' ',$fline);
  1015. my @sday = split('\.',$chunks[2]);
  1016. my @eday = split('\.',substr($chunks[3],6,10));
  1017. my $rets = ($sday[2]-$tday[2]-2000)*365+($sday[1]-$tday[1])*31+($sday[0]-$tday[0]);
  1018. my $rete = ($eday[2]-$tday[2]-2000)*365+($eday[1]-$tday[1])*31+($eday[0]-$tday[0]);
  1019. if (($rete>=0) && ($rets<=0) && ($DayToday == 1))
  1020. {
  1021. my $todaydesc = $chunks[5];
  1022. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $todaydesc";
  1023. $hash->{helper}{Today} = 9;
  1024. }
  1025. $rets = ($sday[2]-$tmor[2]-2000)*365+($sday[1]-$tmor[1])*31+($sday[0]-$tmor[0]);
  1026. $rete = ($eday[2]-$tmor[2]-2000)*365+($eday[1]-$tmor[1])*31+($eday[0]-$tmor[0]);
  1027. if (($rete>=0) && ($rets<=0) && ($DayTomorrow == 1))
  1028. {
  1029. $hash->{helper}{Tomorrow} = 9;
  1030. }
  1031. }
  1032. }
  1033. }
  1034. elsif (scalar(@VacationDevice) eq "2")
  1035. {
  1036. if ((ReadingsVal($VacationDevice[0],"state","NONE") eq $VacationDevice[1]) && ($DayToday == 1))
  1037. {
  1038. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $VacationDevice[1]";
  1039. $hash->{helper}{Today} = 9;
  1040. }
  1041. }
  1042. elsif (scalar(@VacationDevice) eq "3")
  1043. {
  1044. my $VacationEvent = $VacationDevice[2];
  1045. $VacationEvent =~ s/ //g;
  1046. if ((ReadingsVal($VacationDevice[0],$VacationDevice[1],"NONE") eq $VacationEvent)&& ($DayToday == 1))
  1047. {
  1048. Log3 $hash->{NAME}, 1, "alarmclock: $hash->{NAME} - vacation => $VacationDevice[0] - $VacationDevice[1] - $VacationEvent";
  1049. $hash->{helper}{Today} = 9;
  1050. }
  1051. }
  1052. $a ++;
  1053. }
  1054. }
  1055. }
  1056. ########################################################################################
  1057. #
  1058. # skip
  1059. #
  1060. ########################################################################################
  1061. sub alarmclock_skip($)
  1062. {
  1063. my ($hash) = @_;
  1064. readingsSingleUpdate( $hash, "skip", "none", 1 );
  1065. alarmclock_createtimer($hash);
  1066. }
  1067. ########################################################################################
  1068. #
  1069. # Notify
  1070. #
  1071. ########################################################################################
  1072. sub alarmclock_Notify($$)
  1073. {
  1074. my ($hash, $devhash) = @_;
  1075. return "" if(IsDisabled($hash->{NAME})); # Return without any further action if the module is disabled
  1076. my $devName = $devhash->{NAME}; # Device that created the events
  1077. my $events = deviceEvents($devhash,0);
  1078. return if( !$events );
  1079. ### alarmclock_createtimer wird nach dem start von fhem aufgerufen ###
  1080. if($devName eq "global" && grep(m/^INITIALIZED|REREADCFG$/, @{$events}))
  1081. {
  1082. alarmclock_createtimer($hash);
  1083. }
  1084. ### Notify Alarm off ###
  1085. if((ReadingsVal($hash->{NAME},"state",0)) =~ /^(Alarm is running|PreAlarm is running|Snooze for.*)/)
  1086. {
  1087. if(my @AlarmOffDevice = split(/\|/, AttrVal($hash->{NAME},"EventForAlarmOff","")))
  1088. {
  1089. foreach my $AlarmOffDevice(@AlarmOffDevice)
  1090. {
  1091. my @AlarmOffDevicePart = split(/:/, $AlarmOffDevice,2);
  1092. if(($devName eq $AlarmOffDevicePart[0]) && (grep { $AlarmOffDevicePart[1] eq $_ } @{$events}))
  1093. {
  1094. alarmclock_alarmroutine_stop($hash);
  1095. }
  1096. }
  1097. }
  1098. }
  1099. ### Notify Snooze ###
  1100. if((ReadingsVal($hash->{NAME},"state",0)) eq "Alarm is running")
  1101. {
  1102. if(my @SnoozeDevice = split(/\|/, AttrVal($hash->{NAME},"EventForSnooze","")))
  1103. {
  1104. foreach my $SnoozeDevice(@SnoozeDevice)
  1105. {
  1106. my @SnoozeDevicePart = split(/:/, $SnoozeDevice,2);
  1107. if(($devName eq $SnoozeDevicePart[0]) && (grep { $SnoozeDevicePart[1] eq $_ } @{$events}))
  1108. {
  1109. alarmclock_snooze_start($hash);
  1110. }
  1111. }
  1112. }
  1113. }
  1114. }
  1115. 1;
  1116. =pod
  1117. =item helper
  1118. =item summary Fhem Modul to set up a Alarmclock
  1119. =item summary_DE Fhem Weckermodul
  1120. =begin html
  1121. <a name="alarmclock"></a>
  1122. <h3>alarmclock</h3>
  1123. <ul>
  1124. Fhem Modul to set up a Alarmclock
  1125. <br><br>
  1126. <a name="alarmclock_Define"></a>
  1127. <b>Define</b>
  1128. <ul>
  1129. <code>define &lt;name&gt; alarmclock</code>
  1130. <br>
  1131. Example: <code>define Wecker alarmclock</code>
  1132. <br>
  1133. </ul>
  1134. <br>
  1135. <a name="alarmclock_Set"></a>
  1136. <b>Set</b><br>
  1137. <ul>
  1138. <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>
  1139. Sets a alarm time for each day.
  1140. </li>
  1141. <li><b>AlarmTime_Weekdays</b> HH:MM<br>
  1142. Sets the same alarm time for each working day.
  1143. </li>
  1144. <li><b>AlarmTime_Weekend</b> HH:MM<br>
  1145. Sets the same alarm time for Saturday and Sunday.
  1146. </li>
  1147. <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>
  1148. Sets the alarm time of the respective day to off.
  1149. </li>
  1150. <li><b>stop</b> (Alarm)<br>
  1151. Stops a running alarm.
  1152. </li>
  1153. <li><b>save</b> (Weekprofile_1|Weekprofile_2|Weekprofile_3|Weekprofile_4|Weekprofile_5)<br>
  1154. Save alarm times in a profile.
  1155. </li>
  1156. <li><b>load</b> (Weekprofile_1|Weekprofile_2|Weekprofile_3|Weekprofile_4|Weekprofile_5)<br>
  1157. Load alarm times from profile.
  1158. </li>
  1159. <li><b>skip</b> (NextAlarm|None)<br>
  1160. Skips the next alarm.
  1161. </li>
  1162. <li><b>disable</b> (1|0|)<br>
  1163. Deactivated/Activated the alarmclock.
  1164. </li>
  1165. </ul>
  1166. <br>
  1167. <br>
  1168. <a name="alarmclock_Attr"></a>
  1169. <b>Attributes</b>
  1170. <ul>
  1171. <li><b>AlarmRoutine</b> <br>
  1172. A list separated by semicolon (;) which Fhem should run at the alarm time.<br>
  1173. Example: attr &lt;name&gt; AlarmRoutine set Licht on;set Radio on
  1174. </li>
  1175. <li><b>AlarmRoutineOff</b> <br>
  1176. A list separated by semicolon (;) which Fhem should execute to terminate the alarm.<br>
  1177. Example: attr &lt;name&gt; AlarmRoutineOff set Licht off;set Radio off
  1178. </li>
  1179. <li><b>EventForAlarmOff</b> <br>
  1180. Fhem-event to end the alarm.<br>
  1181. There are 2 possibilities:<br>
  1182. 1.Trigger on state.<br>
  1183. &lt;devicename&gt;:&lt;state&gt; Example: attr &lt;name&gt; EventForAlarmOff Taster:off <br>
  1184. 2.Trigger on reading. <br>
  1185. &lt;devicename&gt;:&lt;readingname&gt;: &lt;value&gt; Example: attr &lt;name&gt; EventForAlarmOff Taster:cSceneSet: on <br>
  1186. </li>
  1187. <li><b>EventForSnooze</b> <br>
  1188. Fhem-event to interrupt the alarm.<br>
  1189. The syntax is identical to EventForAlarmOff.<br>
  1190. Example: attr &lt;name&gt; EventForSnooze Taster:cSceneSet: off <br>
  1191. </li>
  1192. <li><b>SnoozeRoutine</b> <br>
  1193. A list separated by semicolon (;) which Fhem operate to interrupt the running alarm.<br>
  1194. Example: attr &lt;name&gt; SnoozeRoutine set Licht off;set Radio off
  1195. </li>
  1196. <li><b>SnoozeTimeInSec</b> <br>
  1197. Time in seconds how long the alarm should be interrupted.<br>
  1198. Example: attr &lt;name&gt; SnoozeTimeInSec 240 <br>
  1199. </li>
  1200. <li><b>PreAlarmRoutine</b> <br>
  1201. A list separated by semicolon (;) which Fhem operate at the pre-alarm.<br>
  1202. Example: attr &lt;name&gt; PreAlarmRoutine set Licht dim 30;set Radio on
  1203. </li>
  1204. <li><b>PreAlarmTimeInSec</b> <br>
  1205. Time in seconds between the alarm and the pre-alarm.<br>
  1206. Example: attr &lt;name&gt; PreAlarmTimeInSec 300<br>
  1207. In the example, the PreAlarmRoutine is executed 5 minutes before the regular alarm.
  1208. </li>
  1209. <li><b>HardAlarmRoutine</b> <br>
  1210. A list separated by semicolon (;) which is to be executed to force the awakening.<br>
  1211. Example: attr &lt;name&gt; HardAlarmRoutine set Sonos_Schlafzimmer Volume 40;set Licht dim 90
  1212. </li>
  1213. <li><b>HardAlarmTimeInSec</b> <br>
  1214. Here you can specify in seconds how long the alarm can "run" until HardAlarmRoutine is started.<br>
  1215. Example: attr &lt;name&gt; HardAlarmTimeInSec 300
  1216. </li>
  1217. <li><b>OffRoutine</b> <br>
  1218. A list separated by semicolon (;) which Fhem operate at the OffDefaultTime.<br>
  1219. Example: attr &lt;name&gt; OffRoutine set rr_Florian home;set Heizung on
  1220. </li>
  1221. <li><b>OffDefaultTime</b> <br>
  1222. Default time for the OffRoutine.<br>
  1223. Example: attr &lt;name&gt; OffDefaultTime 07:30
  1224. </li>
  1225. <li><b>MaxAlarmDurationInSec</b> <br>
  1226. Duration in seconds to stop automatically the running alarm.<br>
  1227. Example: attr &lt;name&gt; MaxAlarmDurationInSec 120
  1228. </li>
  1229. <li><b>RepRoutine</b> <br>
  1230. A list separated by semicolon (;) which is to be repeated.<br>
  1231. Example: attr &lt;name&gt; RepRoutine1 set Licht_Schlafzimmer dim 1
  1232. </li>
  1233. <li><b>RepRoutineWaitInSec</b> <br>
  1234. Time in seconds between the repetitions from RepRoutine.<br>
  1235. Example: attr &lt;name&gt; RepRoutine1WaitInSec 20
  1236. </li>
  1237. <li><b>RepRoutineRepeats</b> <br>
  1238. Number of repetitions of RepRoutine.<br>
  1239. Example: attr &lt;name&gt; RepRoutine1Repeats 15
  1240. </li>
  1241. <li><b>RepRoutineMode(Alarm|PreAlarm|off)</b> <br>
  1242. Alarm:Reproutine is started with the alarm.<br>
  1243. PreAlarm:Reproutine is started with the pre-alarm.<br>
  1244. off:Reproutine is deactivated.
  1245. </li>
  1246. <li><b>RepRoutineStop(Snooze|off)</b> <br>
  1247. Snooze:Reproutine is stopped with snooze.<br>
  1248. off:Reproutine is not stopped with snooze.
  1249. </li>
  1250. <li><b>HolidayDevice</b> <br>
  1251. Name of the holiday device.<br>
  1252. There are 3 possibilities:<br>
  1253. 1.holiday device from typ holiday or Calendar.<br>
  1254. &lt;devicename&gt;<br>
  1255. Example: attr &lt;name&gt; HolidayDevice Feiertage <br>
  1256. 2.On state of a device.For example a dummy <br>
  1257. &lt;devicename&gt;:&lt;value&gt; <br>
  1258. Example: attr &lt;name&gt; HolidayDevice MyDummy:Holiday <br>
  1259. Here the AlarmTime 8_Holiday takes effect when the state of the dummy has the value Holiday <br>
  1260. 3.On a reading of a device. <br>
  1261. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt;<br>
  1262. Example: attr &lt;name&gt; HolidayDevice MyDummy:Today:Holiday <br>
  1263. </li>
  1264. <li><b>HolidayCheck</b> <br>
  1265. 0 disables monitoring the holiday device<br>
  1266. 1 activates monitoring
  1267. </li>
  1268. <li><b>HolidayDays</b> <br>
  1269. List of days on which the alarmtime 8_Holiday may take effect<br>
  1270. Example: attr &lt;name&gt; HolidayDays 1|2|3|4|5 <br>
  1271. Default: 1|2|3|4|5|6|7
  1272. </li>
  1273. <li><b>VacationDevice</b> <br>
  1274. Name of the vacation device.<br>
  1275. There are 3 possibilities:<br>
  1276. 1.vacation device from typ holiday or Calendar.<br>
  1277. &lt;devicename&gt; <br>
  1278. Example: attr &lt;name&gt; VacationDevice Ferien <br>
  1279. 2.On state of a device.For example a dummy <br>
  1280. &lt;devicename&gt;:&lt;value&gt; <br>
  1281. Example: attr &lt;name&gt; VacationDevice MyDummy:Vacation <br>
  1282. Here the AlarmTime 9_Vacation takes effect when the state of the dummy has the value Vacation <br>
  1283. 3.On a reading of a device. <br>
  1284. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt; <br>
  1285. Example: attr &lt;name&gt; VacationDevice MyDummy:Today:Vacation <br>
  1286. </li>
  1287. <li><b>VacationCheck</b> <br>
  1288. 0 disables monitoring the vacation device<br>
  1289. 1 activates monitoring
  1290. </li>
  1291. <li><b>VacationDays</b> <br>
  1292. List of days on which the alarmtime 9_Vacation may take effect<br>
  1293. Example: attr &lt;name&gt; VacationDays 1|2|3|4|5 <br>
  1294. Default: 1|2|3|4|5|6|7
  1295. </li>
  1296. <li><b>PresenceDevice</b> <br>
  1297. Name of the presence device.<br>
  1298. There are 3 possibilities:<br>
  1299. 1.presence device from Typ presence.<br>
  1300. &lt;devicename&gt; <br>
  1301. Example: attr &lt;name&gt; PresenceDevice Presence <br>
  1302. Alarmclock cancel alarm when state is absent <br>
  1303. 2.On state of a device.For example a dummy <br>
  1304. &lt;devicename&gt;:&lt;value&gt; <br>
  1305. Example: attr &lt;name&gt; PresenceDevice MyDummy:absent <br>
  1306. Here the Alarmclock cancel alarm when the state of the dummy has the value absent <br>
  1307. 3.On a reading of a device. <br>
  1308. &lt;devicename&gt;:&lt;readingname&gt;:&lt;value&gt; <br>
  1309. Example: attr &lt;name&gt; PresenceDevice MyDummy:user:notathome <br>
  1310. </li>
  1311. <li><b>PresenceCheck</b> <br>
  1312. 0 disables monitoring the presence device<br>
  1313. 1 activates monitoring
  1314. </li>
  1315. <li><b>WeekprofileName</b> <br>
  1316. Optional list with name for storing the week profiles<br>
  1317. Example: attr &lt;name&gt; WeekprofileName MyWeek1,MyWeek2,MyWeek3 <br>
  1318. </li>
  1319. <li><b>disable</b> <br>
  1320. 1 disables all alarms<br>
  1321. 0 activates this again
  1322. </li>
  1323. </ul>
  1324. </ul>
  1325. =end html
  1326. =cut