17_SIS_PMS.pm 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. ################################################################
  2. #
  3. # Copyright notice
  4. #
  5. # (c) 2009 Copyright: Kai 'wusel' Siering (wusel+fhem at uu dot org)
  6. # All rights reserved
  7. #
  8. # This code is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # The GNU General Public License can be found at
  14. # http://www.gnu.org/copyleft/gpl.html.
  15. # A copy is found in the textfile GPL.txt and important notices to the license
  16. # from the author is found in LICENSE.txt distributed with these scripts.
  17. #
  18. # This script is distributed in the hope that it will be useful,
  19. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. # GNU General Public License for more details.
  22. #
  23. # This copyright notice MUST APPEAR in all copies of the script!
  24. ###############################################
  25. ###########################
  26. # 17_SIS_PMS.pm
  27. # Module for FHEM
  28. #
  29. # Contributed by Kai 'wusel' Siering <wusel+fhem@uu.org> in 2010
  30. # Based in part on work for FHEM by other authors ...
  31. # $Id: 17_SIS_PMS.pm 2076 2012-11-04 13:49:43Z rudolfkoenig $
  32. ###########################
  33. package main;
  34. use strict;
  35. use warnings;
  36. my $SIS_PMS_cmds ="off on on-till off-till toggle";
  37. sub
  38. SIS_PMS_Initialize($)
  39. {
  40. my ($hash) = @_;
  41. $hash->{Match} = "^socket ..:..:..:..:.. .+ state o.*";
  42. $hash->{SetFn} = "SIS_PMS_Set";
  43. # $hash->{StateFn} = "SIS_PMS_SetState";
  44. $hash->{DefFn} = "SIS_PMS_Define";
  45. $hash->{UndefFn} = "SIS_PMS_Undef";
  46. $hash->{ParseFn} = "SIS_PMS_Parse";
  47. }
  48. #############################
  49. sub
  50. SIS_PMS_Define($$)
  51. {
  52. my ($hash, $def) = @_;
  53. my @a = split("[ \t][ \t]*", $def);
  54. my $u = "wrong syntax: define <name> SIS_PMS <serial> <socket>";
  55. return $u if(int(@a) < 4);
  56. my $serial = $a[2];
  57. my $socketnr = $a[3];
  58. my $name = $a[0];
  59. my $serialnocolon=$serial;
  60. $serialnocolon =~ s/:/_/g;
  61. $modules{SIS_PMS}{defptr}{$name} = $hash;
  62. $hash->{SERIAL} = $serial;
  63. $hash->{SOCKET} = $socketnr;
  64. $hash->{NAME} = $name;
  65. $modules{SIS_PMS}{defptr}{$serialnocolon . $socketnr} = $hash;
  66. $hash->{PREV}{STATE} = "undefined";
  67. AssignIoPort($hash);
  68. }
  69. #############################
  70. sub
  71. SIS_PMS_Undef($$)
  72. {
  73. my ($hash, $name) = @_;
  74. #
  75. # foreach my $c (keys %{ $hash->{CODE} } ) {
  76. # $c = $hash->{CODE}{$c};
  77. #
  78. # # As after a rename the $name my be different from the $defptr{$c}{$n}
  79. # # we look for the hash.
  80. # foreach my $dname (keys %{ $modules{SIS_PMS}{defptr}{$c} }) {
  81. # delete($modules{SIS_PMS}{defptr}{$c}{$dname})
  82. # if($modules{SIS_PMS}{defptr}{$c}{$dname} == $hash);
  83. # }
  84. # }
  85. return undef;
  86. }
  87. #############################
  88. sub
  89. SIS_PMS_Parse($$)
  90. {
  91. my ($hash, $msg) = @_;
  92. my $serial;
  93. my $socknr;
  94. my $sockst;
  95. my $dummy;
  96. my $serialnocolon;
  97. # Msg format:
  98. # ^socket ..:..:..:..:.. . state o.*";
  99. ($dummy, $serial, $socknr, $dummy, $sockst) = split(' ', $msg);
  100. $serialnocolon=$serial;
  101. $serialnocolon =~ s/:/_/g;
  102. my $def = $modules{SIS_PMS}{defptr}{$serialnocolon . $socknr};
  103. if($def) {
  104. Log 5, "SIS_PMS: Found device as " . $def->{NAME};
  105. if($def->{STATE} ne $sockst) {
  106. $def->{READINGS}{PREVSTATE}{TIME} = TimeNow();
  107. $def->{READINGS}{PREVSTATE}{VAL} = $def->{STATE};
  108. Log 3, "SIS_PMS " . $def->{NAME} ." state changed from " . $def->{STATE} . " to $sockst";
  109. $def->{PREV}{STATE} = $def->{STATE};
  110. $def->{CHANGED}[0] = $sockst;
  111. DoTrigger($def->{NAME}, undef);
  112. }
  113. $def->{STATE} = $sockst;
  114. $def->{READINGS}{state}{TIME} = TimeNow();
  115. $def->{READINGS}{state}{VAL} = $sockst;
  116. Log 5, "SIS_PMS " . $def->{NAME} ." state $sockst";
  117. return $def->{NAME};
  118. } else {
  119. my $devname=$serial;
  120. $devname =~ s/:/_/g;
  121. Log 3, "SIS_PMS Unknown device $serial $socknr, please define it";
  122. if(defined($hash->{TMPLABEL})) {
  123. $devname=$hash->{TMPLABEL};
  124. return "UNDEFINED $devname SIS_PMS $serial $socknr";
  125. } else {
  126. return "UNDEFINED SIS_PMS_$devname.$socknr SIS_PMS $serial $socknr";
  127. }
  128. }
  129. }
  130. #############################
  131. sub
  132. SIS_PMS_Do_On_Till($@)
  133. {
  134. my ($hash, @a) = @_;
  135. return "Timespec (HH:MM[:SS]) needed for the on-till command" if(@a != 3);
  136. my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]);
  137. return $err if($err);
  138. my @lt = localtime;
  139. my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec);
  140. my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
  141. if($hms_now ge $hms_till) {
  142. Log 4, "on-till: won't switch as now ($hms_now) is later than $hms_till";
  143. return "";
  144. }
  145. my @b = ($a[0], "on");
  146. SIS_PMS_Set($hash, @b);
  147. my $tname = $hash->{NAME} . "_till";
  148. CommandDelete(undef, $tname) if($defs{$tname});
  149. CommandDefine(undef, "$tname at $hms_till set $a[0] off");
  150. }
  151. #############################
  152. sub
  153. SIS_PMS_Do_Off_Till($@)
  154. {
  155. my ($hash, @a) = @_;
  156. return "Timespec (HH:MM[:SS]) needed for the off-till command" if(@a != 3);
  157. my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]);
  158. return $err if($err);
  159. my @lt = localtime;
  160. my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec);
  161. my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]);
  162. if($hms_now ge $hms_till) {
  163. Log 4, "off-till: won't switch as now ($hms_now) is later than $hms_till";
  164. return "";
  165. }
  166. my @b = ($a[0], "off");
  167. SIS_PMS_Set($hash, @b);
  168. my $tname = $hash->{NAME} . "_till";
  169. CommandDelete(undef, $tname) if($defs{$tname});
  170. CommandDefine(undef, "$tname at $hms_till set $a[0] on");
  171. }
  172. ###################################
  173. sub
  174. SIS_PMS_Set($@)
  175. {
  176. my ($hash, @a) = @_;
  177. my $ret = undef;
  178. my $na = int(@a);
  179. my $what = lc($a[1]);
  180. return "no set value specified" if($na < 2 || $na > 3);
  181. my @cmds=split(" ", $SIS_PMS_cmds);
  182. my $ncmds=int(@cmds);
  183. my $i;
  184. my $known_cmd=0;
  185. for($i=0; $i<$ncmds; $i++) {
  186. if($cmds[$i] eq $what) {
  187. $known_cmd++;
  188. }
  189. }
  190. if($known_cmd==0) {
  191. return "Unknown argument $what, choose one of $SIS_PMS_cmds";
  192. }
  193. return SIS_PMS_Do_On_Till($hash, @a) if($a[1] eq "on-till");
  194. return SIS_PMS_Do_Off_Till($hash, @a) if($a[1] eq "off-till");
  195. my $prevstate=$hash->{STATE};
  196. my $currstate=$what;
  197. if($what eq "toggle") {
  198. if($prevstate eq "on") {
  199. $currstate="off";
  200. } elsif($prevstate eq "off") {
  201. $currstate="on";
  202. }
  203. }
  204. if($prevstate ne $currstate) {
  205. $hash->{READINGS}{PREVSTATE}{TIME} = TimeNow();
  206. $hash->{READINGS}{PREVSTATE}{VAL} = $prevstate;
  207. Log 3, "SIS_PMS " . $hash->{NAME} ." state changed from $prevstate to $currstate";
  208. $hash->{PREV}{STATE} = $prevstate;
  209. $hash->{CHANGED}[0] = $currstate;
  210. $hash->{STATE} = $currstate;
  211. $hash->{READINGS}{state}{TIME} = TimeNow();
  212. $hash->{READINGS}{state}{VAL} = $currstate;
  213. # DoTrigger($hash->{NAME}, undef);
  214. }
  215. my $msg;
  216. $msg=sprintf("%s %s %s", $hash->{SERIAL}, $hash->{SOCKET}, $what);
  217. IOWrite($hash, $what, $msg);
  218. return $ret;
  219. }
  220. 1;
  221. =pod
  222. =begin html
  223. <a name="SIS_PMS"></a>
  224. <h3>SIS_PMS</h3>
  225. <ul>
  226. This module is responsible for handling the actual sockets (power on,
  227. power off, toggle) on a "Silver Shield Power Manager", see <a href="#SISPM">SISPM</a>
  228. for how to define access to one (SIS_PMS stands for "Silver Shield Power Manager Socket").
  229. <br><br>
  230. <a name="SIS_PMSdefine"></a>
  231. <b>Define</b>
  232. <ul>
  233. <code>define &lt;name&gt; SIS_PMS &lt;serial&gt; &lt;socket&gt;</code>
  234. <br><br>
  235. To securely distinguish multiple attached Power Manager devices, the
  236. serial number of those is used. You get these with "sispmctl -s"&nbsp;- or
  237. just let autocreate define the sockets attached for you.<br>
  238. <ul>
  239. <li><code>&lt;serial&gt;</code> is the serial number of the Power Manager device, see above.</li>
  240. <li><code>&lt;socket&gt;</code> is a number between 1 and 4 (for a 4 socket model)</li>
  241. </ul>
  242. <br>
  243. Examples:
  244. <ul>
  245. <code>define lamp SIS_PMS 01:02:03:04:05 1</code><br>
  246. <code>define otherlamp SIS_PMS 01:02:03:04:05 3</code><br>
  247. <code>define tv SIS_PMS 01:01:38:44:55 1</code>
  248. </ul>
  249. </ul>
  250. <br>
  251. <a name="SIS_PMSset"></a>
  252. <b>Set </b>
  253. <ul>
  254. <code>set &lt;name&gt; &lt;value&gt; [&lt;time&gt;]</code>
  255. <br><br>
  256. where <code>value</code> is one of:<br>
  257. <pre>
  258. off
  259. on
  260. toggle
  261. on-till # Special, see the note
  262. off-till # Special, see the note
  263. </pre>
  264. Examples:
  265. <ul>
  266. <code>set lamp on</code><br>
  267. <code>set lamp1,lamp2,lamp3 on</code><br>
  268. <code>set lamp1-lamp3 on</code><br>
  269. <code>set hql_lamp on-till 18:45</code><br>
  270. </ul>
  271. <br>
  272. Notes:
  273. <ul>
  274. <li>As an external program is used, a noticeable delay may occur.</li>
  275. <li>*-till requires an absolute time in the "at" format (HH:MM:SS, HH:MM
  276. or { &lt;perl code&gt; }, where the perl-code returns a time
  277. specification).
  278. If the current time is greater than the specified time, then the
  279. command is ignored, else an "on" or "off" command, respectively, is
  280. generated, and for the given time an "off"/"on" command is
  281. scheduleld via the at command.</li>
  282. </ul>
  283. </ul>
  284. <br>
  285. <b>Get</b> <ul>N/A</ul><br>
  286. <a name="SIS_PMSattributes"></a>
  287. <b>Attributes</b>
  288. <ul>
  289. <li><a href="#do_not_notify">do_not_notify</a></li><br>
  290. <a name="attrdummy"></a>
  291. <li>dummy<br>
  292. Set the device attribute dummy to define devices which should not
  293. output any signals. Associated notifys will be executed if the signal
  294. is received. Used e.g. to react to a code from a sender, but it will
  295. not actually switch if triggered in the web frontend.
  296. </li><br>
  297. <li><a href="#loglevel">loglevel</a></li><br>
  298. </ul>
  299. </ul>
  300. =end html
  301. =cut