############################################################################## # # 51_RPI_GPIO.pm # ############################################################################## # Modul for Raspberry Pi GPIO access # # define RPI_GPIO # where is one of RPi's GPIO # # # contributed by Klaus Wittstock (2013) email: klauswittstock bei gmail punkt com # ############################################################################## package main; use strict; use warnings; use POSIX; use Scalar::Util qw(looks_like_number); use IO::File; use SetExtensions; sub RPI_GPIO_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "RPI_GPIO_Define"; $hash->{GetFn} = "RPI_GPIO_Get"; $hash->{SetFn} = "RPI_GPIO_Set"; $hash->{StateFn} = "RPI_GPIO_State"; $hash->{AttrFn} = "RPI_GPIO_Attr"; $hash->{UndefFn} = "RPI_GPIO_Undef"; $hash->{ExceptFn} = "RPI_GPIO_Except"; $hash->{AttrList} = "poll_interval loglevel:0,1,2,3,4,5" . " 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"; } my $gpiodir = "/sys/class/gpio"; #GPIO base directory my $gpioprg = "/usr/local/bin/gpio"; #WiringPi GPIO utility my %setsoutp = ( 'on:noArg' => 0, 'off:noArg' => 0, 'toggle:noArg' => 0, ); my %setsinpt = ( 'readValue' => 0, ); sub RPI_GPIO_Define($$) { my ($hash, $def) = @_; my @args = split("[ \t]+", $def); my $menge = int(@args); if (int(@args) < 3) { return "Define: to less arguments. Usage:\n" . "define RPI_GPIO "; } #Prüfen, ob GPIO bereits verwendet foreach my $dev (devspec2array("TYPE=$hash->{TYPE}")) { if ($args[2] eq InternalVal($dev,"RPI_pin","")) { return "GPIO $args[2] already used by $dev"; } } my $name = $args[0]; $hash->{RPI_pin} = $args[2]; #export Pin alte Version -> wird jetzt über direction gemacht (WiringPi Programm GPIO) #my $exp = IO::File->new("> /sys/class/gpio/export"); #print $exp "$hash->{RPI_pin}"; #$exp->close; #select(undef, undef, undef, 0.4); #kurz warten bis Verzeichnis angelegt # create default attributes my $msg = CommandAttr(undef, $name . ' direction input'); return $msg if ($msg); select(undef, undef, undef, 0.4); $hash->{fhem}{interfaces} = "switch"; return undef; } sub RPI_GPIO_Get($) { my ($hash) = @_; my $name = $hash->{NAME}; #my $dir = $attr{$hash->{NAME}}{direction} || "output"; my $dir = ""; my $zustand = undef; my $val = fileaccess($hash, "value"); if ( defined ($val) ) { if ( $val == 1) { if ($dir eq "output") {$zustand = "on";} else {$zustand = "high";} } elsif ( $val == 0 ) { if ($dir eq "output") {$zustand = "off";} else {$zustand = "low";} } } else { Log 1, "$hash->{NAME} GetFn: readout of Pinvalue fail"; } $hash->{READINGS}{Pinlevel}{VAL} = $zustand; $hash->{READINGS}{Pinlevel}{TIME} = TimeNow(); return "Current Value for $name: $zustand"; } sub RPI_GPIO_Set($@) { my ($hash, @a) = @_; my $name =$a[0]; my $cmd = $a[1]; #my $val = $a[2]; if(defined($attr{$name}) && defined($attr{$name}{"direction"})) { my $mt = $attr{$name}{"direction"}; if($mt && $mt eq "output") { if ($cmd eq 'toggle') { my $val = fileaccess($hash, "value"); #alten Wert des GPIO direkt auslesen $cmd = $val eq "0" ? "on" :"off"; } if ($cmd eq 'on') { fileaccess($hash, "value", "1"); $hash->{STATE} = 'on'; } elsif ($cmd eq 'off') { fileaccess($hash, "value", "0"); $hash->{STATE} = 'off'; } else { my $slist = join(' ', keys %setsoutp); return SetExtensions($hash, $slist, @a); } } else { if(!defined($setsinpt{$cmd})) { return 'Unknown argument ' . $cmd . ', choose one of ' . join(' ', keys %setsinpt) } else { } } } if ($cmd eq 'readValue') { #noch bei input einpflegen updatevalue($hash); } } sub RPI_GPIO_State($$$$) { my ($hash, $tim, $sname, $sval) = @_; #Log 1, "$hash->{NAME}: $sname kann auf $sval wiederhergestellt werden $tim"; if ( (AttrVal($hash->{NAME},"restoreOnStartup","on") eq "on") && ($sname ne "STATE") ) { if (AttrVal($hash->{NAME},"direction","") eq "output") { $hash->{READINGS}{$sname}{VAL} = $sval; $hash->{READINGS}{$sname}{TIME} = $tim; #Log 1, "OUTPUT $hash->{NAME}: $sname wiederhergestellt auf $sval"; if ($sname eq "state") { #RPI_GPIO_Set($hash,$hash->{NAME},$sname,$sval); RPI_GPIO_Set($hash,$hash->{NAME},$sval); #Log 1, "OUTPUT $hash->{NAME}: STATE wiederhergestellt auf $sval"; } } elsif ( (AttrVal($hash->{NAME},"direction","") eq "input") && (AttrVal($hash->{NAME},"toggletostate","") eq "yes")) { if ($sname eq "Toggle") { $hash->{READINGS}{$sname}{VAL} = $sval; $hash->{READINGS}{$sname}{TIME} = $tim; #RPI_GPIO_Set($hash,$hash->{NAME},$sval); readingsBeginUpdate($hash); readingsBulkUpdate($hash, 'state', $sval); readingsEndUpdate($hash, 1); #Log 1, "INPUT $hash->{NAME}: $sname und STATE wiederhergestellt auf $sval"; } elsif ($sname eq "Counter") { $hash->{READINGS}{$sname}{VAL} = $sval; $hash->{READINGS}{$sname}{TIME} = $tim; #Log 1, "INPUT $hash->{NAME}: $sname wiederhergestellt auf $sval"; } } } return; } sub RPI_GPIO_Attr(@) { my (undef, $name, $attr, $val) = @_; my $hash = $defs{$name}; my $msg = ''; if ($attr eq 'poll_interval') { if ( defined($val) ) { if ( looks_like_number($val) && $val > 0) { RemoveInternalTimer($hash); InternalTimer(1, 'RPI_GPIO_Poll', $hash, 0); } else { $msg = "$hash->{NAME}: Wrong poll intervall defined. poll_interval must be a number > 0"; } } else { #wird auch aufgerufen wenn $val leer ist, aber der attribut wert wird auf 1 gesetzt RemoveInternalTimer($hash); } } if ($attr eq 'direction') { if (!$val) { #$val nicht definiert: Einstellungen löschen $msg = "$hash->{NAME}: no direction value. Use input output"; } elsif ($val eq "input") { #fileaccess($hash, "direction", "in"); exuexpin($hash, "in"); #Log 1, "$hash->{NAME}: direction: input"; } elsif( ( AttrVal($hash->{NAME}, "interrupt", "none") ) ne ( "none" ) ) { $msg = "$hash->{NAME}: Delete attribute interrupt or set it to none for output direction"; } elsif ($val eq "output") { #fileaccess($hash, "direction", "out"); exuexpin($hash, "out"); #Log 1, "$hash->{NAME}: direction: output"; } else { $msg = "$hash->{NAME}: Wrong $attr value. Use input output"; } } if ($attr eq 'interrupt') { if ( !$val || ($val eq "none") ) { fileaccess($hash, "edge", "none"); inthandling($hash, "stop"); #Log 1, "$hash->{NAME}: interrupt: none"; } elsif (( AttrVal($hash->{NAME}, "direction", "output") ) eq ( "output" )) { $msg = "$hash->{NAME}: Wrong direction value defined for interrupt. Use input"; } elsif ($val eq "falling") { fileaccess($hash, "edge", "falling"); inthandling($hash, "start"); #Log 1, "$hash->{NAME}: interrupt: falling"; } elsif ($val eq "rising") { fileaccess($hash, "edge", "rising"); inthandling($hash, "start"); #Log 1, "$hash->{NAME}: interrupt: rising"; } elsif ($val eq "both") { fileaccess($hash, "edge", "both"); inthandling($hash, "start"); #Log 1, "$hash->{NAME}: interrupt: both"; } else { $msg = "$hash->{NAME}: Wrong $attr value. Use none, falling, rising or both"; } } #Tastfunktion: bei jedem Tastendruck wird State invertiert if ($attr eq 'toggletostate') { if ( !$val || ($val eq ("yes" || "no") ) ) { #Log 1, "$hash->{NAME}: toggletostate: passt"; } else { $msg = "$hash->{NAME}: Wrong $attr value. Use yes or no"; } } #invertierte Logik if ($attr eq 'active_low') { if ( !$val || ($val eq "no" ) ) { fileaccess($hash, "active_low", "0"); #Log 1, "$hash->{NAME}: interrupt: none"; } elsif ($val eq "yes") { fileaccess($hash, "active_low", "1"); } else { $msg = "$hash->{NAME}: Wrong $attr value. Use yes or no"; } } #Entprellzeit 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') { my $pud; if ( !$val ) { } elsif ($val eq "off") { $pud = $gpioprg.' -g mode '.$hash->{RPI_pin}.' tri'; $pud = `$pud`; } elsif ($val eq "up") { $pud = $gpioprg.' -g mode '.$hash->{RPI_pin}.' up'; $pud = `$pud`; } elsif ($val eq "down") { $pud = $gpioprg.' -g mode '.$hash->{RPI_pin}.' down'; $pud = `$pud`; } else { $msg = "$hash->{NAME}: Wrong $attr value. Use off, up or down"; } } return ($msg) ? $msg : undef; } sub RPI_GPIO_Poll($) { my ($hash) = @_; my $name = $hash->{NAME}; updatevalue($hash); my $pollInterval = AttrVal($hash->{NAME}, 'poll_interval', 0); if ($pollInterval > 0) { InternalTimer(gettimeofday() + ($pollInterval * 60), 'RPI_GPIO_Poll', $hash, 0); } return; } sub RPI_GPIO_Undef($$) { my ($hash, $arg) = @_; if ( defined (AttrVal($hash->{NAME}, "poll_interval", undef)) ) { RemoveInternalTimer($hash); } if ( ( AttrVal($hash->{NAME}, "interrupt", "none") ) ne ( "none" ) ) { delete $selectlist{$hash->{NAME}}; close($hash->{filehandle}); } #unexport Pin alte Version #my $uexp = IO::File->new("> /sys/class/gpio/unexport"); #print $uexp "$hash->{RPI_pin}"; #$uexp->close; #alternative unexport Pin: exuexpin($hash, "unexport"); return undef; } sub RPI_GPIO_Except($) { my ($hash) = @_; #seek($hash->{filehandle},0,0); #an Anfang der Datei springen (ist nötig falls vorher schon etwas gelesen wurde) #chomp ( my $firstval = $hash->{filehandle}->getline ); #aktuelle Zeile auslesen und Endezeichen entfernen my $eval = fileaccess($hash, "edge"); #Eintstellung Flankensteuerung auslesen my ($valst, $valalt, $valto, $valcnt) = undef; my $debounce_time = AttrVal($hash->{NAME}, "debounce_in_ms", "0"); #Wartezeit zum entprellen if( $debounce_time ne "0" ) { $debounce_time /= 1000; Log 1, "Wartezeit: $debounce_time ms"; select(undef, undef, undef, $debounce_time); } seek($hash->{filehandle},0,0); #an Anfang der Datei springen (ist nötig falls vorher schon etwas gelesen wurde) chomp ( my $val = $hash->{filehandle}->getline ); #aktuelle Zeile auslesen und Endezeichen entfernen if ( ( $val == 1) && ( $eval ne ("falling") ) ) { $valst = "on"; $valalt = "high"; } elsif ( ( $val == 0 ) && ($eval ne "rising" ) ) { $valst = "off"; $valalt = "low"; } if ( ( ($eval eq "rising") && ( $val == 1 ) ) || ( ($eval eq "falling") && ( $val == 0 ) ) ) { #nur bei Trigger auf steigende / fallende Flanke #Togglefunktion if (!defined($hash->{READINGS}{Toggle}{VAL})) { #Togglewert existiert nicht -> anlegen #Log 1, "Toggle war nicht def"; $valto = "on"; } elsif ( $hash->{READINGS}{Toggle}{VAL} eq "off" ) { #Togglewert invertieren #my $twert = $hash->{READINGS}{Toggle}{VAL}; #Log 1, "Toggle war auf $twert"; $valto = "on"; } else { #my $twert = $hash->{READINGS}{Toggle}{VAL}; #Log 1, "Toggle war auf $twert"; $valto = "off"; } #Log 1, "Toggle ist jetzt $valto"; if (( AttrVal($hash->{NAME}, "toggletostate", "no") ) eq ( "yes" )) { #wenn Attr "toggletostate" gesetzt auch die Variable für den STATE wert setzen $valst = $valto; } #Zählfunktion if (!defined($hash->{READINGS}{Counter}{VAL})) { #Zähler existiert nicht -> anlegen #Log 1, "Zähler war nicht def"; $valcnt = "1"; } else { $valcnt = $hash->{READINGS}{Counter}{VAL} + 1; #Log 1, "Zähler ist jetzt $valcnt"; } } delete ($hash->{READINGS}{Toggle}) if ($eval ne ("rising" || "falling")); #Reading Toggle löschen wenn kein Wert in Variable readingsBeginUpdate($hash); readingsBulkUpdate($hash, 'Pinlevel', $valalt); readingsBulkUpdate($hash, 'state', $valst); readingsBulkUpdate($hash, 'Toggle', $valto) if ($valto); readingsBulkUpdate($hash, 'Counter', $valcnt) if ($valcnt); readingsEndUpdate($hash, 1); #Log 1, "RPIGPIO: Except ausgelöst: $hash->{NAME}, Wert: $val, edge: $eval,vt: $valto, $debounce_time s: $firstval"; } sub updatevalue($) { my ($hash) = @_; my $val = fileaccess($hash, "value"); if ( defined ($val) ) { my ($valst, $valalt) = undef; if ( $val == 1) { $valst = "on"; $valalt = "high"; } elsif ( $val == 0 ) { $valst = "off"; $valalt = "low"; } readingsBeginUpdate($hash); readingsBulkUpdate($hash, 'Pinlevel', $valalt); readingsBulkUpdate($hash, 'state', $valst) if (( AttrVal($hash->{NAME}, "toggletostate", "yes") ) eq ( "no" )); readingsEndUpdate($hash, 1); } else { Log 1, "$hash->{NAME}: readout of Pinvalue fail"; } } sub fileaccess($$;$) { #my ($hash, $fname, $value) = @_; my ($hash, @args) = @_; my $fname = $args[0]; my $pinroot = qq($gpiodir/gpio$hash->{RPI_pin}); my $file =qq($pinroot/$fname); if (int(@args) < 2){ my $fh = IO::File->new("< $file"); if (defined $fh) { chomp ( my $pinvalue = $fh->getline ); $fh->close; return $pinvalue; } else { Log 1, "Can't open file: $hash->{NAME}, $fname"; } } else { my $value = $args[1]; my $fh = IO::File->new("> $file"); if (defined $fh) { print $fh "$value"; $fh->close; } else { Log 1, "Can't open file: $hash->{NAME}, $fname"; } } } sub exuexpin($$) { my ($hash, $dir) = @_; my $sw; if ($dir eq "unexport") { $sw = $dir; $dir = ""; } else { $sw = "export"; $dir = " ".$dir; } #alternative export Pin if(-e $gpioprg) { if(-x $gpioprg) { if(-u $gpioprg) { my $exp = $gpioprg.' '.$sw.' '.$hash->{RPI_pin}.$dir; $exp = `$exp`; } else { Log 1, "file $gpioprg is not setuid"; } } else { Log 1, "file $gpioprg is not executable"; } } else { Log 1, "file $gpioprg doesnt exist"; } ####################### } sub inthandling($$) { my ($hash, $arg) = @_; my $msg = ''; if ( $arg eq "start") { #FH für value-datei my $pinroot = qq($gpiodir/gpio$hash->{RPI_pin}); my $valfile = qq($pinroot/value); $hash->{filehandle} = IO::File->new("< $valfile"); if (!defined $hash->{filehandle}) { $msg = "Can't open file: $hash->{NAME}, $valfile"; } else { $selectlist{$hash->{NAME}} = $hash; $hash->{EXCEPT_FD} = fileno($hash->{filehandle}); my $pinvalue = $hash->{filehandle}->getline; Log 5, "Datei: $valfile, FH: $hash->{filehandle}, EXCEPT_FD: $hash->{EXCEPT_FD}, akt. Wert: $pinvalue"; } } else { delete $selectlist{$hash->{NAME}}; close($hash->{filehandle}); } } 1; =pod =begin html

