############################################## # $Id$ package main; use strict; use warnings; use Time::HiRes qw(gettimeofday); #use Device::SMBus; #my $clientsI2C = ":I2C_PC.*:I2C_SHT21:I2C_MCP23017:I2C_BMP180:"; my @clients = qw( I2C_LCD I2C_DS1307 I2C_PC.* I2C_MCP23017 I2C_BMP180 I2C_SHT21 I2C_TSL2561 ); my $gpioprg = "/usr/local/bin/gpio"; #WiringPi GPIO utility my $I2C_SLAVE = 0x0703; #Variable for IOCTL (set I2C slave address) #my %matchListI2C = ( #kann noch weg? # "1:I2C_PCF8574"=> ".*", # "2:FHT" => "^81..(04|09|0d)..(0909a001|83098301|c409c401)..", #); my $libcheck_SMBus = 1; my $check_ioctl_ph = 1; sub RPII2C_Initialize($) { my ($hash) = @_; eval "use Device::SMBus;"; $libcheck_SMBus = 0 if($@); eval {require "sys/ioctl.ph"}; $check_ioctl_ph = 0 if($@); # Provider $hash->{Clients} = join (':',@clients); #$hash->{WriteFn} = "RPII2C_Write"; #wird vom client per IOWrite($@) aufgerufen $hash->{I2CWrtFn} = "RPII2C_Write"; #zum testen als alternative fuer IOWrite # Normal devices $hash->{DefFn} = "RPII2C_Define"; $hash->{UndefFn} = "RPII2C_Undef"; $hash->{GetFn} = "RPII2C_Get"; $hash->{SetFn} = "RPII2C_Set"; $hash->{AttrFn} = "RPII2C_Attr"; $hash->{NotifyFn} = "RPII2C_Notify"; $hash->{AttrList}= "do_not_notify:1,0 ignore:1,0 showtime:1,0 " . "$readingFnAttributes"; $hash->{AttrList} .= " useHWLib:IOCTL,SMBus " if( $libcheck_SMBus && $check_ioctl_ph); $hash->{AttrList} .= " swap_i2c0:off,on"; } ##################################### sub RPII2C_Define($$) { # my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); unless(@a == 3) { my $msg = "wrong syntax: define RPII2C <0|1>"; Log3 undef, 2, $msg; return $msg; } $hash->{SMBus_exists} = $libcheck_SMBus if($libcheck_SMBus); $hash->{ioctl_ph_exists} = $check_ioctl_ph if($check_ioctl_ph); my $name = $a[0]; my $dev = $a[2]; if ($check_ioctl_ph) { $hash->{hwfn} = \&RPII2C_HWACCESS_ioctl; } elsif ($libcheck_SMBus) { $hash->{hwfn} = \&RPII2C_HWACCESS; } else { return $name . ": Error! no library for Hardware access installed"; } my $device = "/dev/i2c-".$dev; if ( RPII2C_CHECK_GPIO_DEVICE($device) ) { Log3 $hash, 1, "file $device not accessible try to use gpio utility to fix it"; if ( defined(my $ret = RPII2C_CHECK_GPIO_UTIL($gpioprg)) ) { Log3 $hash, 1, $ret if $ret; } else { #I2C Devices mit gpio utility fuer FHEM User lesbar machen my $exp = $gpioprg.' load i2c'; $exp = `$exp`; } } $hash->{NOTIFYDEV} = "global"; #$hash->{Clients} = $clientsI2C; #$hash->{MatchList} = \%matchListI2C; if($dev eq "none") { Log3 $name, 1, "$name device is none, commands will be echoed only"; $attr{$name}{dummy} = 1; return undef; } my $check = RPII2C_CHECK_GPIO_DEVICE($device); return $name . $check if $check; $hash->{DeviceName} = $device; $hash->{STATE} = "initialized"; return undef; } ##################################### sub RPII2C_Notify { # my ($hash,$dev) = @_; my $name = $hash->{NAME}; my $type = $hash->{TYPE}; if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) { RPII2C_forall_clients($hash,\&RPII2C_Init_Client,undef);; } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) { } } ##################################### sub RPII2C_forall_clients($$$) { # my ($hash,$fn,$args) = @_; foreach my $d ( sort keys %main::defs ) { if ( defined( $main::defs{$d} ) && defined( $main::defs{$d}{IODev} ) && $main::defs{$d}{IODev} == $hash ) { &$fn($main::defs{$d},$args); } } return undef; } ##################################### sub RPII2C_Init_Client($@) { # my ($hash,$args) = @_; if (!defined $args and defined $hash->{DEF}) { my @a = split("[ \t][ \t]*", $hash->{DEF}); $args = \@a; } my $name = $hash->{NAME}; Log3 $name,5,"im init client fuer $name "; my $ret = CallFn($name,"InitFn",$hash,$args); if ($ret) { Log3 $name,2,"error initializing '".$hash->{NAME}."': ".$ret; } } ##################################### sub RPII2C_Undef($$) { # my ($hash, $arg) = @_; my $name = $hash->{NAME}; foreach my $d (sort keys %defs) { if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) { Log3 $name, 3, "deleting port for $d"; delete $defs{$d}{IODev}; } } return undef; } ##################################### sub RPII2C_Attr(@){ my (undef, $name, $attr, $val) = @_; my $hash = $defs{$name}; if ($attr && $attr eq 'useHWLib') { $hash->{hwfn} = \&RPII2C_HWACCESS_ioctl if $val eq "IOCTL"; $hash->{hwfn} = \&RPII2C_HWACCESS if $val eq "SMBus"; } elsif ($attr && $attr eq 'swap_i2c0' && defined($val)) { RPII2C_SWAPI2C0($hash,$val); } return undef; } ##################################### sub RPII2C_Set($@) { #writeBlock noch nicht fertig my ($hash, @a) = @_; my $name = shift @a; my $type = shift @a; my @sets = ('writeByte', 'writeByteReg', 'writeBlock'); #, 'writeNBlock'); return "Unknown argument $type, choose one of " . join(" ", @sets) if @a < 2; foreach (@a) { #Hexwerte pruefen und in Dezimalwerte wandeln return "$name: $_ is no 1byte hexadecimal value" if $_ !~ /^(0x|)[0-9A-F]{1,2}$/xi ; $_ = hex; } my $i2ca = shift @a; return "$name: I2C Address not valid" unless ($i2ca > 3 && $i2ca < 128); #pruefe auf Hexzahl zwischen 4 und 7F my $i2chash = { i2caddress => $i2ca, direction => "i2cwrite" }; my ($reg, $nbyte, $data) = undef; if ($type eq "writeByte") { $data = join(" ", @a); } elsif ($type eq "writeByteReg") { $reg = shift @a; $data = join(" ", @a); } elsif ($type eq "writeBlock") { $reg = shift @a; $nbyte = int(@a); return "$name maximal blocksize (32byte) exeeded" if $nbyte > 32; $data = join(" ", @a); $i2chash->{direction} = "i2cblockwrite"; #####kommt weg da sinnlos??!!! Achtung $nbyte stimmt derzeit nicht # } elsif ($type eq "writeNBlock") { # $reg = shift @a; # return "$name register address must be a hexvalue" if (!defined($reg) || $reg !~ /^(0x|)[0-9A-F]{1,4}$/xi); # $nbyte = shift @a; # return "$name number of bytes must be decimal value" if (!defined($nbyte) || $nbyte !~ /^[0-9]{1,2}$/); # return "$name data values must be n times number of bytes" if (int(@a) % $nbyte != 0); # $data = join(" ", @a); ######################################################################### }else { return "Unknown argument $type, choose one of " . join(" ", @sets); } $i2chash->{reg} = $reg if defined($reg); #startadresse zum lesen $i2chash->{nbyte} = $nbyte if defined($nbyte); $i2chash->{data} = $data if defined($data); &{$hash->{hwfn}}($hash, $i2chash); undef $i2chash; #Hash loeschen return undef; } ##################################### fertig? sub RPII2C_Get($@) { # my ($hash, @a) = @_; my $nargs = int(@a); my $name = $hash->{NAME}; my @gets = ('read'); unless ( exists($a[1]) && $a[1] ne "?" && grep {/^$a[1]$/} @gets ) { return "Unknown argument $a[1], choose one of " . join(" ", @gets); } if ($a[1] eq "read") { return "use: \"get $name $a[1] [ []]\"" if(@a < 3); return "$name: I2C Address not valid" unless ( $a[2] =~ /^(0x|)([0-7]|)[0-9A-F]$/xi); return "$name register address must be a hexvalue" if (defined($a[3]) && $a[3] !~ /^(0x|)[0-9A-F]{1,4}$/xi); return "$name number of bytes must be decimal value" if (defined($a[4]) && $a[4] !~ /^[0-9]{1,2}$/); my $i2chash = { i2caddress => hex($a[2]), direction => "i2cread" }; $i2chash->{reg} = hex($a[3]) if defined($a[3]); #startadresse zum lesen $i2chash->{nbyte} = $a[4] if defined($a[4]); #Log3 $hash, 1, "Reg: ". $i2chash->{reg}; #my $status = RPII2C_HWACCESS_ioctl($hash, $i2chash); my $status = &{$hash->{hwfn}}($hash, $i2chash); #my $received = join(" ", @{$i2chash->{received}}); #als Array my $received = $i2chash->{received}; #als Scalar undef $i2chash; #Hash loeschen return (defined($received) ? "received : " . $received ." | " : "" ) . " transmission: $status"; } return undef; } ##################################### sub RPII2C_Write($$) { #wird vom Client aufgerufen my ($hash, $clientmsg) = @_; my $name = $hash->{NAME}; my $ankommen = "$name: vom client empfangen"; foreach my $av (keys %{$clientmsg}) { $ankommen .= "|" . $av . ": " . $clientmsg->{$av}; } Log3 $hash, 5, $ankommen; if ( $clientmsg->{direction} && $clientmsg->{i2caddress} ) { $clientmsg->{$name . "_" . "SENDSTAT"} = &{$hash->{hwfn}}($hash, $clientmsg); #$clientmsg->{$name . "_" . "SENDSTAT"} = RPII2C_HWACCESS($hash, $clientmsg); } foreach my $d ( sort keys %main::defs ) { #zur Botschaft passenden Clienten ermitteln geht auf Client: I2CRecFn #Log3 $hash, 1, "d: $d". ($main::defs{$d}{IODev}? ", IODev: $main::defs{$d}{IODev}":"") . ($main::defs{$d}{I2C_Address} ? ", I2C: $main::defs{$d}{I2C_Address}":"") . ($clientmsg->{i2caddress} ? " CI2C: $clientmsg->{i2caddress}" : ""); if ( defined( $main::defs{$d} ) && defined( $main::defs{$d}{IODev} ) && $main::defs{$d}{IODev} == $hash && defined( $main::defs{$d}{I2C_Address} ) && defined($clientmsg->{i2caddress}) && $main::defs{$d}{I2C_Address} eq $clientmsg->{i2caddress} ) { my $chash = $main::defs{$d}; Log3 $hash, 5, "$name ->Client gefunden: $d". ($main::defs{$d}{I2C_Address} ? ", I2Caddress: $main::defs{$d}{I2C_Address}":"") . ($clientmsg->{data} ? " Data: $clientmsg->{data}" : ""); CallFn($d, "I2CRecFn", $chash, $clientmsg); undef $clientmsg #Hash loeschen nachdem Daten verteilt wurden } } return undef; } ##################################### #FRM_forall_clients($$$) #{ # my ($hash,$fn,$args) = @_; # foreach my $d ( sort keys %main::defs ) { # if ( defined( $main::defs{$d} ) # && defined( $main::defs{$d}{IODev} ) # && $main::defs{$d}{IODev} == $hash ) { # &$fn($main::defs{$d},$args); #funktion mit Varianblennamen von $fn ausfuehren # } # } # return undef; #} ##################################### sub RPII2C_CHECK_GPIO_DEVICE { my ($dev) = @_; my $ret = undef; #unless (defined($hash->{gpio_util_exists})) { if(-e $dev) { if(-r $dev) { unless(-w $dev) { $ret = ': Error! I2C device not writable: '.$dev . '. Please install wiringpi or change access rights for fhem user'; } } else { $ret = ': Error! I2C device not readable: '.$dev . '. Please install wiringpi or change access rights for fhem user'; } } else { $ret = ': Error! I2C device not found: ' .$dev . '. Please check kernelmodules must loaded: i2c_bcm2708, i2c_dev'; } return $ret; } sub RPII2C_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 { $ret = "file $gpioprg is not executable"; } } else { $ret = "file $gpioprg doesnt exist"; } return $ret; } sub RPII2C_SWAPI2C0 { my ($hash,$set) = @_; unless (defined(my $ret = RPII2C_CHECK_GPIO_UTIL($gpioprg))) { if (defined($set) && $set eq "on") { system "$gpioprg -g mode 0 in"; system "$gpioprg -g mode 1 in"; system "$gpioprg -g mode 28 ALT0"; system "$gpioprg -g mode 29 ALT0"; } else { system "$gpioprg -g mode 28 in"; system "$gpioprg -g mode 29 in"; system "$gpioprg -g mode 0 ALT0"; system "$gpioprg -g mode 1 ALT0"; } } else { Log3 $hash, 1, $ret if $ret; } return } sub RPII2C_HWACCESS($$) { my ($hash, $clientmsg) = @_; my $status = "error"; my $inh = undef; Log3 $hash, 5, "$hash->{NAME}: HWaccess I2CAddr: " . sprintf("0x%.2X", $clientmsg->{i2caddress}); my $dev = Device::SMBus->new( I2CBusDevicePath => $hash->{DeviceName}, I2CDeviceAddress => hex( sprintf("%.2X", $clientmsg->{i2caddress}) ), ); if (defined($clientmsg->{nbyte}) && defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cblockwrite") { #Registerblock beschreiben my @data = split(" ", $clientmsg->{data}); my $dataref = \@data; $inh = $dev->writeBlockData( $clientmsg->{reg} , $dataref ); my $wr = join(" ", @{$dataref}); Log3 $hash, 5, "$hash->{NAME}: Block schreiben Register: " . sprintf("0x%.2X", $clientmsg->{reg}) . " Inhalt: " . $wr . " N: ". int(@data) ." Returnvar.: $inh"; $status = "Ok" if $inh == 0; #kommt wieder weg################# # } elsif (defined($clientmsg->{nbyte}) && defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #Registerbereich (mehrfach) beschreiben # my @data = split(" ", $clientmsg->{data}); # foreach (0..$#data) { # my $i = $_ -( int($_ / $clientmsg->{nbyte}) * $clientmsg->{nbyte} ); # $inh = $dev->writeByteData( ($clientmsg->{reg} + $i ) ,$data[$_]); # Log3 $hash, 5, "$hash->{NAME} NReg schreiben; Reg: " . ($clientmsg->{reg} + $i) . " Inh: " . $data[$_] . " Returnvar.: $inh"; # last if $inh != 0; # $status = "Ok" if $inh == 0; # } #hier Mehrfachbeschreibung eines Registers noch entfernen und dafuer Bereich mit Registeroperationen beschreiben } elsif (defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #Register beschreiben my @data = split(" ", $clientmsg->{data}); foreach (@data) { $inh = $dev->writeByteData($clientmsg->{reg},$_); Log3 $hash, 5, "$hash->{NAME}; Register ".sprintf("0x%.2X", $clientmsg->{reg})." schreiben - Inhalt: " .sprintf("0x%.2X",$_) . " Returnvar.: $inh"; last if $inh != 0; $status = "Ok" if $inh == 0; } } elsif (defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #Byte(s) schreiben my @data = split(" ", $clientmsg->{data}); foreach (@data) { $inh = $dev->writeByte($_); Log3 $hash, 5, "$hash->{NAME} Byte schreiben; Inh: " . $_ . " Returnvar.: $inh"; last if $inh != 0; $status = "Ok" if $inh == 0; } } elsif (defined($clientmsg->{reg}) && $clientmsg->{direction} eq "i2cread") { #Register lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; for (my $n = 0; $n < $nbyte; $n++) { $inh = $dev->readByteData($clientmsg->{reg} + $n ); Log3 $hash, 5, "$hash->{NAME}; Register ".sprintf("0x%.2X", $clientmsg->{reg} + $n )." lesen - Inhalt: ".sprintf("0x%.2X",$inh); last if ($inh < 0); #$rmsg .= sprintf("%.2X",$inh); $rmsg .= $inh; $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } #@{$clientmsg->{received}} = split(" ", $rmsg) if($rmsg); #Daten als Array uebertragen $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } elsif ($clientmsg->{direction} eq "i2cread") { #Byte lesen #Byte lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; for (my $n = 0; $n < $nbyte; $n++) { $inh = $dev->readByte(); Log3 $hash, 5, "$hash->{NAME} Byte lesen; Returnvar.: $inh"; last if ($inh < 0); $rmsg .= $inh; $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } #@{$clientmsg->{received}} = split(" ", $rmsg) if($rmsg); #Daten als Array uebertragen $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } $hash->{STATE} = $status; $hash->{ERRORCNT} = defined($hash->{ERRORCNT}) ? $hash->{ERRORCNT} += 1 : 1 if $status ne "Ok"; $clientmsg->{$hash->{NAME} . "_" . "RAWMSG"} = $inh; return $status; } ##################### sub RPII2C_HWACCESS_ioctl($$) { my ($hash, $clientmsg) = @_; my $status = "error"; Log3 $hash, 5, "$hash->{NAME}: HWaccess I2CAddr: " . sprintf("0x%.2X", $clientmsg->{i2caddress}); my ($fh, $msg) = undef; my $ankommen = "$hash->{NAME}: vom client empfangen"; foreach my $av (keys %{$clientmsg}) { $ankommen .= "|" . $av . ": " . $clientmsg->{$av}; } Log3 $hash, 5, $ankommen; my $i2caddr = hex(sprintf "%x", $clientmsg->{i2caddress}); if ( sysopen(my $fh, $hash->{DeviceName}, O_RDWR) != 1) { #Datei oeffnen Log3 $hash, 1, "$hash->{NAME}: HWaccess sysopen failure: $!" } elsif( not defined( ioctl($fh,$I2C_SLAVE,$i2caddr) ) ) { #I2C Adresse per ioctl setzen Log3 $hash, 1, "$hash->{NAME}: HWaccess (0x".unpack( "H2",pack "C", $clientmsg->{i2caddress}).") ioctl failure: $!" } elsif (defined($clientmsg->{nbyte}) && defined($clientmsg->{reg}) && defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cblockwrite") { #Registerblock beschreiben my $data = chr($clientmsg->{reg}); foreach (split(" ", $clientmsg->{data})) { $data .= chr($_); } my $retval = syswrite($fh, $data, length($data)); unless (defined($retval) && $retval == length($data)) { Log3 $hash, 1, "$hash->{NAME}: HWaccess blockweise nach 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." schreiben, Reg: 0x". unpack( "H2",pack "C", $clientmsg->{reg}) . " Inh: $clientmsg->{data}, laenge: ".length($data)."| -> syswrite failure: $!"; } else { $status = "Ok"; Log3 $hash, 5, "$hash->{NAME}: HWaccess block schreiben, Reg: 0x". unpack( "H2",pack "C", $clientmsg->{reg}) . " Inh(dec):|$clientmsg->{data}|, laenge: |".length($data)."|"; } #(my $datah = $data) =~ s/(.|\n)/sprintf("%.2X ",ord($1))/eg; #Log3 $hash, 1, "$hash->{NAME}: HWaccess block schreiben data:|$clientmsg->{data}|, laenge: |".length($data)."|"; #$status = "Ok" if $resulw == length($data); } elsif (defined($clientmsg->{data}) && $clientmsg->{direction} eq "i2cwrite") { #byteweise beschreiben my $reg = undef; $reg = $clientmsg->{reg} if (defined($clientmsg->{reg})); $status = "Ok"; foreach (split(" ", $clientmsg->{data})) { my $data = (defined($reg) ? chr($reg++) : "") . chr($_); my $retval = syswrite($fh, $data, length($data)); unless (defined($retval) && $retval == length($data)) { Log3 $hash, 1, "$hash->{NAME}: HWaccess byteweise nach 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." schreiben, ". (defined($reg) ? "Reg: 0x". unpack( "H2",pack "C", ($reg - 1)) . " " : "")."Inh: 0x" . unpack( "H2",pack "C", $_) .", laenge: ".length($data)."| -> syswrite failure: $!"; $status = "error"; last; } Log3 $hash, 5, "$hash->{NAME}: HWaccess byteweise schreiben, ". (defined($reg) ? "Reg: 0x". unpack( "H2",pack "C", ($reg - 1)) . " " : "")."Inh: 0x" . unpack( "H2",pack "C", $_) .", laenge: ".length($data); } } elsif ($clientmsg->{direction} eq "i2cread") { #vom I2C lesen my $nbyte = defined($clientmsg->{nbyte}) ? $clientmsg->{nbyte} : 1; my $rmsg = ""; foreach (my $n = 0; $n < $nbyte; $n++) { if ( defined($clientmsg->{reg}) ) { Log3 $hash, 5, "$hash->{NAME}: HWaccess byteweise lesen setze Registerpointer auf " . ($clientmsg->{reg} + $n); my $retval = syswrite($fh, chr($clientmsg->{reg} + $n), 1); unless (defined($retval) && $retval == 1) { Log3 $hash, 1, "$hash->{NAME}: HWaccess byteweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg} + $n)) : "") . " -> syswrite failure: $!" if $!; last; } } my $buf = undef; my $retval = sysread($fh, $buf, 1); unless (defined($retval) && $retval == 1) { Log3 $hash, 1, "$hash->{NAME}: HWaccess byteweise von 0x".unpack( "H2",pack "C", $clientmsg->{i2caddress})." lesen,". (defined($clientmsg->{reg}) ? " Reg: 0x". unpack( "H2",pack "C", ($clientmsg->{reg} + $n)) : "") . " -> sysread failure: $!" if $!; last; } $rmsg .= ord($buf); $rmsg .= " " if $n <= $nbyte; $status = "Ok" if ($n + 1) == $nbyte; } $clientmsg->{received} = $rmsg if($rmsg); #Daten als Scalar uebertragen } $hash->{STATE} = $status; $hash->{ERRORCNT} = defined($hash->{ERRORCNT}) ? $hash->{ERRORCNT} += 1 : 1 if $status ne "Ok"; #$clientmsg->{$hash->{NAME} . "_" . "RAWMSG"} = $inh; return $status; } =pod =begin html

