36_EleroSwitch.pm 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. # $Id: 36_EleroSwitch.pm 14777 2017-07-24 10:48:30Z HCS $
  2. package main;
  3. use strict;
  4. use warnings;
  5. use SetExtensions;
  6. #=======================================================================================
  7. sub EleroSwitch_Initialize($) {
  8. my ($hash) = @_;
  9. $hash->{Match} = ".*";
  10. $hash->{DefFn} = "EleroSwitch_Define";
  11. $hash->{UndefFn} = "EleroSwitch_Undef";
  12. $hash->{FingerprintFn} = "EleroSwitch_Fingerprint";
  13. $hash->{ParseFn} = "EleroSwitch_Parse";
  14. $hash->{SetFn} = "EleroSwitch_Set";
  15. $hash->{GetFn} = "EleroSwitch_Get";
  16. $hash->{AttrFn} = "EleroSwitch_Attr";
  17. $hash->{AttrList} = "IODev " .
  18. "$readingFnAttributes ";
  19. $hash->{noAutocreatedFilelog} = 1;
  20. }
  21. #=======================================================================================
  22. sub EleroSwitch_Define($$) {
  23. my ( $hash, $def ) = @_;
  24. my @a = split( "[ \t][ \t]*", $def );
  25. return "Usage: define <name> EleroSwitch <Channel>" if(@a < 3);
  26. my $devName = $a[0];
  27. my $type = $a[1];
  28. my $channel = $a[2];
  29. $hash->{STATE} = 'Initialized';
  30. $hash->{NAME} = $devName;
  31. $hash->{TYPE} = $type;
  32. $hash->{channel} = $channel;
  33. $modules{EleroSwitch}{defptr}{$channel} = $hash;
  34. AssignIoPort($hash);
  35. if(defined($hash->{IODev}->{NAME})) {
  36. Log3 $devName, 4, "$devName: I/O device is " . $hash->{IODev}->{NAME};
  37. }
  38. else {
  39. Log3 $devName, 1, "$devName: no I/O device";
  40. }
  41. return undef;
  42. }
  43. #=======================================================================================
  44. sub EleroSwitch_Undef($$) {
  45. my ($hash, $arg) = @_;
  46. my $channel = $hash->{channel};
  47. RemoveInternalTimer($hash);
  48. delete( $modules{EleroSwitch}{defptr}{$channel} );
  49. return undef;
  50. }
  51. #=======================================================================================
  52. sub EleroSwitch_Get($@) {
  53. return undef;
  54. }
  55. #=======================================================================================
  56. sub EleroSwitch_Send($$) {
  57. my ( $hash, $position) = @_;
  58. my $channel = $hash->{channel};
  59. my $head = 'aa';
  60. my $msgLength = '05';
  61. my $msgCmd = '4c';
  62. my $firstBits = '';
  63. my $firstChannels = '';
  64. my $secondBits = '';
  65. my $secondChannels = '';
  66. my $checksum = '';
  67. my $payload = '';
  68. if($position eq 'off'){
  69. # stop / off
  70. $payload = '10';
  71. }
  72. elsif($position eq 'on'){
  73. # top / on
  74. $payload = '20';
  75. }
  76. elsif($position eq 'dim1'){
  77. # intermediate / dim1
  78. $payload = '44';
  79. }
  80. elsif($position eq 'dim2'){
  81. # tilt / dim2
  82. $payload = '24';
  83. }
  84. if($payload) {
  85. if($channel <= 8){
  86. $firstChannels = '00';
  87. $secondChannels = 2**($channel-1);
  88. $secondChannels = sprintf('%02x', $secondChannels);
  89. }
  90. else {
  91. $secondChannels = '00';
  92. $firstChannels = 2**($channel-1-8);
  93. $firstChannels = sprintf('%02x', $firstChannels);
  94. }
  95. my $checksumNumber = hex($head) + hex($msgLength) + hex($msgCmd) + hex($firstChannels) + hex($secondChannels) + hex($payload);
  96. my $byteUpperBound = 256;
  97. my $upperBound = $byteUpperBound;
  98. while($checksumNumber > $upperBound){
  99. $upperBound = $upperBound + $byteUpperBound;
  100. }
  101. $checksumNumber = $upperBound - $checksumNumber;
  102. $checksum = sprintf('%02x', $checksumNumber);
  103. my $byteMsg = $head.$msgLength.$msgCmd.$firstChannels.$secondChannels.$payload.$checksum;
  104. IOWrite($hash, "send", $byteMsg);
  105. }
  106. }
  107. #=======================================================================================
  108. sub EleroSwitch_Set($@) {
  109. my ( $hash, $name, $cmd, @params ) = @_;
  110. my $channel = $hash->{channel};
  111. my $iodev = $hash->{IODev}->{NAME};
  112. my $commands=("on:noArg off:noArg dim1:noArg dim2:noArg refresh:noArg");
  113. return $commands if( $cmd eq '?' || $cmd eq '');
  114. my $doRefresh = '0';
  115. if($cmd eq 'refresh'){
  116. IOWrite($hash, "refresh", $channel);
  117. }
  118. elsif($cmd eq 'on'){
  119. EleroSwitch_Send($hash, "on");
  120. $doRefresh = '1';
  121. }
  122. elsif($cmd eq 'off'){
  123. EleroSwitch_Send($hash, "off");
  124. $doRefresh = '1';
  125. }
  126. elsif($cmd eq 'dim1'){
  127. EleroSwitch_Send($hash, "dim1");
  128. }
  129. elsif($cmd eq 'dim2'){
  130. EleroSwitch_Send($hash, "dim2");
  131. $doRefresh = '1';
  132. }
  133. else {
  134. return "Unknown argument $cmd, choose one of $commands";
  135. }
  136. # Start a one time timer that refreshes this switch
  137. if($doRefresh) {
  138. RemoveInternalTimer($hash);
  139. InternalTimer(gettimeofday() + 2, "EleroSwitch_OnRefreshTimer", $hash, 0);
  140. }
  141. return undef;
  142. }
  143. #=======================================================================================
  144. sub EleroSwitch_Fingerprint($$) {
  145. my ($name, $msg) = @_;
  146. return ("", $msg);
  147. }
  148. #=======================================================================================
  149. sub EleroSwitch_Parse($$) {
  150. my ($hash, $msg) = @_;
  151. my $name = $hash->{NAME};
  152. my $buffer = $msg;
  153. # get the channel
  154. my $firstChannels = substr($buffer,6,2);
  155. my $secondChannels = substr($buffer,8,2);
  156. my $bytes = $firstChannels.$secondChannels ;
  157. $bytes = hex ($bytes);
  158. my $channel = 1;
  159. while ($bytes != 1 and $channel <= 15) {
  160. $bytes = $bytes >> 1;
  161. $channel++;
  162. }
  163. if($channel <= 15) {
  164. # Check if it is defined as a switch device
  165. my $switchChannels = AttrVal($name, "SwitchChannels", undef);
  166. if(defined $switchChannels) {
  167. my @channelList = split /,/, $switchChannels;
  168. if (!$channel ~~ @channelList) {
  169. return undef;
  170. }
  171. }
  172. else {
  173. return undef;
  174. }
  175. # get status
  176. my $statusByte = substr($buffer,10,2);
  177. my %deviceStati = ('00' => "no_information",
  178. '01' => "off",
  179. '02' => "on",
  180. '03' => "dim1",
  181. '04' => "dim2",
  182. '05' => "unknown",
  183. '06' => "overheated",
  184. '07' => "timeout",
  185. '08' => "unknown",
  186. '09' => "unknown",
  187. '0a' => "unknown",
  188. '0b' => "unknown",
  189. '0d' => "unknown",
  190. '0e' => "unknown",
  191. '0f' => "unknown",
  192. '10' => "off",
  193. '11' => "on"
  194. );
  195. my $newstate = $deviceStati{$statusByte};
  196. my $rhash = $modules{EleroSwitch}{defptr}{$channel};
  197. my $rname = $rhash->{NAME};
  198. if($modules{EleroSwitch}{defptr}{$channel}) {
  199. readingsBeginUpdate($rhash);
  200. readingsBulkUpdate($rhash, "state", $newstate);
  201. readingsEndUpdate($rhash,1);
  202. my @list;
  203. push(@list, $rname);
  204. return @list;
  205. }
  206. else {
  207. return "UNDEFINED EleroSwitch_$channel EleroSwitch $channel";
  208. }
  209. }
  210. }
  211. #=======================================================================================
  212. sub EleroSwitch_Attr(@) {
  213. }
  214. #=======================================================================================
  215. sub EleroSwitch_OnRefreshTimer($$) {
  216. my ($hash, @params) = @_;
  217. my $name = $hash->{NAME};
  218. my $channel = $hash->{channel};
  219. IOWrite($hash, "refresh", $channel);
  220. return undef;
  221. }
  222. 1;
  223. =pod
  224. =item summary Represents an Elero switch
  225. =item summary_DE Repräsentiert einen Elero switch
  226. =begin html
  227. <a name="EleroSwitch"></a>
  228. <h3>EleroSwitch</h3>
  229. <ul>
  230. This mudule implements an Elero switch. It uses EleroStick as IO-Device.
  231. <br><br>
  232. <a name="EleroSwitch_Define"></a>
  233. <b>Define</b>
  234. <ul>
  235. <code>define &lt;name&gt; EleroSwitch &lt;channel&gt;</code> <br>
  236. &lt;channel&gt; specifies the channel of the transmitter stick that shall be used.
  237. <br><br>
  238. </ul>
  239. <a name="EleroSwitch_Set"></a>
  240. <b>Set</b>
  241. <ul>
  242. <li>on<br>
  243. </li>
  244. <li>off<br>
  245. </li>
  246. <li>dim1<br>
  247. </li>
  248. <li>dim2<br>
  249. </li>
  250. <li>refresh<br>
  251. </li>
  252. </ul>
  253. <br>
  254. <a name="EleroSwitch_Get"></a>
  255. <b>Get</b>
  256. <ul>
  257. <li>no gets<br>
  258. </li><br>
  259. </ul>
  260. <a name="EleroSwitch_Attr"></a>
  261. <b>Attributes</b>
  262. <ul>
  263. <li>IODev<br>
  264. The name of the IO-Device, normally the name of the EleroStick definition</li>
  265. </ul><br>
  266. <a name="EleroSwitch_Readings"></a>
  267. <b>Readings</b>
  268. <ul>
  269. <li>state<br>
  270. Current state of the switch (on, off, dim1, dim2)</li>
  271. </ul><br>
  272. </ul>
  273. =end html
  274. =cut