51_RPI_GPIO.pm: interrupt after restart works now, paths editable

52_I2C_MCP342x.pm: bugfix (definition parameters will work now)


git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@11120 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
klauswitt 2016-03-23 23:49:16 +00:00
parent 74dfc0f249
commit 0cfdd14e8b
2 changed files with 258 additions and 233 deletions

View File

@ -22,27 +22,49 @@ use SetExtensions;
sub RPI_GPIO_fileaccess($$;$); sub RPI_GPIO_fileaccess($$;$);
my $gpiodir = ""; #GPIO base directory
my @gpiodirs = ("/sys/class/aml_gpio", "/sys/class/gpio" );
my $gpioprg = ""; #WiringPi GPIO utility
my @gpioprgs = ("/usr/local/bin/gpio", "/usr/bin/gpio");
sub RPI_GPIO_Initialize($) { sub RPI_GPIO_Initialize($) {
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "RPI_GPIO_Define"; foreach (@gpioprgs) {
$hash->{GetFn} = "RPI_GPIO_Get"; if(-x $_) {
$hash->{SetFn} = "RPI_GPIO_Set"; $gpioprg = $_;
$hash->{StateFn} = "RPI_GPIO_State"; Log3 undef, 4, "RPI_GPIO: wiringpi gpio utility exists: $gpioprg";
$hash->{AttrFn} = "RPI_GPIO_Attr"; last;
$hash->{UndefFn} = "RPI_GPIO_Undef"; } elsif (-e $_) {
$hash->{ExceptFn} = "RPI_GPIO_Except"; Log3 undef, 3, "RPI_GPIO: Attention, WiringPi gpio utility exists: $gpioprg but is not executable";
$hash->{AttrList} = "poll_interval" . }
" direction:input,output pud_resistor:off,up,down" . }
" interrupt:none,falling,rising,both" . foreach (@gpiodirs) {
" toggletostate:no,yes active_low:no,yes" . if(-e $_) {
" debounce_in_ms restoreOnStartup:no,yes,on,off,last" . $gpiodir = $_;
" unexportpin:no,yes" . Log3 undef, 4, "RPI_GPIO: gpio directory exists: $gpiodir";
" longpressinterval " . last;
"$readingFnAttributes"; }
} }
Log3 undef, 3, "RPI_GPIO: could not find gpio base directory, please add correct path in define" unless defined $gpiodir;
Log3 undef, 4, "RPI_GPIO: could not find/use WiringPi gpio utility base directory" unless defined $gpioprg;
my $gpiodir = "/sys/class/gpio"; #GPIO base directory $hash->{DefFn} = "RPI_GPIO_Define";
my $gpioprg = "/usr/local/bin/gpio"; #WiringPi GPIO utility $hash->{GetFn} = "RPI_GPIO_Get";
$hash->{SetFn} = "RPI_GPIO_Set";
$hash->{StateFn} = "RPI_GPIO_State";
$hash->{AttrFn} = "RPI_GPIO_Attr";
$hash->{ShutdownFn} = "RPI_GPIO_Shutdown";
$hash->{UndefFn} = "RPI_GPIO_Undef";
$hash->{ExceptFn} = "RPI_GPIO_Except";
$hash->{AttrList} = "poll_interval" .
" direction:input,output pud_resistor:off,up,down" .
" interrupt:none,falling,rising,both" .
" toggletostate:no,yes active_low:no,yes" .
" debounce_in_ms restoreOnStartup:no,yes,on,off,last" .
" unexportpin:no,yes longpressinterval" .
" $readingFnAttributes";
}
my %setsoutp = ( my %setsoutp = (
'on:noArg' => 0, 'on:noArg' => 0,
@ -51,12 +73,11 @@ my %setsoutp = (
); );
my %setsinpt = ( my %setsinpt = (
'readValue' => 0, 'readValue:noArg' => 0,
); );
sub RPI_GPIO_Define($$) { sub RPI_GPIO_Define($$) {
my ($hash, $def) = @_; my ($hash, $def) = @_;
my @args = split("[ \t]+", $def); my @args = split("[ \t]+", $def);
my $menge = int(@args); my $menge = int(@args);
if (int(@args) < 3) if (int(@args) < 3)
@ -67,67 +88,87 @@ sub RPI_GPIO_Define($$) {
#Pruefen, ob GPIO bereits verwendet #Pruefen, ob GPIO bereits verwendet
foreach my $dev (devspec2array("TYPE=$hash->{TYPE}")) { foreach my $dev (devspec2array("TYPE=$hash->{TYPE}")) {
if ($args[2] eq InternalVal($dev,"RPI_pin","")) { if ($args[2] eq InternalVal($dev,"RPI_pin","") && $hash->{NAME} ne InternalVal($dev,"NAME","") ) {
return "GPIO $args[2] already used by $dev"; return "GPIO $args[2] already used by $dev";
} }
} }
my $name = $args[0]; my $name = $args[0];
$hash->{RPI_pin} = $args[2]; $hash->{RPI_pin} = $args[2];
$hash->{dir_not_set} = 1;
if(-e "$gpiodir/gpio$hash->{RPI_pin}" && -w "$gpiodir/gpio$hash->{RPI_pin}/value" && -w "$gpiodir/gpio$hash->{RPI_pin}/direction") { #GPIO bereits exportiert? if ( defined $args[3] ) {
Log3 $hash, 4, "$name: gpio$hash->{RPI_pin} already exists"; return "unable to find gpio basedir $args[3]" unless (-e $args[3]);
#nix tun...ist ja schon da $hash->{GPIO_Basedir} = $args[3];
} elsif (-w "$gpiodir/export") { #gpio export Datei mit schreibrechten? } else {
Log3 $hash, 4, "$name: write access to file $gpiodir/export, use it to export GPIO"; return "unable to find gpio basedir $gpiodir" unless defined $gpiodir;
my $exp = IO::File->new("> $gpiodir/export"); #gpio ueber export anlegen $hash->{GPIO_Basedir} = $gpiodir;
print $exp "$hash->{RPI_pin}"; }
$exp->close;
} else { if ( defined $args[4] ) {
if ( defined(my $ret = RPI_GPIO_CHECK_GPIO_UTIL($gpioprg)) ) { #Abbbruch da kein gpio utility vorhanden return "unable to find wiringpi gpio utility: $gpioprg" unless (-e $args[4]);
Log3 $hash, 1, "$name: can't export gpio$hash->{RPI_pin}, no write access to $gpiodir/export and " . $ret; $hash->{WiringPi_gpio} = $args[4];
return "$name: can't export gpio$hash->{RPI_pin}, no write access to $gpiodir/export and " . $ret; } else {
} else { #nutze GPIO Utility? return "unable to find wiringpi gpio utility: $gpioprg" unless defined $gpioprg;
Log3 $hash, 4, "$name: using gpio utility to export pin"; $hash->{WiringPi_gpio} = $gpioprg;
RPI_GPIO_exuexpin($hash, "in"); }
$hash->{dir_not_set} = 1;
if(-e "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}" &&
-w "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value" &&
-w "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/direction") { #GPIO bereits exportiert?
Log3 $hash, 4, "$name: gpio$hash->{RPI_pin} already exists";
#nix tun...ist ja schon da
} elsif (-w "$hash->{GPIO_Basedir}/export") { #gpio export Datei mit schreibrechten?
Log3 $hash, 4, "$name: write access to file $hash->{GPIO_Basedir}/export, use it to export GPIO";
my $exp = IO::File->new("> $hash->{GPIO_Basedir}/export"); #gpio ueber export anlegen
print $exp "$hash->{RPI_pin}";
$exp->close;
} else {
if ( defined $hash->{WiringPi_gpio} ) { #GPIO Utility Vorhanden?
Log3 $hash, 4, "$name: using gpio utility to export pin";
RPI_GPIO_exuexpin($hash, "in");
} else { #Abbbruch da kein gpio utility vorhanden
my $msg = "$name: can't export gpio$hash->{RPI_pin}, no write access to $hash->{GPIO_Basedir}/export and WiringPi gpio utility not (correct) installed";
Log3 $hash, 1, $msg;
return $msg;
} }
} }
# wait for Pin export (max 5s) # wait for Pin export (max 5s)
my $checkpath = qq($gpiodir/gpio$hash->{RPI_pin}/value); my $checkpath = qq($hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value);
my $counter = 100; my $counter = 100;
while( $counter ){ while( $counter ){
last if( -e $checkpath && -w $checkpath ); last if( -e $checkpath && -w $checkpath );
Time::HiRes::sleep( 0.05 ); Time::HiRes::sleep( 0.05 );
$counter --; $counter --;
} }
unless( $counter ) { #abbrechen wenn export fehlgeschlagen unless( $counter ) { # nur wenn export fehlgeschlagen
# nochmal probieren wenn keine Schreibrechte auf GPIO Dateien ########## # nochmal probieren wenn keine Schreibrechte auf GPIO Dateien ##########
if ( defined(my $ret = RPI_GPIO_CHECK_GPIO_UTIL($gpioprg)) ) { #Abbbruch da kein gpio utility vorhanden if ( defined $hash->{WiringPi_gpio} ) { # nutze GPIO Utility fuer zweiten Exportversuch
if ( -e "$gpiodir/export") { Log3 $hash, 4, "$name: using gpio utility to export pin (first export via $hash->{GPIO_Basedir}/export failed)";
Log3 $hash, 1, "$name: \"$gpiodir/export\" exists and is " . ( ( -w "$gpiodir/export") ? "" : "NOT " ) . "writable"; RPI_GPIO_exuexpin($hash, "in");
} else { # Abbbruch da kein gpio utility vorhanden
Log3 $hash, 1, "$name: second attempt to export gpio$hash->{RPI_pin} also failed: WiringPi gpio utility not (correct) installed, possibly reasons for first fail:";
if ( -e "$hash->{GPIO_Basedir}/export") {
Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/export\" exists and is " . ( ( -w "$hash->{GPIO_Basedir}/export") ? "" : "NOT " ) . "writable";
} else { } else {
Log3 $hash, 1, "$name: gpio$hash->{RPI_pin}/value doesnt exist"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/export\" doesnt exist";
} }
if(-e "$gpiodir/gpio$hash->{RPI_pin}") { if(-e "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}") {
Log3 $hash, 1, "$name: \"$gpiodir/gpio$hash->{RPI_pin}\" exported but define aborted:"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}\" exported but define aborted:";
if ( -e "$gpiodir/gpio$hash->{RPI_pin}/value") { if ( -e "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value") {
Log3 $hash, 1, "$name: \"$gpiodir/gpio$hash->{RPI_pin}/value\" exists and is " . ( ( -w "$gpiodir/gpio$hash->{RPI_pin}/value") ? "" : "NOT " ) . "writable"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value\" exists and is " . ( ( -w "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value") ? "" : "NOT " ) . "writable";
} else { } else {
Log3 $hash, 1, "$name: \"$gpiodir/gpio$hash->{RPI_pin}/value\" doesnt exist"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/value\" doesnt exist";
} }
if ( -e "$gpiodir/gpio$hash->{RPI_pin}/direction") { if ( -e "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/direction") {
Log3 $hash, 1, "$name: \"$gpiodir/gpio$hash->{RPI_pin}/direction\" exists and is " . ( ( -w "$gpiodir/gpio$hash->{RPI_pin}/direction") ? "" : "NOT " ) . "writable"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/direction\" exists and is " . ( ( -w "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/direction") ? "" : "NOT " ) . "writable";
} else { } else {
Log3 $hash, 1, "$name: \"$gpiodir/gpio$hash->{RPI_pin}/direction\" doesnt exist"; Log3 $hash, 1, "$name: \"$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/direction\" doesnt exist";
} }
Log3 $hash, 1, "$name: second attempt to export gpio$hash->{RPI_pin} failed: " . $ret;
} }
return "$name: failed to export pin gpio$hash->{RPI_pin}, see logfile"; return "$name: failed to export pin gpio$hash->{RPI_pin}, see logfile";
} else { #nutze GPIO Utility fuer zweiten Exportversuch
Log3 $hash, 4, "$name: using gpio utility to export pin (first export via $gpiodir/export failed)";
RPI_GPIO_exuexpin($hash, "in");
} }
} }
@ -160,51 +201,33 @@ sub RPI_GPIO_Set($@) {
my ($hash, @a) = @_; my ($hash, @a) = @_;
my $name =$a[0]; my $name =$a[0];
my $cmd = $a[1]; my $cmd = $a[1];
#my $val = $a[2]; my $mt = AttrVal($name, 'direction', 'input');
if($mt && $mt eq "output") {
if(defined($attr{$name}) && defined($attr{$name}{"direction"})) { if ($cmd eq 'on') {
my $mt = $attr{$name}{"direction"}; RPI_GPIO_fileaccess($hash, "value", "1");
if($mt && $mt eq "output") { readingsSingleUpdate($hash, 'state', $cmd, 1);
#if ($cmd eq 'toggle') { } elsif ($cmd eq 'off') {
# my $val = RPI_GPIO_fileaccess($hash, "value"); #alten Wert des GPIO direkt auslesen RPI_GPIO_fileaccess($hash, "value", "0");
# $cmd = $val eq "0" ? "on" :"off"; readingsSingleUpdate($hash, 'state', $cmd, 1);
#}
if ($cmd eq 'on') {
RPI_GPIO_fileaccess($hash, "value", "1");
#$hash->{STATE} = 'on';
readingsBeginUpdate($hash);
#readingsBulkUpdate($hash, 'Pinlevel', $valalt);
readingsBulkUpdate($hash, 'state', "on");
readingsEndUpdate($hash, 1);
} elsif ($cmd eq 'off') {
RPI_GPIO_fileaccess($hash, "value", "0");
#$hash->{STATE} = 'off';
readingsBeginUpdate($hash);
#readingsBulkUpdate($hash, 'Pinlevel', $valalt);
readingsBulkUpdate($hash, 'state', "off");
readingsEndUpdate($hash, 1);
} else {
my $slist = join(' ', keys %setsoutp);
Log3 $hash, 5, "wird an setextensions gesendet: @a";
return SetExtensions($hash, $slist, @a);
}
} else { } else {
if(!defined($setsinpt{$cmd})) { my $slist = join(' ', keys %setsoutp);
return 'Unknown argument ' . $cmd . ', choose one of ' . join(' ', keys %setsinpt) Log3 $hash, 5, "wird an setextensions gesendet: @a";
} else { return SetExtensions($hash, $slist, @a);
} }
} elsif ($mt && $mt eq "input") {
if ($cmd eq 'readValue') {
RPI_GPIO_updatevalue($hash);
} else {
return 'Unknown argument ' . $cmd . ', choose one of ' . join(' ', keys %setsinpt)
} }
} }
if ($cmd eq 'readValue') { #noch bei input einpflegen return undef;
RPI_GPIO_updatevalue($hash);
}
} }
sub RPI_GPIO_State($$$$) { #reload readings at FHEM start sub RPI_GPIO_State($$$$) { #reload readings at FHEM start
my ($hash, $tim, $sname, $sval) = @_; my ($hash, $tim, $sname, $sval) = @_;
Log3 $hash, 4, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim"; Log3 $hash, 4, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim";
#if ( (AttrVal($hash->{NAME},"restoreOnStartup","yes") eq "yes") && ($sname ne "STATE") ) {
if ( $sname ne "STATE" && AttrVal($hash->{NAME},"restoreOnStartup","last") ne "no") { if ( $sname ne "STATE" && AttrVal($hash->{NAME},"restoreOnStartup","last") ne "no") {
if (AttrVal($hash->{NAME},"direction","") eq "output") { if (AttrVal($hash->{NAME},"direction","") eq "output") {
$hash->{READINGS}{$sname}{VAL} = $sval; $hash->{READINGS}{$sname}{VAL} = $sval;
@ -220,7 +243,7 @@ sub RPI_GPIO_State($$$$) { #reload readings at FHEM start
} }
} elsif ( AttrVal($hash->{NAME},"direction","") eq "input") { } elsif ( AttrVal($hash->{NAME},"direction","") eq "input") {
if ($sname eq "Toggle") { if ($sname eq "Toggle") {
#wenn restoreOnStartup "on" oder "off" und der Wert mit dem im Statefile uebereinstimmt wird der Zeitstempel aus dem Statefile gesetzt #wenn restoreOnStartup "on" oder "off" und der Wert mit dem im Statefile uebereinstimmt wird der Zeitstempel aus dem Statefile gesetzt
my $rval = AttrVal($hash->{NAME},"restoreOnStartup","last"); my $rval = AttrVal($hash->{NAME},"restoreOnStartup","last");
$rval = "last" if ( $rval ne "on" && $rval ne "off" ); $rval = "last" if ( $rval ne "on" && $rval ne "off" );
$tim = gettimeofday() if $rval ne "last" && $rval ne $sval; $tim = gettimeofday() if $rval ne "last" && $rval ne $sval;
@ -254,7 +277,6 @@ sub RPI_GPIO_State($$$$) { #reload readings at FHEM start
$hash->{READINGS}{$sname}{VAL} = $sval; $hash->{READINGS}{$sname}{VAL} = $sval;
$hash->{READINGS}{$sname}{TIME} = $tim; $hash->{READINGS}{$sname}{TIME} = $tim;
} }
#}
} }
} }
} }
@ -285,7 +307,7 @@ sub RPI_GPIO_Attr(@) {
} }
} }
} }
if ($attr eq 'direction') { if ($attr eq 'direction') {
if (!$val) { #$val nicht definiert: Einstellungen loeschen if (!$val) { #$val nicht definiert: Einstellungen loeschen
$msg = "$hash->{NAME}: no direction value. Use input output"; $msg = "$hash->{NAME}: no direction value. Use input output";
} elsif ($val eq "input") { } elsif ($val eq "input") {
@ -307,7 +329,7 @@ sub RPI_GPIO_Attr(@) {
$msg = "$hash->{NAME}: Wrong $attr value. Use input output"; $msg = "$hash->{NAME}: Wrong $attr value. Use input output";
} }
} }
if ($attr eq 'interrupt') { if ($attr eq 'interrupt') {
if ( !$val || ($val eq "none") ) { if ( !$val || ($val eq "none") ) {
RPI_GPIO_fileaccess($hash, "edge", "none"); RPI_GPIO_fileaccess($hash, "edge", "none");
RPI_GPIO_inthandling($hash, "stop"); RPI_GPIO_inthandling($hash, "stop");
@ -330,51 +352,48 @@ sub RPI_GPIO_Attr(@) {
$msg = "$hash->{NAME}: Wrong $attr value. Use none, falling, rising or both"; $msg = "$hash->{NAME}: Wrong $attr value. Use none, falling, rising or both";
} }
} }
#Tastfunktion: bei jedem Tastendruck wird State invertiert if ($attr eq 'toggletostate') { # Tastfunktion: bei jedem Tastendruck wird State invertiert
if ($attr eq 'toggletostate') { unless ( !$val || ($val eq ("yes" || "no") ) ) {
unless ( !$val || ($val eq ("yes" || "no") ) ) { $msg = "$hash->{NAME}: Wrong $attr value. Use yes or no";
$msg = "$hash->{NAME}: Wrong $attr value. Use yes or no"; }
} }
} if ($attr eq 'active_low') { # invertierte Logik
#invertierte Logik if ( !$val || ($val eq "no" ) ) {
if ($attr eq 'active_low') { RPI_GPIO_fileaccess($hash, "active_low", "0");
if ( !$val || ($val eq "no" ) ) { Log3 $hash, 5, "$hash->{NAME}: set attr active_low: no";
RPI_GPIO_fileaccess($hash, "active_low", "0"); } elsif ($val eq "yes") {
Log3 $hash, 5, "$hash->{NAME}: set attr active_low: no"; RPI_GPIO_fileaccess($hash, "active_low", "1");
} elsif ($val eq "yes") { Log3 $hash, 5, "$hash->{NAME}: set attr active_low: yes";
RPI_GPIO_fileaccess($hash, "active_low", "1"); } else {
Log3 $hash, 5, "$hash->{NAME}: set attr active_low: yes"; $msg = "$hash->{NAME}: Wrong $attr value. Use yes or no";
} else { }
$msg = "$hash->{NAME}: Wrong $attr value. Use yes or no"; }
} if ($attr eq 'debounce_in_ms') { # Entprellzeit
} if ( $val && ( ($val > 250) || ($val < 0) ) ) {
#Entprellzeit $msg = "$hash->{NAME}: debounce_in_ms value to big. Use 0 to 250";
if ($attr eq 'debounce_in_ms') { }
if ( $val && ( ($val > 250) || ($val < 0) ) ) { }
$msg = "$hash->{NAME}: debounce_in_ms value to big. Use 0 to 250"; if ($attr eq "pud_resistor" && $val) { # interner pullup/down Widerstand
} if($val =~ /^(off|up|down)$/) {
} if(-w "$hash->{GPIO_Basedir}/gpio$hash->{RPI_pin}/pull") {
if ($attr eq "pud_resistor" && $val) { $val =~ s/off/disable/;
if($val =~ /^(off|up|down)$/) { RPI_GPIO_fileaccess($hash, "pull", $val);
if(-w "$gpiodir/gpio$hash->{RPI_pin}/pull") { } else { #nur fuer Raspberry (ueber gpio utility)
$val =~ s/off/disable/; #my $pud;
RPI_GPIO_fileaccess($hash, "pull", $val); if ( defined $hash->{WiringPi_gpio} ) {
} else { #nur fuer Raspberry (ueber gpio utility) $val =~ s/off/tri/;
my $pud; RPI_GPIO_exuexpin($hash, $val);
if ( defined(my $ret = RPI_GPIO_CHECK_GPIO_UTIL($gpioprg)) ) { } else {
Log3 $hash, 1, "$hash->{NAME}: unable to change pud resistor:" . $ret; my $ret = "$hash->{NAME}: unable to change pud resistor: WiringPi gpio utility not (correct) installed";
return "$hash->{NAME}: " . $ret; Log3 $hash, 1, $ret;
} else { return $ret;
$val =~ s/off/tri/; }
$pud = $gpioprg." -g mode ".$hash->{RPI_pin}." ".$val; }
$pud = `$pud`; } else {
} $msg = "$hash->{NAME}: Wrong $attr value. Use off, up or down";
} }
} else { }
$msg = "$hash->{NAME}: Wrong $attr value. Use off, up or down"; return ($msg) ? $msg : undef;
}
}
return ($msg) ? $msg : undef;
} }
sub RPI_GPIO_Poll($) { #for attr poll_intervall -> readout pin value sub RPI_GPIO_Poll($) { #for attr poll_intervall -> readout pin value
@ -388,6 +407,33 @@ sub RPI_GPIO_Poll($) { #for attr poll_intervall -> readout pin value
return; return;
} }
sub RPI_GPIO_Shutdown($$) {
my ($hash, $arg) = @_;
if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) { # remove internal timer
RemoveInternalTimer($hash);
}
if ( ( AttrVal($hash->{NAME}, "interrupt", "none") ) ne ( "none" ) ) { # detach interrupt
delete $selectlist{$hash->{NAME}};
close($hash->{filehandle});
Log3 $hash, 5, "$hash->{NAME}: interrupt detached";
}
# to have a chance to externaly setup the GPIOs -
# leave GPIOs untouched if attr unexportpin is set to "no"
# only delete inputs (otherwise outputs will flicker during restart of FHEM)
if( AttrVal($hash->{NAME},"direction","") ne "output" and AttrVal($hash->{NAME},"unexportpin","") ne "no" ) {
if (-w "$hash->{GPIO_Basedir}/unexport") {# unexport if write access to unexport
my $uexp = IO::File->new("> $hash->{GPIO_Basedir}/unexport");
print $uexp "$hash->{RPI_pin}";
$uexp->close;
} else {# else use gpio utility
RPI_GPIO_exuexpin($hash, "unexport");
}
Log3 $hash, 5, "$hash->{NAME}: gpio$hash->{RPI_pin} removed";
}
return undef;
}
sub RPI_GPIO_Undef($$) { sub RPI_GPIO_Undef($$) {
my ($hash, $arg) = @_; my ($hash, $arg) = @_;
if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) { if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) {
@ -397,18 +443,18 @@ sub RPI_GPIO_Undef($$) {
delete $selectlist{$hash->{NAME}}; delete $selectlist{$hash->{NAME}};
close($hash->{filehandle}); close($hash->{filehandle});
} }
# to have a chance to externaly setup the GPIOs - # to have a chance to externaly setup the GPIOs -
# leave GPIOs untouched if attr unexportpin is set to "no" # leave GPIOs untouched if attr unexportpin is set to "no"
if(AttrVal($hash->{NAME},"unexportpin","") ne "no") { if(AttrVal($hash->{NAME},"unexportpin","") ne "no") {
if (-w "$gpiodir/unexport") {#unexport Pin alte Version if (-w "$hash->{GPIO_Basedir}/unexport") {#unexport Pin alte Version
my $uexp = IO::File->new("> $gpiodir/unexport"); my $uexp = IO::File->new("> $hash->{GPIO_Basedir}/unexport");
print $uexp "$hash->{RPI_pin}"; print $uexp "$hash->{RPI_pin}";
$uexp->close; $uexp->close;
} else {#alternative unexport Pin: } else {#alternative unexport Pin:
RPI_GPIO_exuexpin($hash, "unexport"); RPI_GPIO_exuexpin($hash, "unexport");
} }
} }
Log3 $hash, 1, "$hash->{NAME}: entfernt"; Log3 $hash, 4, "$hash->{NAME}: entfernt";
return undef; return undef;
} }
@ -437,7 +483,7 @@ sub RPI_GPIO_Except($) { #called from main if an interrupt occured
$valalt = "low"; $valalt = "low";
} }
if ( ( ($eval eq "rising") && ( $val == 1 ) ) || ( ($eval eq "falling") && ( $val == 0 ) ) ) { #nur bei Trigger auf steigende / fallende Flanke if ( ( ($eval eq "rising") && ( $val == 1 ) ) || ( ($eval eq "falling") && ( $val == 0 ) ) ) { #nur bei Trigger auf steigende / fallende Flanke
#Togglefunktion #Togglefunktion
if (!defined($hash->{READINGS}{Toggle}{VAL})) { #Togglewert existiert nicht -> anlegen if (!defined($hash->{READINGS}{Toggle}{VAL})) { #Togglewert existiert nicht -> anlegen
Log3 $hash, 5, "Toggle war nicht def"; Log3 $hash, 5, "Toggle war nicht def";
$valto = "on"; $valto = "on";
@ -452,29 +498,34 @@ sub RPI_GPIO_Except($) { #called from main if an interrupt occured
if (( AttrVal($hash->{NAME}, "toggletostate", "no") ) eq ( "yes" )) { #wenn Attr "toggletostate" gesetzt auch die Variable fuer den STATE wert setzen if (( AttrVal($hash->{NAME}, "toggletostate", "no") ) eq ( "yes" )) { #wenn Attr "toggletostate" gesetzt auch die Variable fuer den STATE wert setzen
$valst = $valto; $valst = $valto;
} }
#Zaehlfunktion #Zaehlfunktion
if (!defined($hash->{READINGS}{Counter}{VAL})) { #Zaehler existiert nicht -> anlegen if (!defined($hash->{READINGS}{Counter}{VAL})) { #Zaehler existiert nicht -> anlegen
Log3 $hash, 5, "Zaehler war nicht def"; Log3 $hash, 5, "Zaehler war nicht def";
$valcnt = "1"; $valcnt = "1";
} else { } else {
$valcnt = $hash->{READINGS}{Counter}{VAL} + 1; $valcnt = $hash->{READINGS}{Counter}{VAL} + 1;
Log3 $hash, 5, "Zaehler ist jetzt $valcnt"; Log3 $hash, 5, "Zaehler ist jetzt $valcnt";
} }
#langer Testendruck #Doppelklick (noch im Teststatus)
my $testtt = (gettimeofday() - $hash->{lasttrg} );
$hash->{lasttrg} = gettimeofday();
readingsSingleUpdate($hash, 'Dblclick', "on", 1) if $testtt < 2;
#langer Testendruck
} elsif ($eval eq "both") { } elsif ($eval eq "both") {
if ( $val == 1 ) { if ( $val == 1 ) {
my $lngpressInterval = AttrVal($hash->{NAME}, "longpressinterval", "1"); my $lngpressInterval = AttrVal($hash->{NAME}, "longpressinterval", "1");
InternalTimer(gettimeofday() + $lngpressInterval, 'RPI_GPIO_longpress', $hash, 0); InternalTimer(gettimeofday() + $lngpressInterval, 'RPI_GPIO_longpress', $hash, 0);
#$hash->{Anzeit} = gettimeofday();
} else { } else {
RemoveInternalTimer('RPI_GPIO_longpress'); RemoveInternalTimer('RPI_GPIO_longpress');
$vallp = 'off'; $vallp = 'off';
#my $zeit = $acttime; }
#$zeit -= $hash->{Anzeit}; #Doppelklick (noch im Teststatus)
#Log3 $hash, 5, "Anzeit: $zeit"; if ( $val == AttrVal($hash->{NAME}, "dblclicklevel", "1") ) {
#readingsBeginUpdate($hash); my $testtt = (gettimeofday() - $hash->{lasttrg} );
#readingsBulkUpdate($hash, 'Anzeit', $zeit); $hash->{lasttrg} = gettimeofday();
#readingsEndUpdate($hash, 1); readingsSingleUpdate($hash, 'Dblclick', "on", 1) if $testtt < 2;
} else {
readingsSingleUpdate($hash, 'Dblclick', "off", 1);
} }
} }
@ -495,9 +546,7 @@ sub RPI_GPIO_longpress($) { #for reading longpress
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $val = RPI_GPIO_fileaccess($hash, "value"); my $val = RPI_GPIO_fileaccess($hash, "value");
if ($val == 1) { if ($val == 1) {
readingsBeginUpdate($hash); readingsSingleUpdate($hash, 'Longpress', 'on', 1);
readingsBulkUpdate($hash, 'Longpress', 'on');
readingsEndUpdate($hash, 1);
} }
} }
@ -505,7 +554,7 @@ sub RPI_GPIO_dblclick($) {
} }
sub RPI_GPIO_updatevalue($) { #update value for Input devices sub RPI_GPIO_updatevalue($) { #update value for Input devices
my ($hash) = @_; my ($hash) = @_;
my $val = RPI_GPIO_fileaccess($hash, "value"); my $val = RPI_GPIO_fileaccess($hash, "value");
if ( defined ($val) ) { if ( defined ($val) ) {
@ -527,10 +576,9 @@ sub RPI_GPIO_updatevalue($) { #update value for Input devices
} }
sub RPI_GPIO_fileaccess($$;$) { #Fileaccess for GPIO base directory sub RPI_GPIO_fileaccess($$;$) { #Fileaccess for GPIO base directory
#my ($hash, $fname, $value) = @_;
my ($hash, @args) = @_; my ($hash, @args) = @_;
my $fname = $args[0]; my $fname = $args[0];
my $pinroot = qq($gpiodir/gpio$hash->{RPI_pin}); my $pinroot = qq($hash->{GPIO_Basedir}/gpio$hash->{RPI_pin});
my $file =qq($pinroot/$fname); my $file =qq($pinroot/$fname);
Log3 $hash, 5, "$hash->{NAME}, in fileaccess: $fname " . (defined($args[1])?$args[1]:""); Log3 $hash, 5, "$hash->{NAME}, in fileaccess: $fname " . (defined($args[1])?$args[1]:"");
@ -562,12 +610,6 @@ sub RPI_GPIO_fileaccess($$;$) { #Fileaccess for GPIO base directory
if ($fname eq "direction" && (not -w $file)) { #wenn direction und diese nicht schreibbar mit gpio utility versuchen if ($fname eq "direction" && (not -w $file)) { #wenn direction und diese nicht schreibbar mit gpio utility versuchen
Log3 $hash, 4, "$hash->{NAME}: direction ueber gpio utility einstellen"; Log3 $hash, 4, "$hash->{NAME}: direction ueber gpio utility einstellen";
RPI_GPIO_exuexpin($hash, $value); RPI_GPIO_exuexpin($hash, $value);
#if ( defined(my $ret = RPI_GPIO_CHECK_GPIO_UTIL($gpioprg)) ) {
# Log3 $hash, 1, "$hash->{NAME}: " . $ret;
#} else {
#my $exp = $gpioprg.' -g mode '.$hash->{RPI_pin}. ' '.$value;
#$exp = `$exp`;
#}
} else { } else {
my $fh = IO::File->new("> $file"); my $fh = IO::File->new("> $file");
if (defined $fh) { if (defined $fh) {
@ -580,42 +622,27 @@ sub RPI_GPIO_fileaccess($$;$) { #Fileaccess for GPIO base directory
} }
} }
sub RPI_GPIO_exuexpin($$) { #export, unexport and direction Pin via GPIO utility sub RPI_GPIO_exuexpin($$) { #export, unexport, direction, pud_resistor via GPIO utility
my ($hash, $dir) = @_; my ($hash, $dir) = @_;
my $sw; my $gpioutility = $hash->{WiringPi_gpio};
if ($dir eq "unexport") { if ( defined $hash->{WiringPi_gpio} ) {
$sw = $dir; my $sw;
$dir = ""; if ($dir eq "unexport") {
} else { $sw = $dir;
$sw = "export"; $dir = "";
$dir = "out" if ( $dir eq "high" || $dir eq "low" ); #auf out zurueck, da gpio tool dies nicht unterst?tzt } elsif ($dir eq "up" || $dir eq "down"|| $dir eq "tri") {
$dir = " ".$dir; $sw = "-g mode";
}
if ( defined(my $ret = RPI_GPIO_CHECK_GPIO_UTIL($gpioprg)) ) {
Log3 $hash, 1, "$hash->{NAME}: " . $ret;
} else {
my $exp = $gpioprg.' '.$sw.' '.$hash->{RPI_pin}.$dir;
$exp = `$exp`;
}
#######################
}
sub RPI_GPIO_CHECK_GPIO_UTIL {
my ($gpioprg) = @_;
my $ret = undef;
#unless (defined($hash->{gpio_util_exists})) {
if(-e $gpioprg) {
if(-x $gpioprg) {
unless(-u $gpioprg) {
$ret = "file $gpioprg is not setuid";
}
} else { } else {
$ret = "file $gpioprg is not executable"; $sw = "export";
$dir = "out" if ( $dir eq "high" || $dir eq "low" ); #auf out zurueck, da gpio tool dies nicht unterst?tzt
} }
my $exp = $gpioutility.' '.$sw.' '.$hash->{RPI_pin}. (defined $dir ? " " . $dir : "");
$exp = `$exp`;
} else { } else {
$ret = "file $gpioprg doesnt exist"; my $ret = "WiringPi gpio utility not (correct) installed";
Log3 $hash, 1, "$hash->{NAME}: $ret";
return $ret;
} }
return $ret;
} }
sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
@ -623,7 +650,7 @@ sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
my $msg = ''; my $msg = '';
if ( $arg eq "start") { if ( $arg eq "start") {
#FH fuer value-datei #FH fuer value-datei
my $pinroot = qq($gpiodir/gpio$hash->{RPI_pin}); my $pinroot = qq($hash->{GPIO_Basedir}/gpio$hash->{RPI_pin});
my $valfile = qq($pinroot/value); my $valfile = qq($pinroot/value);
$hash->{filehandle} = IO::File->new("< $valfile"); $hash->{filehandle} = IO::File->new("< $valfile");
if (!defined $hash->{filehandle}) { if (!defined $hash->{filehandle}) {
@ -683,13 +710,14 @@ sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
<a name="RPI_GPIODefine"></a> <a name="RPI_GPIODefine"></a>
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define <name> RPI_GPIO &lt;GPIO number&gt;</code><br><br> <code>define <name> RPI_GPIO &lt;GPIO number&gt;[ &lt;GPIO-Basedir&gt;[ &lt;WiringPi-gpio-utility&gt;]]</code><br><br>
all usable <code>GPIO number</code> can be found <a href="http://www.panu.it/raspberry/">here</a><br><br> all usable <code>GPIO number</code> can be found <a href="http://www.panu.it/raspberry/">here</a><br><br>
Examples: Examples:
<pre> <pre>
define Pin12 RPI_GPIO 18 define Pin12 RPI_GPIO 18
attr Pin12 poll_interval 5 attr Pin12 poll_interval 5
define Pin12 RPI_GPIO 18 /sys/class/gpio /usr/somewhere/bin/gpio
</pre> </pre>
</ul> </ul>
@ -828,13 +856,14 @@ sub RPI_GPIO_inthandling($$) { #start/stop Interrupthandling
<a name="RPI_GPIODefine"></a> <a name="RPI_GPIODefine"></a>
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; RPI_GPIO &lt;GPIO number&gt;</code><br><br> <code>define &lt;name&gt; RPI_GPIO &lt;GPIO number&gt;[ &lt;GPIO-Basedir&gt;[ &lt;WiringPi-gpio-utility&gt;]]</code><br><br>
Alle verf&uuml;gbaren <code>GPIO number</code> sind z.B. <a href="http://www.panu.it/raspberry/">hier</a> zu finden<br><br> Alle verf&uuml;gbaren <code>GPIO number</code> sind z.B. <a href="http://www.panu.it/raspberry/">hier</a> zu finden<br><br>
Beispiele: Beispiele:
<pre> <pre>
define Pin12 RPI_GPIO 18 define Pin12 RPI_GPIO 18
attr Pin12 poll_interval 5 attr Pin12 poll_interval 5
define Pin12 RPI_GPIO 18 /sys/class/gpio /usr/somewhere/bin/gpio
</pre> </pre>
</ul> </ul>

View File

@ -90,27 +90,23 @@ sub I2C_MCP342x_Init($$) {
my ( $hash, $args ) = @_; my ( $hash, $args ) = @_;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
Log3 $hash, 1, "$hash->{NAME}: Init Argumente1: $args";
if (defined $args && int(@$args) > 1) if (defined $args && int(@$args) < 1) {
{ Log3 $hash, 0, "Define: Wrong syntax. Usage:\n" .
return "Define: Wrong syntax. Usage:\n" . "define <name> MCP342x [<i2caddress>] [<type>]";
"define <name> MCP342x [<i2caddress>] [<type>]";
} }
if (defined (my $address = shift @$args)) {
if (defined (my $address = shift @$args)) { $hash->{I2C_Address} = $address =~ /^0x.*$/ ? oct($address) : $address;
$hash->{I2C_Address} = $address =~ /^0.*$/ ? oct($address) : $address; Log3 $hash, 0, "$name: I2C Address not valid" unless ($hash->{I2C_Address} < 128 && $hash->{I2C_Address} > 3);
return "$name I2C Address not valid" unless ($address < 128 && $address > 3); } else {
} else {
$hash->{I2C_Address} = hex(MCP3422_I2C_ADDRESS); $hash->{I2C_Address} = hex(MCP3422_I2C_ADDRESS);
} }
if (defined (my $channels = shift @$args)) { if (defined (my $channels = shift @$args)) {
$hash->{channels} = $channels if $channels == 2 || $channels == 4; $hash->{channels} = ($channels == 4 ? 4 : 2);
} else { } else {
$hash->{channels} = 2; $hash->{channels} = 2;
} }
my $msg = ''; my $msg = '';
# create default attributes # create default attributes
if (AttrVal($name, 'poll_interval', '?') eq '?') { if (AttrVal($name, 'poll_interval', '?') eq '?') {