89_inputevent.pm 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package main;
  2. ###########################
  3. # 89_inputevent.pm
  4. # Modul for FHEM
  5. #
  6. # contributed by Dirk Hoffmann 2010-2011
  7. # $Id: 89_inputEvent.pm,v 0.2 2011/11/27 19:16:16 dirkho Exp $
  8. #
  9. #
  10. # Linux::Input wird benötigt
  11. ###########################
  12. use strict;
  13. use Switch;
  14. use warnings;
  15. use IO::Select;
  16. use Linux::Input;
  17. use vars qw{%attr %defs};
  18. sub Log($$);
  19. our $FH;
  20. ####################################
  21. # INPUTEVENT_Initialize
  22. # Implements Initialize function
  23. #
  24. sub INPUTEVENT_Initialize($) {
  25. my ($hash) = @_;
  26. Log 1, "INPUT/Event Initialize";
  27. # Provider
  28. $hash->{ReadFn} = "INPUTEVENT_Read";
  29. $hash->{ReadyFn} = "INPUTEVENT_Ready";
  30. # Consumer
  31. $hash->{DefFn} = "INPUTEVENT_Define";
  32. $hash->{UndefFn} = "INPUTEVENT_Undef";
  33. $hash->{SetFn} = "INPUTEVENT_Set";
  34. $hash->{AttrList}= "model:EVENT loglevel:0,1,2,3,4,5";
  35. $hash->{READINGS}{uTIME}{VAL} = 0;
  36. $hash->{READINGS}{lastCode}{VAL} = 0;
  37. }
  38. #####################################
  39. # INPUTEVENT_Define
  40. # Implements DefFn function
  41. #
  42. sub INPUTEVENT_Define($$) {
  43. my ($hash, $def) = @_;
  44. my ($name, undef, $dev, $msIgnore) = split("[ \t][ \t]*", $def);
  45. if (!$msIgnore) {
  46. $msIgnore = 175;
  47. }
  48. delete $hash->{fh};
  49. delete $hash->{FD};
  50. my $fileno;
  51. if($dev eq "none") {
  52. Log 1, "Input device is none, commands will be echoed only";
  53. return undef;
  54. }
  55. Log 4, "Opening input device at $dev. Repeated commands within $msIgnore miliseconds was ignored.";
  56. if ($dev=~/^\/dev\/input/) {
  57. my $OS=$^O;
  58. if ($OS eq 'MSWin32') {
  59. my $logMsg = "Input devices only avilable under Linux OS at this time.";
  60. Log 1, $logMsg;
  61. return $logMsg;
  62. } else {
  63. if ($@) {
  64. my $logMsg = "Error using Modul Linux::Input";
  65. $hash->{STATE} = $logMsg;
  66. Log 1, $logMsg;
  67. return $logMsg . " Can't open Linux::Input $@\n";
  68. }
  69. my $devObj = Linux::Input->new($dev);
  70. if (!$devObj) {
  71. my $logMsg = "Error opening device";
  72. $hash->{STATE} = "error opening device";
  73. Log 1, $logMsg . " $dev";
  74. return "Can't open Device $dev: $^E\n";
  75. }
  76. my $select = IO::Select->new($devObj->fh);
  77. foreach my $fh ($select->handles) {
  78. $fileno = $fh->fileno;
  79. }
  80. $selectlist{"$name.$dev"} = $hash;
  81. $hash->{fh} = $devObj->fh;
  82. $hash->{FD} = $fileno;
  83. $hash->{SelectObj} = $select;
  84. $hash->{STATE} = "Opened";
  85. $hash->{DeviceName}=$name;
  86. $hash->{msIgnore}=$msIgnore;
  87. Log 4, "$name connected to device $dev";
  88. }
  89. } else {
  90. my $logMsg = "$dev is no device and not implemented";
  91. $hash->{STATE} = $logMsg;
  92. Log 1, $logMsg;
  93. return $logMsg;
  94. }
  95. return undef;
  96. }
  97. #####################################
  98. # implements UnDef-Function
  99. #
  100. sub INPUTEVENT_Undef($$) {
  101. my ($hash, $arg) = @_;
  102. my $name = $hash->{NAME};
  103. my $fh = $hash->{fh};
  104. delete $hash->{fh};
  105. $hash->{STATE}='Closed';
  106. if ($fh) {
  107. $fh->close();
  108. }
  109. Log 5, "$name shutdown complete";
  110. return undef;
  111. }
  112. #####################################
  113. # INPUTEVENT_Set
  114. # implement SetFn
  115. # currently nothing to set
  116. #
  117. sub INPUTEVENT_Ready($$) {
  118. my ($hash, $dev) = @_;
  119. my $select= $hash->{SelectObj};
  120. return ($select->can_read(0));
  121. }
  122. #####################################
  123. # INPUTEVENT_Set
  124. # implement SetFn
  125. # currently nothing to set
  126. #
  127. sub INPUTEVENT_Set($@) {
  128. my ($hash, @a) = @_;
  129. my $name=$a[0];
  130. my $msg = "$name => No Set function implemented";
  131. Log 1,$msg;
  132. return $msg;
  133. }
  134. #####################################
  135. # INPUTEVENT_Read
  136. # Implements ReadFn, called from global select
  137. #
  138. sub INPUTEVENT_Read($$) {
  139. my ($hash) = @_;
  140. my $fh = $hash->{fh};
  141. my $select= $hash->{SelectObj};
  142. my $name = $hash->{NAME};
  143. my $message = undef;
  144. if( $select->can_read(0) ){
  145. $fh->read($message,16);
  146. INPUTEVENT_Parse($hash, $message);
  147. }
  148. return 1;
  149. }
  150. #####################################
  151. # INPUTEVENT_Parse
  152. # decodes complete frame
  153. # called directly from INPUTEVENT_Read
  154. sub INPUTEVENT_Parse($$) {
  155. my ($hash, $msg) = @_;
  156. my $name = $hash->{NAME};
  157. my $message;
  158. my ($b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$b10,$b11,$b12,$b13,$b14,$b15) =
  159. map {$_ & 0x7F} unpack("U*",$msg);
  160. my $sec = sprintf('%10s', $b0 + $b1*256 + $b2*256*256 + $b3*256*256*256);
  161. my $ySec = sprintf('%06s', $b4 + $b5*256 + $b6*256*256);
  162. my $type = $b8;
  163. my $code = $b10;
  164. my $value = sprintf('%07s', $b12 + $b13*256 + $b14*256*256);
  165. if ($type eq 4 && $code eq 3) {
  166. $message = "$name => $sec.$ySec, type: $type, code: $code, value: $value";
  167. # Set $ignoreUSecs => µSec sice last command.
  168. my $uTime = $sec * 1000000 + $ySec;
  169. my $ignoreUSecs = $uTime - $hash->{READINGS}{uTIME}{VAL};
  170. my $tm = TimeNow();
  171. $hash->{READINGS}{uTIME}{VAL} = $uTime;
  172. $hash->{READINGS}{uTIME}{TIME} = $tm;
  173. #Log 4, $hash->{READINGS}{lastCode} . " _ " . $value . " | " . $hash->{READINGS}{uTIME} . " --- " . $uTime . " +++ " . $ignoreUSecs;
  174. # IR-codes was repeated with short delay. So we ignor commands the next µSeconds set in the define command. (Default 175000)
  175. if (($ignoreUSecs > ($hash->{msIgnore} * 1000)) || ($hash->{READINGS}{lastCode}{VAL} ne $value)) {
  176. $hash->{READINGS}{LAST}{VAL} = unpack('H*',$msg);
  177. $hash->{READINGS}{LAST}{TIME} = $tm;
  178. $hash->{READINGS}{RAW}{VAL} = unpack('H*',$msg);
  179. $hash->{READINGS}{RAW}{TIME} = $tm;
  180. $hash->{READINGS}{lastCode}{VAL} = $value;
  181. $hash->{READINGS}{lastCode}{TIME} = $tm;
  182. Log 4, $message;
  183. DoTrigger($name, $message);
  184. }
  185. }
  186. }
  187. #####################################
  188. sub INPUTEVENT_List($$) {
  189. my ($hash,$msg) = @_;
  190. $msg = INPUTEVENT_Get($hash,$hash->{NAME},'list');
  191. return $msg;
  192. }
  193. 1;