RPII2C

    Provides access to Raspberry Pi's I2C interfaces for some logical modules and also directly.
    This modul will basically work on every linux system that provides /dev/i2c-x.

    preliminary:
    • Access rights for /dev/i2c-* devices
      • Add following lines into /etc/init.d/fhem before perl fhem.pl line in start or into /etc/rc.local:
        sudo chown fhem /dev/i2c-*
        sudo chgrp dialout /dev/i2c-*
        sudo chmod +t /dev/i2c-*
        sudo chmod 660 /dev/i2c-*
      • Alternatively for Raspberry Pi you can install the gpio utility from WiringPi library change access rights of I2C-Interface
        WiringPi installation is described here: RPI_GPIO.
        gpio utility will be automaticly used, if installed.
    • installation of i2c dependencies:
      sudo apt-get install libi2c-dev i2c-tools build-essential
    • load I2C kernel modules:
      open /etc/modules
      sudo nano /etc/modules
      add theese lines
      i2c-dev
      i2c-bcm2708
    • Optional, access via IOCTL will be used if Device::SMBus is not present.
      To access the I2C-Bus via the Device::SMBus module, following steps are necessary:
      sudo apt-get install libmoose-perl
      sudo cpan Device::SMBus


    Define
      define <name> RPII2C <I2C Bus Number>
      where <I2C Bus Number> is the number of the I2C bus that should be used (0 or 1)

    Set
    • Write one byte (or more bytes sequentially) directly to an I2C device (for devices that have only one register to write):
      set <name> writeByte <I2C Address> <value>

    • Write n-bytes to an register range (as an series of single register write operations), beginning at the specified register:
      set <name> writeByteReg <I2C Address> <Register Address> <value>

    • Write n-bytes to an register range (as an block write operation), beginning at the specified register:
      set <name> writeBlock <I2C Address> <Register Address> <value>


    • Examples:
        Write 0xAA to device with I2C address 0x60
        set test1 writeByte 60 AA
        Write 0xAA to register 0x01 of device with I2C address 0x6E
        set test1 writeByteReg 6E 01 AA
        Write 0xAA to register 0x01 of device with I2C address 0x6E, after it write 0x55 to 0x02 as two separate commands
        set test1 writeByteReg 6E 01 AA 55
        Write 0xA4 to register 0x03, 0x00 to register 0x04 and 0xDA to register 0x05 of device with I2C address 0x60 as an block command
        set test1 writeBlock 60 03 A4 00 DA

    Get
      get <name> read <I2C Address> [<Register Address> [<number of registers>]]
      gets value of I2C device's registers

      Examples:
        Reads byte from device with I2C address 0x60
        get test1 writeByte 60
        Reads register 0x01 of device with I2C address 0x6E.
        get test1 read 6E 01 AA 55
        Reads register 0x03 to 0x06 of device with I2C address 0x60.
        get test1 read 60 03 4


    Attributes
    • swap_i2c0
      Swap Raspberry Pi's I2C-0 from J5 to P5 rev. B
      This attribute is for Raspberry Pi only and needs gpio utility from WiringPi library.
      Default: none, valid values: on, off

    • useHWLib
      Change hardware access method.
      Attribute exists only if both access methods are usable
      Default: IOCTL, valid values: IOCTL, SMBus

    • ignore
    • do_not_notify
    • showtime