RPI_GPIO

    Raspberry Pi offers direct access to several GPIO via header P1 (and P5 on V2). The Pinout is shown in table under define. With this module you are able to access these GPIO's directly as output or input. For input you can use either polling or interrupt mode

    Warning: Never apply any external voltage to an output configured pin! GPIO's internal logic operate with 3,3V. Don't exceed this Voltage!

    preliminary:
    GPIO Pins accessed by sysfs. The files are located in folder /system/class/gpio which can be only accessed by root. This module uses gpio utility from WiringPi library to export and change access rights of GPIO's
    Install WiringPi:

      sudo apt-get update
      sudo apt-get upgrade
      sudo apt-get install git-core
      git clone git://git.drogon.net/wiringPi
      cd wiringPi
      ./build
      sudo adduser fhem gpio
    Thats all

    Define
      define RPI_GPIO <GPIO number>

      all usable GPIO number are in the following tables

      PCB Revision 1 P1 pin header
      Function PinPin Function
      3,3V 1 2 5V
      GPIO 0 (SDA0)3 4
      GPIO 1 (SCL0)5 6 GND
      GPIO 4 (GPCLK0) 7 8 GPIO 14 (TxD)
      9 10 GPIO 15 (RxD)
      GPIO 17 11 12 GPIO 18 (PCM_CLK)
      GPIO 21 13 14
      GPIO 22 15 16 GPIO 23
      17 18 GPIO 24
      GPIO 10 (MOSI) 19 20
      GPIO 9 (MISO) 21 22 GPIO 25
      GPIO 11 (SCLK) 23 24 GPIO 8 (CE0)
      25 26 GPIO 7 (CE1)
      PCB Revision 2 P1 pin header
      Function PinPin Function
      3,3V 1 2 5V
      GPIO 2 (SDA1)3 4
      GPIO 3 (SCL1)5 6 GND
      GPIO 4 (GPCLK0) 7 8 GPIO 14 (TxD)
      9 10 GPIO 15 (RxD)
      GPIO 17 11 12 GPIO 18 (PCM_CLK)
      GPIO 27 13 14
      GPIO 22 15 16 GPIO 23
      17 18 GPIO 24
      GPIO 10 (MOSI) 19 20
      GPIO 9 (MISO) 21 22 GPIO 25
      GPIO 11 (SCLK) 23 24 GPIO 8 (CE0)
      25 26 GPIO 7 (CE1)
      PCB Revision 2 P5 pin header
      Function PinPinFunction
      5V 1 2 3,3V
      GPIO 28 (SDA0)3 4 GPIO 29 (SCL0)
      GPIO 30 5 6 GPOI 31
      GND 7 8 GND
      Examples:
            define Pin12 RPI_GPIO 18
            attr Pin12
            attr Pin12 poll_interval 5
          
    Set
      set <name> <value>

      where value is one of:
      • for output configured GPIO
          off
          on
          toggle
        The set extensions are also supported.
      • for input configured GPIO
          readval
        readval refreshes the reading Pinlevel and, if attr toggletostate not set, the state value

      Examples:
        set Pin12 off
        set Pin11,Pin12 on

    Get
      get <name>

      returns "high" or "low" regarding the actual status of the pin and writes this value to reading Pinlevel

    Attributes
    • direction
      Sets the GPIO direction to input or output.
      Default: input, valid values: input, output

    • interrupt
      can only be used with GPIO configured as input
      enables edge detection for GPIO pin
      on each interrupt event readings Pinlevel and state will be updated
      Default: none, valid values: none, falling, rising, both

    • poll_interval
      Set the polling interval in minutes to query the GPIO's level
      Default: -, valid values: decimal number

    • toggletostate
      works with interrupt set to falling or rising only
      if yes, state will be toggled at each interrupt event
      Default: no, valid values: yes, no

    • pud_resistor
      Sets the internal pullup/pulldown resistor
      Default: -, valid values: off, up, down

    • debounce_in_ms
      readout of pin value x ms after an interrupt occured. Can be used for switch debouncing
      Default: 0, valid values: decimal number

    • restoreOnStartup
      Restore Readings and sets after reboot
      Default: on, valid values: on, off


