6. Source/Values

GPIO Zero provides a method of using the declarative programming paradigm to connect devices together: feeding the values of one device into another, for example the values of a button into an LED:

from gpiozero import LED, Button
from signal import pause

led = LED(17)
button = Button(2)

led.source = button.values

pause()

which is equivalent to:

from gpiozero import LED, Button
from time import sleep

led = LED(17)
button = Button(2)

while True:
    led.value = button.value
    sleep(0.01)

Every device has a value property (the device’s current value). Input devices can only have their values read, but output devices can also have their value set to alter the state of the device:

>>> led = PWMLED(17)
>>> led.value  # LED is initially off
0.0
>>> led.on()  # LED is now on
>>> led.value
1.0
>>> led.value = 0  # LED is now off

Every device also has a values property (a generator continuously yielding the device’s current value). All output devices have a source property which can be set to any iterator. The device will iterate over the values provided, setting the device’s value to each element at a rate specified in the source_delay property.

_images/source_values.png

The most common use case for this is to set the source of an output device to the values of an input device, like the example above. A more interesting example would be a potentiometer controlling the brightness of an LED:

from gpiozero import PWMLED, MCP3008
from signal import pause

led = PWMLED(17)
pot = MCP3008()

led.source = pot.values

pause()

It is also possible to set an output device’s source to the values of another output device, to keep them matching:

from gpiozero import LED, Button
from signal import pause

red = LED(14)
green = LED(15)
button = Button(17)

red.source = button.values
green.source = red.values

pause()

The device’s values can also be processed before they are passed to the source:

_images/source_value_processing.png

For example:

from gpiozero import Button, LED
from signal import pause

def opposite(values):
    for value in values:
        yield not value

led = LED(4)
btn = Button(17)

led.source = opposite(btn.values)

pause()

Alternatively, a custom generator can be used to provide values from an artificial source:

_images/custom_generator.png

For example:

from gpiozero import LED
from random import randint
from signal import pause

def rand():
    while True:
        yield randint(0, 1)

led = LED(17)
led.source = rand()

pause()

If the iterator is infinite (i.e. an infinite generator), the elements will be processed until the source is changed or set to None.

If the iterator is finite (e.g. a list), this will terminate once all elements are processed (leaving the device’s value at the final element):

from gpiozero import LED
from signal import pause

led = LED(17)
led.source = [1, 0, 1, 1, 1, 0, 0, 1, 0, 1]

pause()

6.1. Composite devices

Most devices have a value range between 0 and 1. Some have a range between -1 and 1 (e.g. Motor). The value of a composite device is a namedtuple of such values. For example, the Robot class:

>>> from gpiozero import Robot
>>> robot = Robot(left=(14, 15), right=(17, 18))
>>> robot.value
RobotValue(left_motor=0.0, right_motor=0.0)
>>> tuple(robot.value)
(0.0, 0.0)
>>> robot.forward()
>>> tuple(robot.value)
(1.0, 1.0)
>>> robot.backward()
>>> tuple(robot.value)
(-1.0, -1.0)
>>> robot.value = (1, 1)  # robot is now driven forwards

6.2. Source Tools

GPIO Zero provides a set of ready-made functions for dealing with source/values, called source tools. These are available by importing from gpiozero.tools.

Some of these source tools are artificial sources which require no input:

_images/source_tool.png

In this example, random values between 0 and 1 are passed to the LED, giving it a flickering candle effect:

from gpiozero import PWMLED
from gpiozero.tools import random_values
from signal import pause

led = PWMLED(4)
led.source = random_values()
led.source_delay = 0.1

pause()

Some tools take a single source and process its values:

_images/source_tool_value_processor.png

In this example, the LED is lit only when the button is not pressed:

from gpiozero import Button, LED
from gpiozero.tools import negated
from signal import pause

led = LED(4)
btn = Button(17)

led.source = negated(btn.values)

pause()

Some tools combine the values of multiple sources:

_images/combining_sources.png

In this example, the LED is lit only if both buttons are pressed (like an AND gate):

from gpiozero import Button, LED
from gpiozero.tools import all_values
from signal import pause

button_a = Button(2)
button_b = Button(3)
led = LED(17)

led.source = all_values(button_a.values, button_b.values)

pause()