GPIO Zero is a Python library I created to make physical computing on the Raspberry Pi more accessible, particularly for use in education. Read more about it on raspberrypi.org, or about how it was created in an article on this blog, GPIO Zero: Developing a new friendly API for Physical Computing.
GPIO Zero is a module providing simple interfaces to GPIO components and devices (LED, Button, Buzzer, LightSensor, TrafficLights, etc). It provides classes representing these devices, for the user to create instances to control each of them. Each device has all the features you’d expect the component to have (e.g. LED has
blink methods), providing a simple way to perform common tasks with the device. More complex devices (sensors and such) usually require humongous amounts of code, when using the previous library
RPi.GPIO, but with GPIO Zero, are generally as straightforward as the simple LED:
from gpiozero import LED, MotionSensor led = LED(2) sensor = MotionSensor(3) sensor.when_motion = led.on sensor.when_no_motion = led.off
One of the fancier features of the library is source/values. All devices have a
value attribute, which when inspected, shows the current state (An LED shows
1 when on,
0 when off; a Button shows
1 when pressed,
0 when released), and a
values attribute, which is an infinite iterator constantly yielding the current
value. All output devices have a
source attribute, which is initially
None, but can be set to an infinite iterator. This means you can easily connect two components together:
led.source = button.values
Now the LED’s source comes directly from the Button’s values. In other words, when the button is pressed, the LED is lit.
Additionally, it’s worth noting that an output device’s source can come from an input device (like above), an output device (blue LED comes on when red LED comes on), or from a custom generator (blue LED goes off when red LED comes on, or even something unrelated to GPIO components!)
Version 1.2 of GPIO Zero is out now! The next Raspbian release will include it, but you can upgrade now with:
sudo apt-get update sudo apt-get install python3-gpiozero python-gpiozero
(Note: apt-get install will install a package if it’s not already installed, and will upgrade it if there’s a newer version available)
This version has zero dependencies, so you shouldn’t have any issues installing it even on an older Wheezy image. Previously, the library depended on
spidev, but these are no longer requirements. Alternative pin implementations are available (more on that later), including a pure Python one built in to the library, so
RPi.GPIO is no longer required. If it’s present (more than likely the case), then it will be used, but three alternatives are sought if it’s not! Also, a software implementation of the SPI protocol has been implemented, meaning it’s possible to interface with SPI devices without using hardware SPI at all (the
spidev library doesn’t need to be installed, and SPI doesn’t even need to be enabled in
Something I’ve wanted to have since the early days, but had no idea how to implement. Dave created a test suite, which does a decent job, but does not currently cover the full scope of the library. We have continuous integration set up with Travis, and people have even created GPIO Zero projects related to this – using the Travis CI API to show the test suite status on traffic lights.
See the changelog for full details. We’ve added the following:
Energenie is a long-term favourite of mine and others, it’s an add-on board for the Pi which communicates wirelessly with a special power socket (or set of sockets). I previously maintained a Python module for controlling the Energenie, providing simple
switch_off() functions which took a socket number to control. The GPIO Zero solution is just as simple, a little more elegant, and importantly comes bundled with the fancy features of a first-class GPIO Zero component (source/values)!
from gpiozero import Button, Energenie button = Button(21) light = Energenie(1) light.source = button.values
Here a connection to Energenie’s socket #1 is created, referenced as
light (an actual wall socket desk lamp rather than an LED) and the button set to trigger the light to come on. That’s right – a light switch!
The basic line sensor unit is a simple binary sensor, so its interface is similar to the Button. It just has aliases for
from gpiozero import LED, LineSensor led = LED(2) sensor = LineSensor(3) sensor.when_line = led.on sensor.when_no_line = led.off
There’s one of these in the new CamJam Edu Kit 3 (robotics kit), so it will be handy for that!
The ultrasonic distance sensor is a little more complex in implementation, and requires two GPIO pins (echo and trigger). Its distance thresholds and such are configurable but basic usage looks like this:
from gpiozero import LED, DistanceSensor led = LED(2) sensor = DistanceSensor(echo=3, trigger=4, max_distance=1) sensor.when_in_range = led.on sensor.when_out_of_range = led.off while True: print("Distance: %s" % sensor.distance * 100) sleep(1)
There’s also one of these in CamJam Kit 3 and they’re popular for various projects not limited to robotics.
An excellent Christmas themed add-on board made by Ryan Walmsley. It’s a snowman with LEDs for eyes, one for the nose, and three for each arm.
Simple to program using nine individual LED objects but we crafted a neater interface:
from gpiozero import SnowPi sp = SnowPi() sp.on() # all on sp.blink() # all blinking sp.off() # all off sp.nose.on() # nose on sp.arms.on() # all arm leds on sp.arms.left.off() # all leds on left arm off sp.arms.right.blink() # right arm blinking sp.arms.left.top.on() # individually control top left arm led sp.arms.right.middle.on() # similarly sp.arms.left.bottom.on() # similarly sp.arms.bottom.off() # control bottom led of both arm
This one’s pretty fun to play with! A real stocking filler for next Christmas :)
Martin O’Hanlon suggested we add a way to detect when a button is held for a given length of time, rather than just when it was pressed. He submitted a PR adding a new HoldableButton class, but Dave ended up adding the functionality into the standard Button class:
from gpiozero import Button def hello(): print("Hello") button = Button(2, hold_time=2) button.when_held = hello
led.blink() from the very beginning, and we’ve had an interface for variable brightness LEDs (using PWM). Recently we added additional parameters to
PWMLED‘s version of blink so you could configure fade in time and fade out time:
from gpiozero import PWMLED led = PWMLED(2) led.blink(on_time=1, off_time=1, fade_in_time=1, fade_out_time=1)
Andrew Scheller then added a PR for a
pulse() method which defaulted
0. We liked the idea but it seemed rather pointless to create a new method merely aliasing some different default settings of an existing method. I ended up suggesting we actually remove the
out_time parameters, so it’s more like regular
blink() but with automatic fading, and the time of the fade configurable. So now:
from gpiozero import PWMLED led = PWMLED(2) led.pulse(fade_in_time=1, fade_out_time=1)
Named parameters are not necessary, so in this example you can just use
led.pulse(1, 1) – or skip them altogether as those are the defaults:
Watch Ben Nuttall’s Vine “With PWM” taken on 8 February 2016. It has 0 likes. The entertainment network where videos and personalities get really big, really fast. Download Vine to watch videos, remixes and trends before they blow up.
Various ADC chips – and software SPI
We added to our initial support of a couple of ADC chips such as the MCP3008:
As I mentioned earlier, there’s now a software implementation of the SPI protocol which means you don’t need
spidev installed or SPI enabled in
There’s now a function you can run that returns a whole bunch of information about the Pi you’re using: the revision, model, SoC, manufacturer, memory, storage type and more. As well as providing this information to the user on request, it is used internally to warn users when they, for example, try to use a pull-down circuit on a pin with a physical pull-up resistor built in. Also, developers could use this information to do similar things in their own projects or libraries. See the wealth of information provided in data.py
The source/value feature is more advanced than simply using loops, or even callbacks, but it can be really powerful. We found that although the basic examples were very simple to use, there were many alternative common uses that required much more code. For example, if you wanted one LED to mimic another, that’s just
blue.source = red.values, but if you want one to be the inverse of the other (i.e. red at 40% brightness should make blue 60% brightness), you’d have to create your own generator function:
from gpiozero import PWMLED blue = PWMLED(2) red = PWMLED(3) def invert(led): while True: yield 1 - led.value blue.source = invert(red)
But now we have a set of tools exactly for these common use cases. We have
averaged. The invert example becomes:
from gpiozero import PWMLED from gpiozero.tools import inverted blue = PWMLED(2) red = PWMLED(3) blue.source = inverted(red.values)
See the documentation on source tools for more information and examples.
Alternative pin implementations
Initially, when I created GPIO Zero, it was just an abstraction layer sitting on top of an existing GPIO library, RPi.GPIO. However, we now support four multiple back-ends: RPi.GPIO, RPIO, pigpiod and a native implementation. The priority is such that RPi.GPIO is preferred, being the most stable option we know of (and 99% of users will be using this implementation, as it’s pre-installed in Raspbian); secondly, RPIO, another Python library with better PWM support; thirdly a Python module which communicates with a C library (pigpio) running as a daemon (pigpiod), which is an interesting option I’ll explain next; finally, if none of those libraries are found to be available, the fallback is a pure Python pins implementation Dave wrote as part of GPIO Zero. It’s pretty basic at present, and is rather experimental, but for basic use it does just about work.
pigpio and pigpiod
pigpio is a C library which provides an interface to GPIO, PWM, SPI, I2C, Serial and more. Its feature set is brilliantly extensive, and its killer feature is the daemon. pigpiod runs as root, but takes commands via sockets from the regular Pi user, or anywhere else. It’s also got a comprehensive set of documentation. Unfortunately, despite its excellent quality and usefulness, it’s not packaged or distributed. It’s just sitting on GitHub. However, we (the Foundation) intend to do this packaging work and ship it with Raspbian in future. Watch this space. Or that space, maybe.
One amazing feature of pigpio is remote pin access. Because GPIO Zero has no dependencies, I can install and run it on my Ubuntu laptop (it would also run on Mac or Windows). I can open a shell, and type:
from gpiozero import LED from gpiozero.pins.pigpiod import PiGPIOPin pin = PiGPIOPin(2, host='192.168.0.2') led = LED(pin) led.blink()
So rather than creating an LED on pin 2, I create it on a reference to a remote pin elsewhere on the network. This is seriously cool and I look forward to this being used more broadly once
pigpio is packaged. See the pins docs for more information on the various pin implementations.
Development of v1.3 is under way. We’re planning to add:
- One-wire temperature sensor (in CamJam kit 2)
- DOTS board
- Composite robot interfaces (robots with sensors as a single object)
- More – feel free to make suggestions
See the v1.3 milestone for more information – and feel free to chip in with ideas, suggestions and code!
Join the *Zero revolution
The MicroPython API for the BBC micro:bit has been designed with a similar philosophy, and there’s now a NetworkZero library made by Tim Golden. You can read about it in his blog post. Nicholas Tollervey has created a Py-ZeroZero organisation on GitHub for discussion of this family of *Zero libraries and a description of our philosophies.
Dave Jones has gone above and beyond and he’s responsible for the vast majority of the code base (and the feature set). I can’t thank him enough for the voluntary work he’s done on the library.
Thanks also to Andrew Scheller, who’s made some great contributions to the code, and helped a lot by posting issues and commenting on commits and PRs. And to Martin O’Hanlon who helped create the holdable Button; to Schelto van Doorn, who added numerous ADC chips; and to everyone who’s used the library, given feedback, shared it with others or provided help with documentation, API design or usage suggestions. Finally thanks to Joan for pigpio.
GPIOzero rocks! #pipartypic.twitter.com/tRFSxyqKBY