package main; ########################### # 89_inputevent.pm # Modul for FHEM # # contributed by Dirk Hoffmann 2010-2011 # $Id: 89_inputEvent.pm,v 0.2 2011/11/27 19:16:16 dirkho Exp $ # # # Linux::Input wird benötigt ########################### use strict; use Switch; use warnings; use IO::Select; use Linux::Input; use vars qw{%attr %defs}; sub Log($$); our $FH; #################################### # INPUTEVENT_Initialize # Implements Initialize function # sub INPUTEVENT_Initialize($) { my ($hash) = @_; Log 1, "INPUT/Event Initialize"; # Provider $hash->{ReadFn} = "INPUTEVENT_Read"; $hash->{ReadyFn} = "INPUTEVENT_Ready"; # Consumer $hash->{DefFn} = "INPUTEVENT_Define"; $hash->{UndefFn} = "INPUTEVENT_Undef"; $hash->{SetFn} = "INPUTEVENT_Set"; $hash->{AttrList}= "model:EVENT loglevel:0,1,2,3,4,5"; $hash->{READINGS}{uTIME}{VAL} = 0; $hash->{READINGS}{lastCode}{VAL} = 0; } ##################################### # INPUTEVENT_Define # Implements DefFn function # sub INPUTEVENT_Define($$) { my ($hash, $def) = @_; my ($name, undef, $dev, $msIgnore) = split("[ \t][ \t]*", $def); if (!$msIgnore) { $msIgnore = 175; } delete $hash->{fh}; delete $hash->{FD}; my $fileno; if($dev eq "none") { Log 1, "Input device is none, commands will be echoed only"; return undef; } Log 4, "Opening input device at $dev. Repeated commands within $msIgnore miliseconds was ignored."; if ($dev=~/^\/dev\/input/) { my $OS=$^O; if ($OS eq 'MSWin32') { my $logMsg = "Input devices only avilable under Linux OS at this time."; Log 1, $logMsg; return $logMsg; } else { if ($@) { my $logMsg = "Error using Modul Linux::Input"; $hash->{STATE} = $logMsg; Log 1, $logMsg; return $logMsg . " Can't open Linux::Input $@\n"; } my $devObj = Linux::Input->new($dev); if (!$devObj) { my $logMsg = "Error opening device"; $hash->{STATE} = "error opening device"; Log 1, $logMsg . " $dev"; return "Can't open Device $dev: $^E\n"; } my $select = IO::Select->new($devObj->fh); foreach my $fh ($select->handles) { $fileno = $fh->fileno; } $selectlist{"$name.$dev"} = $hash; $hash->{fh} = $devObj->fh; $hash->{FD} = $fileno; $hash->{SelectObj} = $select; $hash->{STATE} = "Opened"; $hash->{DeviceName}=$name; $hash->{msIgnore}=$msIgnore; Log 4, "$name connected to device $dev"; } } else { my $logMsg = "$dev is no device and not implemented"; $hash->{STATE} = $logMsg; Log 1, $logMsg; return $logMsg; } return undef; } ##################################### # implements UnDef-Function # sub INPUTEVENT_Undef($$) { my ($hash, $arg) = @_; my $name = $hash->{NAME}; my $fh = $hash->{fh}; delete $hash->{fh}; $hash->{STATE}='Closed'; if ($fh) { $fh->close(); } Log 5, "$name shutdown complete"; return undef; } ##################################### # INPUTEVENT_Set # implement SetFn # currently nothing to set # sub INPUTEVENT_Ready($$) { my ($hash, $dev) = @_; my $select= $hash->{SelectObj}; return ($select->can_read(0)); } ##################################### # INPUTEVENT_Set # implement SetFn # currently nothing to set # sub INPUTEVENT_Set($@) { my ($hash, @a) = @_; my $name=$a[0]; my $msg = "$name => No Set function implemented"; Log 1,$msg; return $msg; } ##################################### # INPUTEVENT_Read # Implements ReadFn, called from global select # sub INPUTEVENT_Read($$) { my ($hash) = @_; my $fh = $hash->{fh}; my $select= $hash->{SelectObj}; my $name = $hash->{NAME}; my $message = undef; if( $select->can_read(0) ){ $fh->read($message,16); INPUTEVENT_Parse($hash, $message); } return 1; } ##################################### # INPUTEVENT_Parse # decodes complete frame # called directly from INPUTEVENT_Read sub INPUTEVENT_Parse($$) { my ($hash, $msg) = @_; my $name = $hash->{NAME}; my $message; my ($b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$b10,$b11,$b12,$b13,$b14,$b15) = map {$_ & 0x7F} unpack("U*",$msg); my $sec = sprintf('%10s', $b0 + $b1*256 + $b2*256*256 + $b3*256*256*256); my $ySec = sprintf('%06s', $b4 + $b5*256 + $b6*256*256); my $type = $b8; my $code = $b10; my $value = sprintf('%07s', $b12 + $b13*256 + $b14*256*256); if ($type eq 4 && $code eq 3) { $message = "$name => $sec.$ySec, type: $type, code: $code, value: $value"; # Set $ignoreUSecs => µSec sice last command. my $uTime = $sec * 1000000 + $ySec; my $ignoreUSecs = $uTime - $hash->{READINGS}{uTIME}{VAL}; my $tm = TimeNow(); $hash->{READINGS}{uTIME}{VAL} = $uTime; $hash->{READINGS}{uTIME}{TIME} = $tm; #Log 4, $hash->{READINGS}{lastCode} . " _ " . $value . " | " . $hash->{READINGS}{uTIME} . " --- " . $uTime . " +++ " . $ignoreUSecs; # IR-codes was repeated with short delay. So we ignor commands the next µSeconds set in the define command. (Default 175000) if (($ignoreUSecs > ($hash->{msIgnore} * 1000)) || ($hash->{READINGS}{lastCode}{VAL} ne $value)) { $hash->{READINGS}{LAST}{VAL} = unpack('H*',$msg); $hash->{READINGS}{LAST}{TIME} = $tm; $hash->{READINGS}{RAW}{VAL} = unpack('H*',$msg); $hash->{READINGS}{RAW}{TIME} = $tm; $hash->{READINGS}{lastCode}{VAL} = $value; $hash->{READINGS}{lastCode}{TIME} = $tm; Log 4, $message; DoTrigger($name, $message); } } } ##################################### sub INPUTEVENT_List($$) { my ($hash,$msg) = @_; $msg = INPUTEVENT_Get($hash,$hash->{NAME},'list'); return $msg; } 1;