diff --git a/fhem/FHEM/52_I2C_MCP23017.pm b/fhem/FHEM/52_I2C_MCP23017.pm index 04b90e90d..6809d10fc 100644 --- a/fhem/FHEM/52_I2C_MCP23017.pm +++ b/fhem/FHEM/52_I2C_MCP23017.pm @@ -1,13 +1,9 @@ ############################################################################## # $Id$ ############################################################################## -# Modul for I2C PWM Driver MCP23017 -# -# define I2C_MCP23017 -# set -# -# contributed by Klaus Wittstock (2013) email: klauswittstock bei gmail punkt com +# Modul for I2C GPIO Extender MCP23017 # +# contributed by Klaus Wittstock (2013) email: klauswittstock bei gmail ############################################################################## package main; @@ -17,27 +13,27 @@ use SetExtensions; use Scalar::Util qw(looks_like_number); my %Registers = ( - 'IODIRA' => 0x00, #1 = input; 0 = output (default 1) - 'IODIRB' => 0x01, - 'IPOLA' => 0x02, #1 inverts logic (default 0) - 'IPOLB' => 0x03, - 'GPINTENA' => 0x04, #1 enables the pin for interrupt-on-change (default 0) - 'GPINTENB' => 0x05, - 'DEFVALA' => 0x06, #The default comparison value for interrupt (opposite value will caues an interrupt) (default 0) - 'DEFVALB' => 0x07, - 'INTCONA' => 0x08, #If a bit is set, the corresponding I/O pin is compared against DEFVAL register. Otherwise against the previous value. - 'INTCONB' => 0x09, - 'IOCON' => 0x0A, - 'GPPUA' => 0x0C, #100k pull up resistor for input - 'GPPUB' => 0x0D, - 'INTFA' => 0x0E, #shows which Pin caused the interrupt (ro) - 'INTFB' => 0x0F, - 'INTCAPA' => 0x10, #status from all registers at the time the interrupt occured, remain unchanged until a read of INTCAP or GPIO. (ro) - 'INTCAPB' => 0x11, - 'GPIOA' => 0x12, #value on the ports (r/w) - 'GPIOB' => 0x13, - 'OLATA' => 0x14, - 'OLATB' => 0x15, + 'IODIRA' => 0x00, #1 = input; 0 = output (default 1) + 'IODIRB' => 0x01, + 'IPOLA' => 0x02, #1 inverts logic (default 0) + 'IPOLB' => 0x03, + 'GPINTENA' => 0x04, #1 enables the pin for interrupt-on-change (default 0) + 'GPINTENB' => 0x05, + 'DEFVALA' => 0x06, #The default comparison value for interrupt (opposite value will caues an interrupt) (default 0) + 'DEFVALB' => 0x07, + 'INTCONA' => 0x08, #If a bit is set, the corresponding I/O pin is compared against DEFVAL register. Otherwise against the previous value. + 'INTCONB' => 0x09, + 'IOCON' => 0x0A, + 'GPPUA' => 0x0C, #100k pull up resistor for input + 'GPPUB' => 0x0D, + 'INTFA' => 0x0E, #shows which Pin caused the interrupt (ro) + 'INTFB' => 0x0F, + 'INTCAPA' => 0x10, #status from all registers at the time the interrupt occured, remain unchanged until a read of INTCAP or GPIO. (ro) + 'INTCAPB' => 0x11, + 'GPIOA' => 0x12, #value on the ports (r/w) + 'GPIOB' => 0x13, + 'OLATA' => 0x14, + 'OLATB' => 0x15, ); my %setsP = ( @@ -55,70 +51,70 @@ my %intout = ( ); ############################################################################### sub I2C_MCP23017_Initialize($) { - my ($hash) = @_; - $hash->{DefFn} = "I2C_MCP23017_Define"; - $hash->{InitFn} = 'I2C_MCP23017_Init'; - $hash->{UndefFn} = "I2C_MCP23017_Undefine"; - $hash->{AttrFn} = "I2C_MCP23017_Attr"; - $hash->{StateFn} = "I2C_MCP23017_State"; - $hash->{SetFn} = "I2C_MCP23017_Set"; - $hash->{GetFn} = "I2C_MCP23017_Get"; - $hash->{I2CRecFn} = "I2C_MCP23017_I2CRec"; - $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 showtime:1,0". - "poll_interval OutputPorts ". - "Pullup invert_input Interrupt OnStartup ". + my ($hash) = @_; + $hash->{DefFn} = "I2C_MCP23017_Define"; + $hash->{InitFn} = 'I2C_MCP23017_Init'; + $hash->{UndefFn} = "I2C_MCP23017_Undefine"; + $hash->{AttrFn} = "I2C_MCP23017_Attr"; + $hash->{StateFn} = "I2C_MCP23017_State"; + $hash->{SetFn} = "I2C_MCP23017_Set"; + $hash->{GetFn} = "I2C_MCP23017_Get"; + $hash->{I2CRecFn} = "I2C_MCP23017_I2CRec"; + $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:1,0 showtime:1,0". + "poll_interval OutputPorts ". + "Pullup invert_input Interrupt OnStartup ". "InterruptOut:separate_active-low,separate_active-high,separate_open-drain,connected_active-low,connected_active-high,connected_open-drain ". - "$readingFnAttributes"; + "$readingFnAttributes"; } ############################################################################### sub I2C_MCP23017_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t]+", $def); $hash->{STATE} = 'defined'; - if ($main::init_done) { - eval { I2C_MCP23017_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); }; - return I2C_MCP23017_Catch($@) if $@; - } - return undef; + if ($main::init_done) { + eval { I2C_MCP23017_Init( $hash, [ @a[ 2 .. scalar(@a) - 1 ] ] ); }; + return I2C_MCP23017_Catch($@) if $@; + } + return undef; } ############################################################################### sub I2C_MCP23017_Init($$) { #Geraet beim anlegen/booten/nach Neuverbindung (wieder) initialisieren my ( $hash, $args ) = @_; if (defined $args && int(@$args) != 1) { - return "Define: Wrong syntax. Usage:\n" . - "define I2C_MCP23017 "; + return "Define: Wrong syntax. Usage:\n" . + "define I2C_MCP23017 "; } - if (defined (my $address = shift @$args)) { - $hash->{I2C_Address} = $address =~ /^0.*$/ ? oct($address) : $address; + if (defined (my $address = shift @$args)) { + $hash->{I2C_Address} = $address =~ /^0.*$/ ? oct($address) : $address; } else { - return "$hash->{NAME} I2C Address not valid"; + return "$hash->{NAME} I2C Address not valid"; } AssignIoPort($hash); my $msg = ''; - #Output level wieder setzen - my $sbyte = 0; - foreach (reverse 0..7) { + #Output level wieder setzen + my $sbyte = 0; + foreach (reverse 0..7) { $sbyte += $setsP{ReadingsVal($hash->{NAME},"PortA".$_,"off")} << ($_); #Werte fuer PortA aus dem Reading holen $sbyte += $setsP{ReadingsVal($hash->{NAME},"PortB".$_,"off")} << (8 + $_); - } - $msg = I2C_MCP23017_SetRegPair($hash, $sbyte, "GPIO") if $sbyte; + } + $msg = I2C_MCP23017_SetRegPair($hash, $sbyte, "GPIO") if $sbyte; #bei Init IC neu konfigurieren - if ( defined ( my $val = AttrVal($hash->{NAME},"invert_input",undef)) ) { + if ( defined ( my $val = AttrVal($hash->{NAME},"invert_input",undef)) ) { ($msg, my $regval) = I2C_MCP23017_CheckAttr($hash, "invert_input", $val); $msg = I2C_MCP23017_SetRegPair($hash, $regval, "IPOL") unless $msg; - } - if ( defined ( my $val = AttrVal($hash->{NAME},"OutputPorts",undef)) ) { + } + if ( defined ( my $val = AttrVal($hash->{NAME},"OutputPorts",undef)) ) { ($msg, my $regval) = I2C_MCP23017_CheckAttr($hash, "OutputPorts", $val); $msg = I2C_MCP23017_SetRegPair($hash, ~$regval, "IODIR") unless $msg; - } - if ( defined ( my $val = AttrVal($hash->{NAME},"Pullup",undef)) ) { + } + if ( defined ( my $val = AttrVal($hash->{NAME},"Pullup",undef)) ) { ($msg, my $regval) = I2C_MCP23017_CheckAttr($hash, "Pullup", $val); $msg = I2C_MCP23017_SetRegPair($hash, $regval, "GPPU") unless $msg; - } - if ( defined ( my $val = AttrVal($hash->{NAME},"Interrupt",undef)) ) { + } + if ( defined ( my $val = AttrVal($hash->{NAME},"Interrupt",undef)) ) { ($msg, my $regval) = I2C_MCP23017_CheckAttr($hash, "Interrupt", $val); $msg = I2C_MCP23017_SetRegPair($hash, $regval, "GPINTEN") unless $msg; - } + } if ( defined ( my $val = AttrVal($hash->{NAME},"InterruptOut",undef)) ) { my $regval = 0; $regval = $intout{$val} if defined $val; @@ -133,25 +129,25 @@ sub I2C_MCP23017_Init($$) { #Geraet beim anlegen/booten return "no IODev assigned to '$hash->{NAME}'"; } - } + } $hash->{STATE} = 'Initialized'; return ($msg) ? $msg : undef; } ############################################################################### sub I2C_MCP23017_Catch($) { #Fehlermeldung von eval formattieren - my $exception = shift; - if ($exception) { - $exception =~ /^(.*)( at.*FHEM.*)$/; - return $1; - } - return undef; + my $exception = shift; + if ($exception) { + $exception =~ /^(.*)( at.*FHEM.*)$/; + return $1; + } + return undef; } ############################################################################### sub I2C_MCP23017_Undefine($$) { - my ($hash, $arg) = @_; - if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) { - RemoveInternalTimer($hash); - } + my ($hash, $arg) = @_; + if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) { + RemoveInternalTimer($hash); + } } ############################################################################### sub I2C_MCP23017_Attr(@) { @@ -160,10 +156,10 @@ sub I2C_MCP23017_Attr(@) { my $msg = ''; if ($command && $command eq "set" && $attr && $attr eq "IODev") { if ($main::init_done and (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $val)) { - main::AssignIoPort($hash,$val); - my @def = split (' ',$hash->{DEF}); - I2C_MCP23017_Init($hash,\@def) if (defined ($hash->{IODev})); - } + main::AssignIoPort($hash,$val); + my @def = split (' ',$hash->{DEF}); + I2C_MCP23017_Init($hash,\@def) if (defined ($hash->{IODev})); + } } if ($attr && $attr eq 'poll_interval') { #my $pollInterval = (defined($val) && looks_like_number($val) && $val > 0) ? $val : 0; @@ -200,7 +196,7 @@ sub I2C_MCP23017_Attr(@) { $pair[0] =~ m/^(A|B)(0|)[0-7]$/i && $pair[1] =~ m/^(on|off|last)$/i); } - } + } } elsif ($attr && $attr eq "InterruptOut") { my $regval = 0; if (defined $val) { @@ -221,7 +217,7 @@ sub I2C_MCP23017_Attr(@) { return "no IODev assigned to '$hash->{NAME}'"; } } - return ($msg) ? $msg : undef; + return ($msg) ? $msg : undef; } ############################################################################### sub I2C_MCP23017_State($$$$) { #reload readings at FHEM start @@ -229,7 +225,7 @@ sub I2C_MCP23017_State($$$$) { #reload readings at FHEM s Log3 $hash, 4, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim"; if ($sname =~ m/^Port(A|B)(0|)[0-7]$/i) { my $po = substr $sname, 4, 2; # Ax oder Bx - Log3 $hash, 5, "$hash->{NAME}: Port = $po"; + Log3 $hash, 5, "$hash->{NAME}: Port = $po"; if ( index( AttrVal($hash->{NAME}, "OutputPorts", ""), $po, 0) >= 0 ) { if ( ( my $pos = index(AttrVal($hash->{NAME},"OnStartup", ""), $po ,0) ) >=0 ) { my $val = substr AttrVal($hash->{NAME},"OnStartup",undef), $pos + 3, 2; @@ -245,40 +241,40 @@ sub I2C_MCP23017_State($$$$) { #reload readings at FHEM s $hash->{READINGS}{$sname}{TIME} = $tim; } } else { - Log3 $hash, 5, "$hash->{NAME}: $sname wird auf Altzustand: $sval gesetzt (kein Eintrag in on Startup)"; - $hash->{READINGS}{$sname}{VAL} = $sval; - $hash->{READINGS}{$sname}{TIME} = $tim; - } - } else { + Log3 $hash, 5, "$hash->{NAME}: $sname wird auf Altzustand: $sval gesetzt (kein Eintrag in on Startup)"; + $hash->{READINGS}{$sname}{VAL} = $sval; + $hash->{READINGS}{$sname}{TIME} = $tim; + } + } else { Log3 $hash, 5, "$hash->{NAME}: $sname ist Eingang"; - } + } } - return undef; + return undef; } ############################################################################### sub I2C_MCP23017_CheckAttr { my ($hash, $attr, $val) = @_; my $msg = undef; my ($regval) = 0; - if (defined $val) { + if (defined $val) { foreach (split (/,/,$val)) { $msg = "wrong value: $_ for \"attr $hash->{NAME} $attr\" use comma separated values from A0 - A7 and/or B0 - B7" unless ($_ =~ m/^(A|B)(0|)[0-7]$/i); my $bank = ($_ =~ m/^A/) ? 0 : 8; # A oder B $_ =~ tr/[a-zA-Z]//d; #Nummer aus String extrahieren - $regval |= 1 << ($_ + $bank); + $regval |= 1 << ($_ + $bank); } - } + } return $msg, $regval; } ############################################################################### sub I2C_MCP23017_SetRegPair { #set register pair for PortA/B my ($hash, $regval, $regtype) = @_; - my %port = (); + my %port = (); $port{A} = $regval & 0xff; $port{B} = ( $regval >> 8 ) & 0xff; - if (defined (my $iodev = $hash->{IODev})) { - foreach my $reg (keys %port) { + if (defined (my $iodev = $hash->{IODev})) { + foreach my $reg (keys %port) { #Log3 $hash, 1, "schreibe raus: i2cwrite|$hash->{I2C_Address}|$Registers{$regtype . $reg}|$port{$reg}|"; CallFn($iodev->{NAME}, "I2CWrtFn", $iodev, { direction => "i2cwrite", @@ -286,35 +282,35 @@ sub I2C_MCP23017_SetRegPair { #set register pair for Por reg => $Registers{$regtype . $reg}, data => $port{$reg}, }) if (defined $hash->{I2C_Address}); - } + } } else { return "no IODev assigned to '$hash->{NAME}'"; } } ############################################################################### sub I2C_MCP23017_Poll($) { #function for refresh intervall - my ($hash) = @_; - my $name = $hash->{NAME}; - # Read values - I2C_MCP23017_Get($hash, $name); - my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0); - if ($pollInterval > 0) { - InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_MCP23017_Poll', $hash, 0); - } + my ($hash) = @_; + my $name = $hash->{NAME}; + # Read values + I2C_MCP23017_Get($hash, $name); + my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0); + if ($pollInterval > 0) { + InternalTimer(gettimeofday() + ($pollInterval * 60), 'I2C_MCP23017_Poll', $hash, 0); + } } ############################################################################### sub I2C_MCP23017_Set($@) { - my ($hash, @a) = @_; - my $name =$a[0]; - my $cmd = $a[1]; - my $val = $a[2]; - my @outports = sort(split(/,/,AttrVal($name, "OutputPorts", ""))); - unless (@a == 3) { + my ($hash, @a) = @_; + my $name =$a[0]; + my $cmd = $a[1]; + my $val = $a[2]; + my @outports = sort(split(/,/,AttrVal($name, "OutputPorts", ""))); + unless (@a == 3) { - } + } my $msg = undef; if ( $cmd && $cmd =~ m/^P(ort|)(A|B)((0|)[0-7])(,(P|)(ort|)(A|B)((0|)[0-7])){0,7}$/i) { - return "wrong value: $val for \"set $name $cmd\" use one of: " . + return "wrong value: $val for \"set $name $cmd\" use one of: " . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) unless(exists($setsP{$val})); my @scmd = split(",", $cmd); @@ -336,19 +332,19 @@ sub I2C_MCP23017_Set($@) { } } } - #Log3 $hash, 1, "$name: endwert: $regval"; + #Log3 $hash, 1, "$name: endwert: $regval"; $msg = I2C_MCP23017_SetRegPair($hash, $regval, "GPIO") unless $msg; } else { - my $list = ""; - foreach (0..7) { - next unless ( ("A" . $_) ~~ @outports ); #Inputs überspringen - $list .= "PortA" . $_ . ":" . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " "; - } + my $list = ""; foreach (0..7) { - next unless ( ("B" . $_) ~~ @outports ); #Inputs überspringen + next unless ( ("A" . $_) ~~ @outports ); #Inputs ueberspringen + $list .= "PortA" . $_ . ":" . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " "; + } + foreach (0..7) { + next unless ( ("B" . $_) ~~ @outports ); #Inputs ueberspringen $list .= "PortB" . $_ . ":" . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " "; - } - $msg = "Unknown argument $a[1], choose one of " . $list; + } + $msg = "Unknown argument $a[1], choose one of " . $list; } return ($msg) ? $msg : undef; @@ -360,9 +356,9 @@ sub I2C_MCP23017_Set($@) { # join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) # unless(exists($setsP{$val})); # my $po = substr $cmd, 4, 1; # A oder B -# my $regaddr = $po eq "A" ? $Registers{GPIOA} : $Registers{GPIOB}; #Adresse für GPIO Register +# my $regaddr = $po eq "A" ? $Registers{GPIOA} : $Registers{GPIOB}; #Adresse fuer GPIO Register # substr($cmd,0,5,""); -# return "$name error: Port$po$cmd is defined as input" unless ( ($po . $cmd) ~~ @outports ); #Prüfen ob entsprechender Port Input ist +# return "$name error: Port$po$cmd is defined as input" unless ( ($po . $cmd) ~~ @outports ); #Pruefen ob entsprechender Port Input ist # # my $sbyte = 0; # foreach (reverse 0..7) { @@ -379,11 +375,11 @@ sub I2C_MCP23017_Set($@) { # } else { # my $list = ""; # foreach (0..7) { -# next unless ( ("A" . $_) ~~ @outports ); #Inputs überspringen +# next unless ( ("A" . $_) ~~ @outports ); #Inputs ueberspringen # $list .= "PortA" . $_ . ":" . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " "; # } # foreach (0..7) { -# next unless ( ("B" . $_) ~~ @outports ); #Inputs überspringen +# next unless ( ("B" . $_) ~~ @outports ); #Inputs ueberspringen # $list .= "PortB" . $_ . ":" . join(',', (sort { $setsP{ $a } <=> $setsP{ $b } } keys %setsP) ) . " "; # } # return "Unknown argument $a[1], choose one of " . $list; @@ -396,38 +392,38 @@ sub I2C_MCP23017_Set($@) { } ############################################################################### sub I2C_MCP23017_Get($@) { - my ($hash, @a) = @_; - my $name =$a[0]; + my ($hash, @a) = @_; + my $name =$a[0]; my %sendpackage = ( i2caddress => $hash->{I2C_Address}, direction => "i2cread" ); $sendpackage{reg} = 18; #startadresse zum lesen $sendpackage{nbyte} = 2; return "$name: no IO device defined" unless ($hash->{IODev}); my $phash = $hash->{IODev}; - my $pname = $phash->{NAME}; + my $pname = $phash->{NAME}; CallFn($pname, "I2CWrtFn", $phash, \%sendpackage); } ############################################################################### sub I2C_MCP23017_I2CRec($@) { #ueber CallFn vom physical aufgerufen my ($hash, $clientmsg) = @_; - my $name = $hash->{NAME}; - my $phash = $hash->{IODev}; - my $pname = $phash->{NAME}; - while ( my ( $k, $v ) = each %$clientmsg ) { #erzeugen von Internals für alle Keys in $clientmsg die mit dem physical Namen beginnen - $hash->{$k} = $v if $k =~ /^$pname/ ; - } - #hier noch überprüfen, ob Register und Daten ok - if ($clientmsg->{direction} && defined $clientmsg->{reg} && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok" ) { + my $name = $hash->{NAME}; + my $phash = $hash->{IODev}; + my $pname = $phash->{NAME}; + while ( my ( $k, $v ) = each %$clientmsg ) { #erzeugen von Internals fuer alle Keys in $clientmsg die mit dem physical Namen beginnen + $hash->{$k} = $v if $k =~ /^$pname/ ; + } + #hier noch ueberpruefen, ob Register und Daten ok + if ($clientmsg->{direction} && defined $clientmsg->{reg} && $clientmsg->{$pname . "_SENDSTAT"} && $clientmsg->{$pname . "_SENDSTAT"} eq "Ok" ) { if ($clientmsg->{direction} eq "i2cread" && $clientmsg->{received}) { # =~ m/^[a-f0-9]{2}$/i) { - #my @rec = @{$clientmsg->{received}}; #bei übergabe im hash als array - my @rec = split(" ",$clientmsg->{received}); #bei übergabe im als skalar + #my @rec = @{$clientmsg->{received}}; #bei uebergabe im hash als array + my @rec = split(" ",$clientmsg->{received}); #bei uebergabe im als skalar Log3 $hash, 3, "$name: wrong amount of registers transmitted from $pname" unless (@rec == $clientmsg->{nbyte}); foreach (reverse 0..$#rec) { #reverse, damit Inputs (Register 0 und 1 als letztes geschrieben werden) I2C_MCP23017_UpdReadings($hash, $_ + $clientmsg->{reg} , $rec[$_]); } readingsSingleUpdate($hash,"state", "Ok", 1); - } elsif ($clientmsg->{direction} eq "i2cwrite" && defined $clientmsg->{data}) { # =~ m/^[a-f0-9]{2}$/i) {#readings aktualisieren wenn Übertragung ok + } elsif ($clientmsg->{direction} eq "i2cwrite" && defined $clientmsg->{data}) { # =~ m/^[a-f0-9]{2}$/i) {#readings aktualisieren wenn uebertragung ok I2C_MCP23017_UpdReadings($hash, $clientmsg->{reg} , $clientmsg->{data}) if ( ($clientmsg->{reg} == $Registers{GPIOA}) || ($clientmsg->{reg} == $Registers{GPIOB}) ); readingsSingleUpdate($hash,"state", "Ok", 1); @@ -440,7 +436,7 @@ sub I2C_MCP23017_I2CRec($@) { #ueber CallFn vom physical (defined($clientmsg->{data}) ? " Data: " . sprintf("0x%.2X", $clientmsg->{data}) : " Data: undef"). (defined($clientmsg->{received}) ? " received: " . sprintf("0x%.2X", $clientmsg->{received}) : " received: undef"); } - } else { + } else { readingsSingleUpdate($hash,"state", "transmission error", 1); Log3 $hash, 3, "$name: failure in message from $pname"; Log3 $hash, 3,(defined($clientmsg->{direction}) ? "Direction: " . $clientmsg->{direction} : "Direction: undef"). @@ -463,17 +459,17 @@ sub I2C_MCP23017_UpdReadings($$$) { #nach Rueckmeldung read readingsBeginUpdate($hash); if ($reg == $Registers{GPIOA}) { my %rsetsP = reverse %setsP; - foreach (0..7) { - my $pval = 1 & ( $inh >> $_ ); + foreach (0..7) { + my $pval = 1 & ( $inh >> $_ ); readingsBulkUpdate($hash, 'PortA'.$_ , $rsetsP{$pval}) - if (ReadingsVal($name, 'PortA'.$_,"nix") ne $rsetsP{$pval}); #nur wenn Wert geändert + if (ReadingsVal($name, 'PortA'.$_,"nix") ne $rsetsP{$pval}); #nur wenn Wert geaendert } } elsif ($reg == $Registers{GPIOB}) { my %rsetsP = reverse %setsP; - foreach (0..7) { - my $pval = 1 & ( $inh >> $_ ); + foreach (0..7) { + my $pval = 1 & ( $inh >> $_ ); readingsBulkUpdate($hash, 'PortB'.$_ , $rsetsP{$pval}) - if (ReadingsVal($name, 'PortB'.$_,"nix") ne $rsetsP{$pval}); #nur wenn Wert geändert + if (ReadingsVal($name, 'PortB'.$_,"nix") ne $rsetsP{$pval}); #nur wenn Wert geaendert } } @@ -492,7 +488,7 @@ sub I2C_MCP23017_UpdReadings($$$) { #nach Rueckmeldung read Provides an interface to the MCP23017 16 channel port extender IC. On Raspberry Pi the Interrupt Pin's can be connected to an GPIO and RPI_GPIO can be used to get the port values if an interrupt occurs.
The I2C messages are send through an I2C interface module like RPII2C, FRM or NetzerI2C so this device must be defined first.
- attribute IODev must be set
+ attribute IODev must be set

Define
    @@ -660,7 +656,7 @@ sub I2C_MCP23017_UpdReadings($$$) { #nach Rueckmeldung read Standard: -, gültige Werte: A0-A7, B0-B7

  • Interrupt
    - Durch Komma getrennte Input Ports, die einen Interrupt auf IntA/B auslösen.
    + Durch Komma getrennte Input Ports, die einen Interrupt auf IntA/B auslösen.
    Standard: -, gültige Werte: A0-A7, B0-B7

  • invert_input
    @@ -702,4 +698,4 @@ sub I2C_MCP23017_UpdReadings($$$) { #nach Rueckmeldung read =end html_DE -=cut +=cut \ No newline at end of file