=end html =begin html_DE

RPII2C

    Ermöglicht den Zugriff auf die I2C Schnittstellen des Raspberry Pi über logische Module. Register von I2C IC's können auch direkt gelesen und geschrieben werden.

    Dieses Modul funktioniert grunsätzlich auf allen Linux Systemen, die /dev/i2c-x bereitstellen.

    Vorbereitung:
      • Folgende Zeilen müssen der Datei /etc/init.d/fhem vor perl fhem.pl in start hinzu, oder in die Datei /etc/rc.local eingefügt werden:
        sudo chown fhem /dev/i2c-*
        sudo chgrp dialout /dev/i2c-*
        sudo chmod +t /dev/i2c-*
        sudo chmod 660 /dev/i2c-*
      • Für das Raspberry Pi kann alternativ das gpio Utility der WiringPi Bibliothek benutzt werden um FHEM Schreibrechte auf die I2C Schnittstelle zu bekommen.
        WiringPi Installation ist hier beschrieben: RPI_GPIO
        Das gpio Utility wird, wenn vorhanden, automatisch verwendet
    • Installation der I2C Abhängigkeiten:
      sudo apt-get install libi2c-dev i2c-tools build-essential
    • I2C Kernelmodule laden:
      modules Datei öffnen
      sudo nano /etc/modules
      folgendes einfügen
      i2c-dev
      i2c-bcm2708
    • Optional, Hardwarezugriff via IOCTL wird standardmäßig genutzt, wenn Device::SMBus nicht installiert ist
      Soll der Hardwarezugriff über das Perl Modul Device::SMBus erfolgen sind diese Schritte notwendig:
      sudo apt-get install libmoose-perl
      sudo cpan Device::SMBus


    Define
      define <name> RPII2C <I2C Bus Number>
      Die <I2C Bus Number> ist die Nummer des I2C Bus an den die I2C IC's angeschlossen werden (0 oder 1)

    Set
    • Schreibe ein Byte (oder auch mehrere nacheinander) direkt auf ein I2C device (manche I2C Module sind so einfach, das es nicht einmal mehrere Register gibt):
      set <name> writeByte <I2C Address> <value>

    • Schreibe n-bytes auf einen Registerbereich (als Folge von Einzelbefehlen), beginnend mit dem angegebenen Register:
      set <name> writeByteReg <I2C Address> <Register Address> <value>

    • Schreibe n-bytes auf einen Registerbereich (als Blockoperation), beginnend mit dem angegebenen Register:
      set <name> writeBlock <I2C Address> <Register Address> <value>


    • Beispiele:
        Schreibe 0xAA zu Modul mit I2C Addresse 0x60
        set test1 writeByte 60 AA
        Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E
        set test1 writeByteReg 6E 01 AA
        Schreibe 0xAA zu Register 0x01 des Moduls mit der I2C Adresse 0x6E, schreibe danach 0x55 in das Register 0x02 als einzelne Befehle
        set test1 writeByteReg 6E 01 AA 55
        Schreibe 0xA4 zu Register 0x03, 0x00 zu Register 0x04 und 0xDA zu Register 0x05 des Moduls mit der I2C Adresse 0x60 zusammen als ein Blockbefehl
        set test1 writeBlock 60 03 A4 00 DA

    Get
      get <name> read <I2C Address> [<Register Address> [<number of registers>]]
      Auslesen der Registerinhalte des I2C Moduls

      Examples:
        Lese Byte vom Modul mit der I2C Adresse 0x60
        get test1 writeByte 60
        Lese den Inhalt des Registers 0x01 vom Modul mit der I2C Adresse 0x6E.
        get test1 read 6E 01 AA 55
        Lese den Inhalt des Registerbereichs 0x03 bis 0x06 vom Modul mit der I2C Adresse 0x60.
        get test1 read 60 03 4


    Attribute
    • swap_i2c0
      Umschalten von I2C-0 des Raspberry Pi Rev. B von J5 auf P5
      Dieses Attribut ist nur für das Raspberry Pi vorgesehen und benötigt das gpio utility wie unter dem Punkt Vorbereitung beschrieben.
      Standard: keiner, gültige Werte: on, off

    • useHWLib
      Ändern der Methode des Hardwarezugriffs.
      Dieses Attribut existiert nur, wenn beide Zugriffsmethoden verfügbar sind
      Standard: IOCTL, gültige Werte: IOCTL, SMBus

    • ignore
    • do_not_notify
    • showtime

=end html_DE 1;