=end html =begin html_DE

RPI_GPIO

    Das Raspberry Pi ermöglicht direkten Zugriff zu einigen GPIO's über den Pfostenstecker P1 (und P5 bei V2). Die Steckerbelegung ist in den Tabellen unter Define zu finden. Dieses Modul ermöglicht es, die herausgefühten GPIO's direkt als Ein- und Ausgang zu benutzen. Die Eingänge können zyklisch abgefragt werden oder auch sofort bei Pegelwechsel gesetzt werden.

    Wichtig: Niemals Spannung an einen GPIO anlegen, der als Ausgang eingestellt ist! Die interne Logik der GPIO's arbeitet mit 3,3V. Ein überschreiten der 3,3V zerstört den GPIO und vielleicht auch den ganzen Prozessor!

    Vorbereitung:
    Auf GPIO Pins wird im Modul über sysfs zugegriffen. Die Dateien befinden sich unter /system/class/gpio und können nur mit root erreicht werden. Dieses Modul nutzt das gpio Tool von der WiringPi. Bibliothek um GPIS zu exportieren und die korrekten Nutzerrechte zu setzen. Installation WiringPi:

      sudo apt-get update
      sudo apt-get upgrade
      sudo apt-get install git-core
      git clone git://git.drogon.net/wiringPi
      cd wiringPi
      ./build
      sudo adduser fhem gpio
    Das wars!

    Define
      define <name> RPI_GPIO <GPIO number>

      Alle verfügbaren GPIO number sind in den folgenden Tabellen zu finden

      PCB Revision 1 P1 pin header
      Function PinPin Function
      3,3V 1 2 5V
      GPIO 0 (SDA0)3 4
      GPIO 1 (SCL0)5 6 GND
      GPIO 4 (GPCLK0) 7 8 GPIO 14 (TxD)
      9 10 GPIO 15 (RxD)
      GPIO 17 11 12 GPIO 18 (PCM_CLK)
      GPIO 21 13 14
      GPIO 22 15 16 GPIO 23
      17 18 GPIO 24
      GPIO 10 (MOSI) 19 20
      GPIO 9 (MISO) 21 22 GPIO 25
      GPIO 11 (SCLK) 23 24 GPIO 8 (CE0)
      25 26 GPIO 7 (CE1)
      PCB Revision 2 P1 pin header
      Function PinPin Function
      3,3V 1 2 5V
      GPIO 2 (SDA1)3 4
      GPIO 3 (SCL1)5 6 GND
      GPIO 4 (GPCLK0) 7 8 GPIO 14 (TxD)
      9 10 GPIO 15 (RxD)
      GPIO 17 11 12 GPIO 18 (PCM_CLK)
      GPIO 27 13 14
      GPIO 22 15 16 GPIO 23
      17 18 GPIO 24
      GPIO 10 (MOSI) 19 20
      GPIO 9 (MISO) 21 22 GPIO 25
      GPIO 11 (SCLK) 23 24 GPIO 8 (CE0)
      25 26 GPIO 7 (CE1)
      PCB Revision 2 P5 pin header
      Function PinPinFunction
      5V 1 2 3,3V
      GPIO 28 (SDA0)3 4 GPIO 29 (SCL0)
      GPIO 30 5 6 GPOI 31
      GND 7 8 GND
      Beispiele:
            define Pin12 RPI_GPIO 18
            attr Pin12
            attr Pin12 poll_interval 5
          
    Set
      set <name> <value>

      value ist dabei einer der folgenden Werte:
      • Für GPIO der als output konfiguriert ist
          off
          on
          toggle
        Die set extensions werden auch unterstützt.
      • Für GPIO der als input konfiguriert ist
          readval
        readval aktualisiert das reading Pinlevel und, wenn attr toggletostate nicht gesetzt ist, auch state

      Beispiele:
        set Pin12 off
        set Pin11,Pin12 on

    Get
      get <name>

      Gibt "high" oder "low" entsprechend dem aktuellen Pinstatus zurück und schreibt den Wert auch in das reading Pinlevel

    Attributes
    • direction
      Setzt den GPIO auf Ein- oder Ausgang.
      Standard: input, gültige Werte: input, output

    • interrupt
      kann nur gewählt werden, wenn der GPIO als Eingang konfiguriert ist
      Aktiviert Flankenerkennung für den GPIO
      bei jedem interrupt Erwignis werden die readings Pinlevel und state aktualisiert
      Standard: none, gültige Werte: none, falling, rising, both

    • poll_interval
      Fragt den Zustand des GPIO regelmäßig ensprechend des eingestellten Wertes in Minuten ab
      Standard: -, gültige Werte: Dezimalzahl

    • toggletostate
      Funktioniert nur bei auf falling oder rising gesetztem Attribut interrupt
      Wenn auf "yes" gestellt wird bei jedem Triggerereignis das state reading invertiert
      Standard: no, gültige Werte: yes, no

    • pud_resistor
      Interner Pullup/down Widerstand
      Standard: -, gültige Werte: off, up, down

    • debounce_in_ms
      Wartezeit in ms bis nach ausgelöstem Interrupt der entsprechende Pin abgefragt wird. Kann zum entprellen von mechanischen Schaltern verwendet werden
      Standard: 0, gültige Werte: Dezimalzahl

    • restoreOnStartup
      Wiederherstellen der Portzustände nach Neustart
      Standard: on, gültige Werte: on, off


=end html_DE =cut