• Utility corner
pi-button-pipe — A GPIO button watcher for Raspberry Pi and similar devices
Version 0.0.1, January 2013
What is this?
pi-button-pipe is a simple daemon for reading interrupts from
the GPIO pins of a Raspberry Pi or similar device, and making them available
as a stream of data that can be read by another program. It is specifically
designed to handle simple, normally-open pushbuttons that pull up the
GPIO pins from ground to supply (that is, it triggers on the rising edge
of the pin voltage).
pi-button-pipe works without polling, can monitor several
pins at once, and does not need to run as
root step is needed to initialize the pin configuration — see below). It does not (or should not) need additional de-bouncing
hardware on the pushbuttons, as
pi-button-pipe debounces both on the closing and opening
of the switch contacts.
pi-button-pipe uses a named pipe for communication with
the consumer process, whatever that is. Data from the program is
simply a stream of decimal numbers corresponding to the pins that
were toggled, so it should be easy to integrate with other software.
pi-button-pipe is written in plain C, and does not depend
on any additional libraries.
Building and installation
To build from source, in general, unpack the source bundle and
make install. The source bundle includes a compiled binary
for Raspberry Pi. The install process writes the binary into
/usr/bin, although the program is not at all fussy about
where it is installed.
In normal operation,
pi-button-pipe is invoked with a list of pins to monitor,
# pi-button-pump 23 24 25
It is assumed that each of these pins is attached to a pushbutton that
will raise the pin voltage when it is depressed. The program opens a
named pipe called
/tmp/pi-button-pump and, every time
a button is pressed, the pin number is written to the pipe as
a decimal number. Meanwhile, the consumer of the pushbutton data
reads the pipe. If you simple use
cat to read the data,
you might see something like this:
$ cat /tmp/pi-buttons
Notice that the consumer need not run as root.
The pipe filename is (sorry) not configurable at present, except by
editing the code. If the pipe does not exist, the the program will
create it if it can. However, it's important to understand
that a Linux pipe is not like a socket — it is intended for one-time
use for communication between a single pair of processes. What this means
is that both processes will block until both are attached to the pipe.
Then, when one process exits, the pipe will break, and the other
process will also exit (via a signal). The practical result is that
you can't just start
pi-button-pipe at boot time, and then have multiple processes
connect to it, either conucrrently or one at a time —
pi-button-pipe and its consumer must be started as a pair.
Running as a non-root user
pi-button-pipe will run as a non-root user, provided that
the relevant pins have been 'exported' first. To export a pin is to
tell the kernel to expose in the directory
another directory named after the pin, and which contains pseudo-files
that can be used to read and write the pin. It is also necessary to set
the required pins to input mode, and to set them to interrup on the
You might also want to
'unexport' the pins afterwards, to avoid them being used inadvertently
by other processes. These operations do require
To make non-root operation easier,
provides a way to nothing but export and unexport certain pins; these
operations can be run as root. To do this, use the
-u (unexport) command-line switches.
Then the rest of the work can be done by
running as an ordinary user, with the
-n switch to indicate
that the program should not attempt to export or unexport any pins.
For example, the monitor pins 23, 24, and 25 as a non-root user, use
the following commands:
$ sudo pi-button-pump -e 23 24 25 # Export pins
$ pi-button-pump -n 23 24 25 # Do the work
$ sudo pi-button-pump -u 23 24 25 # Unexport pins
# Now start the consumer process
If you're running as a non-root user, you might need to give some thought
to the permissions assigned to the pipe
particularly if it will be read by a process owned by a different user.
To test the program without a consumer, use the
this will cause it to write the pin numbers to the console rather than
the pipe. If nothing at all seems to be happening, check that the
pin voltage is actually changing, e.g., by running