# $Id$
####################################################################################################
#
# 55_PIFACE.pm
#
# An FHEM Perl module to control RaspberryPi extension board PiFace
#
# The PiFace is an add-on board for the Raspberry Pi featuring 8 open-collector outputs,
# with 2 relays and 8 inputs (with 4 on-board buttons).
# These functions are fairly well fixed in the hardware,
# so only the read, write and internal pull-up commands are implemented.
#
# Please read commandref for details on prerequisits!
# Depends on wiringPi library from http://wiringpi.com
#
# Copyright: betateilchen ®
# e-mail: fhem.development@betateilchen.de
#
# This file is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see .
#
####################################################################################################
package main;
use strict;
use warnings;
sub PIFACE_Define($$);
sub PIFACE_Undefine($$);
sub PIFACE_Set($@);
sub PIFACE_Get($@);
my $base = 199;
sub PIFACE_Initialize($){
my ($hash) = @_;
$hash->{DefFn} = "PIFACE_Define";
$hash->{UndefFn} = "PIFACE_Undefine";
$hash->{SetFn} = "PIFACE_Set";
$hash->{GetFn} = "PIFACE_Get";
$hash->{AttrList} = $readingFnAttributes;
}
sub PIFACE_Define($$){
my ($hash, $def) = @_;
my $name = $hash->{NAME};
Log3($name, 3, "PIFACE $name: created");
readingsSingleUpdate($hash, "state", "active",1);
PI_read_outports($hash);
PI_read_inports($hash,0);
PI_read_inports($hash,1);
return undef;
}
sub PIFACE_Undefine($$){
my($hash, $name) = @_;
RemoveInternalTimer($hash);
return;
}
sub PIFACE_Set($@){
my ($hash, @a) = @_;
my $name = $hash->{NAME};
my $port = $a[1];
my $val = $a[2];
my ($adr, $cmd, $i, $j, $k);
my $usage = "Unknown argument $port, choose one of 0 1:0,1 2:0,1 3:0,1 4:0,1 5:0,1 6:0,1 7:0,1 8:0,1 ";
return $usage if $port eq "?";
if ($port ne "0") {
$adr = $base + $port;
Log3($name, 3, "PIFACE $name: set port $port $val");
$cmd = "/usr/local/bin/gpio -p write $adr $val";
$cmd = `$cmd`;
readingsSingleUpdate($hash, 'out'.$port, $val, 1);
} else {
$adr = $base + 1;
Log3($name, 3, "PIFACE $name: set ports $val");
readingsBeginUpdate($hash);
for($i=0; $i<8; $i++){
$j = 2**$i;
$k = ($val & $j);
$k = ($k) ? 1 : 0;
$adr = 1 + $i;
Log3($name, 3, "PIFACE $name: set port $adr $k");
$adr += $base;
$cmd = "/usr/local/bin/gpio -p write $adr $k";
$cmd = `$cmd`;
$j = $i + 1;
readingsBulkUpdate($hash, 'out'.$j, $k);
}
readingsEndUpdate($hash, 1);
}
return "";
}
sub PIFACE_Get($@){
my ($hash, @a) = @_;
my $name = $hash->{NAME};
my $port = $a[1];
my ($adr, $cmd, $pin, $pull, $val);
my $usage = "Unknown argument $port, choose one of 0:noArg ".
"1:noArg 2:noArg 3:noArg 4:noArg ".
"5:noArg 6:noArg 7:noArg 8:noArg ".
"11:noArg 12:noArg 13:noArg 14:noArg ".
"15:noArg 16:noArg 17:noArg 18:noArg ".
"21:noArg 22:noArg 23:noArg 24:noArg ".
"25:noArg 26:noArg 27:noArg 28:noArg ";
return $usage if $port eq "?";
if ($port eq "0") {
PI_read_outports($hash);
PI_read_inports($hash,0);
PI_read_inports($hash,1);
} elsif ($port ~~ [1..8]) {
# read inport
$adr = $base + $port;
$cmd = '/usr/local/bin/gpio -p read '.$adr;
$val = `$cmd`;
readingsSingleUpdate($hash, 'in'.$port, $val, 1);
} elsif ($port ~~ [11..18]) {
# read inport with pullup
$pin = $port - 10;
$adr = $base + $pin;
$cmd = '/usr/local/bin/gpio -p mode '.$adr.' up';
$val = `$cmd`;
$cmd = '/usr/local/bin/gpio -p read '.$adr;
$val = `$cmd`;
readingsSingleUpdate($hash, 'in'.$port, $val, 1);
} elsif ($port ~~ [21..28]) {
# read outport
$pin = $port - 12;
$port -= 20;
$adr = $base + $pin;
$cmd = '/usr/local/bin/gpio -p read '.$adr;
$val = `$cmd`;
readingsSingleUpdate($hash, 'out'.$port, $val, 1);
}
return "";
}
sub PI_read_outports($){
my ($hash) = @_;
my $val = '?';
my ($cmd, $i, $port);
readingsBeginUpdate($hash);
for($i=1; $i<9; $i++){
$port = $base + $i + 8;
$cmd = '/usr/local/bin/gpio -p read '.$port;
$val = `$cmd`;
readingsBulkUpdate($hash, 'out'.$i, $val);
}
readingsEndUpdate($hash, 0);
return
}
sub PI_read_inports($;$){
my ($hash,$pull) = @_;
my $val = '?';
my ($cmd, $i, $j, $port);
readingsBeginUpdate($hash);
for($i=1; $i<9; $i++){
$port = $base + $i;
if($pull eq '1'){
$cmd = '/usr/local/bin/gpio -p mode '.$port.' up';
$val = `$cmd`;
$cmd = '/usr/local/bin/gpio -p read '.$port;
$val = `$cmd`;
$j = 10 + $i;
readingsBulkUpdate($hash, 'in'.$j, chomp($val));
} else {
$cmd = '/usr/local/bin/gpio -p mode '.$port.' tri';
$val = `$cmd`;
$cmd = '/usr/local/bin/gpio -p read '.$port;
$val = `$cmd`;
readingsBulkUpdate($hash, 'in'.$i, chomp($val));
}
}
readingsEndUpdate($hash, 1);
return
}
1;
=pod
=begin html
PIFACE
Prerequesits
Module needs wiringPi tools from http://wiringpi.com
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
Define
define <name> PIFACE
This module provides set/get functionality to control ports on RaspberryPi extension board PiFace
Set-Commands
set <name> <port> <value>
- set single port n to 1 (on) or 0 (off)
Examples:
set <name> 3 1 => set port 3 on
set <name> 5 0 => set port 5 off
- set all ports in one command by bitmask
Example:
set <name> 0 255 => set all ports on
set <name> 0 0 => set all ports off
set <name> 0 170 => bitmask(170) = 10101010 => set ports 2 4 6 8 on, ports 1 3 5 7 off
port 87654321
bit 10101010
Get-Commands
get <name> <port>
- get state of single input port with internal pullups off
Example:
get <name> 3 => get state of input port 3
- get state of single input port with internal pullups on
Add 10 to port number!
Example:
get <name> 15 => get state of input port 5
- get state of single output port with internal pullups on
Add 20 to port number!
Example:
get <name> 25 => get state of output port 5
- get state of all input AND output ports and update readings
Example:
get <name> 0 => get state of all ports
Attributes
Generated Readings/Events:
- <out1..out8> - state of output port 1..8
- <in1..in8> - state of input port 1..8 without pullup resistor active
- <in11..in18> - state of input port 1..8 with pullup resistor active
Author's notes
- Relays 1 and 2 have corresponding port 1 and 2
- Switches 1..4 have corresponding ports 1..4 and must be read with pullups on
- Have fun!
=end html
=cut