mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	This commit is a fairly major piece of work that abstracts all pin operations (function, state, edge detection, PWM, etc.) into a base "Pin" class which is then used by input/output/composite devices to perform all required configuration. The idea is to pave the way for I2C based IO extenders which can present additional GPIO ports with similar capabilities to the Pi's "native" GPIO ports. As a bonus it also abstracts away the reliance on the RPi.GPIO library to allow alternative pin implementations (e.g. using RPIO to take advantage of DMA based PWM), or even pure Python implementations.
		
			
				
	
	
		
			652 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			652 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| =======
 | |
| Recipes
 | |
| =======
 | |
| 
 | |
| .. currentmodule:: gpiozero
 | |
| 
 | |
| The following recipes demonstrate some of the capabilities of the gpiozero
 | |
| library. Please note that all recipes are written assuming Python 3. Recipes
 | |
| *may* work under Python 2, but no guarantees!
 | |
| 
 | |
| 
 | |
| Pin Numbering
 | |
| =============
 | |
| 
 | |
| This library uses Broadcom (BCM) pin numbering for the GPIO pins, as opposed
 | |
| to physical (BOARD) numbering. Unlike in the `RPi.GPIO`_ library, this is not
 | |
| configurable.
 | |
| 
 | |
| .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO
 | |
| 
 | |
| Any pin marked ``GPIO`` in the diagram below can be used for generic
 | |
| components:
 | |
| 
 | |
| .. image:: images/pin_layout.*
 | |
| 
 | |
| LED
 | |
| ===
 | |
| 
 | |
| .. image:: images/led.*
 | |
| 
 | |
| Turn an :class:`LED` on and off repeatedly::
 | |
| 
 | |
|     from gpiozero import LED
 | |
|     from time import sleep
 | |
| 
 | |
|     red = LED(17)
 | |
| 
 | |
|     while True:
 | |
|         red.on()
 | |
|         sleep(1)
 | |
|         red.off()
 | |
|         sleep(1)
 | |
| 
 | |
| Alternatively::
 | |
| 
 | |
|     from gpiozero import LED
 | |
|     from signal import pause
 | |
| 
 | |
|     red = LED(17)
 | |
| 
 | |
|     red.blink()
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     Reaching the end of a Python script will terminate the process and GPIOs
 | |
|     may be reset. Keep your script alive with :func:`signal.pause`. See
 | |
|     :ref:`keep-your-script-running` for more information.
 | |
| 
 | |
| 
 | |
| Button
 | |
| ======
 | |
| 
 | |
| .. image:: images/button.*
 | |
| 
 | |
| Check if a :class:`Button` is pressed::
 | |
| 
 | |
|     from gpiozero import Button
 | |
| 
 | |
|     button = Button(2)
 | |
| 
 | |
|     while True:
 | |
|         if button.is_pressed:
 | |
|             print("Button is pressed")
 | |
|         else:
 | |
|             print("Button is not pressed")
 | |
| 
 | |
| Wait for a button to be pressed before continuing::
 | |
| 
 | |
|     from gpiozero import Button
 | |
| 
 | |
|     button = Button(2)
 | |
| 
 | |
|     button.wait_for_press()
 | |
|     print("Button was pressed")
 | |
| 
 | |
| Run a function every time the button is pressed::
 | |
| 
 | |
|     from gpiozero import Button
 | |
|     from signal import pause
 | |
| 
 | |
|     def say_hello():
 | |
|         print("Hello!")
 | |
| 
 | |
|     button = Button(2)
 | |
| 
 | |
|     button.when_pressed = say_hello
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Button controlled LED
 | |
| =====================
 | |
| 
 | |
| Turn on an :class:`LED` when a :class:`Button` is pressed::
 | |
| 
 | |
|     from gpiozero import LED, Button
 | |
|     from signal import pause
 | |
| 
 | |
|     led = LED(17)
 | |
|     button = Button(2)
 | |
| 
 | |
|     button.when_pressed = led.on
 | |
|     button.when_released = led.off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Alternatively::
 | |
| 
 | |
|     from gpiozero import LED, Button
 | |
|     from signal import pause
 | |
| 
 | |
|     led = LED(17)
 | |
|     button = Button(2)
 | |
| 
 | |
|     led.source = button.values
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Traffic Lights
 | |
| ==============
 | |
| 
 | |
| A full traffic lights system.
 | |
| 
 | |
| Using a :class:`TrafficLights` kit like Pi-Stop::
 | |
| 
 | |
|     from gpiozero import TrafficLights
 | |
|     from time import sleep
 | |
| 
 | |
|     lights = TrafficLights(2, 3, 4)
 | |
| 
 | |
|     lights.green.on()
 | |
| 
 | |
|     while True:
 | |
|         sleep(10)
 | |
|         lights.green.off()
 | |
|         lights.amber.on()
 | |
|         sleep(1)
 | |
|         lights.amber.off()
 | |
|         lights.red.on()
 | |
|         sleep(10)
 | |
|         lights.amber.on()
 | |
|         sleep(1)
 | |
|         lights.green.on()
 | |
|         lights.amber.off()
 | |
|         lights.red.off()
 | |
| 
 | |
| Alternatively::
 | |
| 
 | |
|     from gpiozero import TrafficLights
 | |
|     from time import sleep
 | |
|     from signal import pause
 | |
| 
 | |
|     def traffic_light_sequence():
 | |
|         while True:
 | |
|             yield (0, 0, 1) # green
 | |
|             sleep(10)
 | |
|             yield (0, 1, 0) # amber
 | |
|             sleep(1)
 | |
|             yield (1, 0, 0) # red
 | |
|             sleep(10)
 | |
|             yield (1, 1, 0) # red+amber
 | |
|             sleep(1)
 | |
| 
 | |
|     lights.source = traffic_light_sequence()
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Using :class:`LED` components::
 | |
| 
 | |
|     from gpiozero import LED
 | |
|     from time import sleep
 | |
| 
 | |
|     red = LED(2)
 | |
|     amber = LED(3)
 | |
|     green = LED(4)
 | |
| 
 | |
|     green.on()
 | |
|     amber.off()
 | |
|     red.off()
 | |
| 
 | |
|     while True:
 | |
|         sleep(10)
 | |
|         green.off()
 | |
|         amber.on()
 | |
|         sleep(1)
 | |
|         amber.off()
 | |
|         red.on()
 | |
|         sleep(10)
 | |
|         amber.on()
 | |
|         sleep(1)
 | |
|         green.on()
 | |
|         amber.off()
 | |
|         red.off()
 | |
| 
 | |
| 
 | |
| Push button stop motion
 | |
| =======================
 | |
| 
 | |
| Capture a picture with the camera module every time a button is pressed::
 | |
| 
 | |
|     from gpiozero import Button
 | |
|     from picamera import PiCamera
 | |
| 
 | |
|     button = Button(2)
 | |
| 
 | |
|     with PiCamera() as camera:
 | |
|         camera.start_preview()
 | |
|         frame = 1
 | |
|         while True:
 | |
|             button.wait_for_press()
 | |
|             camera.capture('/home/pi/frame%03d.jpg' % frame)
 | |
|             frame += 1
 | |
| 
 | |
| See `Push Button Stop Motion`_ for a full resource.
 | |
| 
 | |
| 
 | |
| Reaction Game
 | |
| =============
 | |
| 
 | |
| When you see the light come on, the first person to press their button wins!
 | |
| 
 | |
| ::
 | |
| 
 | |
|     from gpiozero import Button, LED
 | |
|     from time import sleep
 | |
|     import random
 | |
| 
 | |
|     led = LED(17)
 | |
| 
 | |
|     player_1 = Button(2)
 | |
|     player_2 = Button(3)
 | |
| 
 | |
|     time = random.uniform(5, 10)
 | |
|     sleep(time)
 | |
|     led.on()
 | |
| 
 | |
|     while True:
 | |
|         if player_1.is_pressed:
 | |
|             print("Player 1 wins!")
 | |
|             break
 | |
|         if player_2.is_pressed:
 | |
|             print("Player 2 wins!")
 | |
|             break
 | |
| 
 | |
|     led.off()
 | |
| 
 | |
| See `Quick Reaction Game`_ for a full resource.
 | |
| 
 | |
| 
 | |
| GPIO Music Box
 | |
| ==============
 | |
| 
 | |
| Each button plays a different sound!
 | |
| 
 | |
| ::
 | |
| 
 | |
|     from gpiozero import Button
 | |
|     import pygame.mixer
 | |
|     from pygame.mixer import Sound
 | |
|     from signal import pause
 | |
| 
 | |
|     pygame.mixer.init()
 | |
| 
 | |
|     sound_pins = {
 | |
|         2: Sound("samples/drum_tom_mid_hard.wav"),
 | |
|         3: Sound("samples/drum_cymbal_open.wav"),
 | |
|     }
 | |
| 
 | |
|     buttons = [Button(pin) for pin in sound_pins]
 | |
|     for button in buttons:
 | |
|         sound = sound_pins[button.pin.number]
 | |
|         button.when_pressed = sound.play
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| See `GPIO Music Box`_ for a full resource.
 | |
| 
 | |
| 
 | |
| All on when pressed
 | |
| ===================
 | |
| 
 | |
| While the button is pressed down, the buzzer and all the lights come on.
 | |
| 
 | |
| :class:`FishDish`::
 | |
| 
 | |
|     from gpiozero import FishDish
 | |
|     from signal import pause
 | |
| 
 | |
|     fish = FishDish()
 | |
| 
 | |
|     fish.button.when_pressed = fish.on
 | |
|     fish.button.when_released = fish.off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Ryanteck :class:`TrafficHat`::
 | |
| 
 | |
|     from gpiozero import TrafficHat
 | |
|     from signal import pause
 | |
| 
 | |
|     th = TrafficHat()
 | |
| 
 | |
|     th.button.when_pressed = th.on
 | |
|     th.button.when_released = th.off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Using :class:`LED`, :class:`Buzzer`, and :class:`Button` components::
 | |
| 
 | |
|     from gpiozero import LED, Buzzer, Button
 | |
|     from signal import pause
 | |
| 
 | |
|     button = Button(2)
 | |
|     buzzer = Buzzer(3)
 | |
|     red = LED(4)
 | |
|     amber = LED(5)
 | |
|     green = LED(6)
 | |
| 
 | |
|     things = [red, amber, green, buzzer]
 | |
| 
 | |
|     def things_on():
 | |
|         for thing in things:
 | |
|             thing.on()
 | |
| 
 | |
|     def things_off():
 | |
|         for thing in things:
 | |
|             thing.off()
 | |
| 
 | |
|     button.when_pressed = things_on
 | |
|     button.when_released = things_off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| RGB LED
 | |
| =======
 | |
| 
 | |
| Making colours with an :class:`RGBLED`::
 | |
| 
 | |
|     from gpiozero import RGBLED
 | |
|     from time import sleep
 | |
| 
 | |
|     led = RGBLED(red=9, green=10, blue=11)
 | |
| 
 | |
|     led.red = 1  # full red
 | |
|     sleep(1)
 | |
|     led.red = 0.5  # half red
 | |
|     sleep(1)
 | |
| 
 | |
|     led.color = (0, 1, 0)  # full green
 | |
|     sleep(1)
 | |
|     led.color = (1, 0, 1)  # magenta
 | |
|     sleep(1)
 | |
|     led.color = (1, 1, 0)  # yellow
 | |
|     sleep(1)
 | |
|     led.color = (0, 1, 1)  # cyan
 | |
|     sleep(1)
 | |
|     led.color = (1, 1, 1)  # white
 | |
|     sleep(1)
 | |
| 
 | |
|     led.color = (0, 0, 0)  # off
 | |
|     sleep(1)
 | |
| 
 | |
|     # slowly increase intensity of blue
 | |
|     for n in range(100):
 | |
|         led.blue = n/100
 | |
|         sleep(0.1)
 | |
| 
 | |
| 
 | |
| Motion sensor
 | |
| =============
 | |
| 
 | |
| .. image:: images/motion-sensor.*
 | |
| 
 | |
| Light an :class:`LED` when a :class:`MotionSensor` detects motion::
 | |
| 
 | |
|     from gpiozero import MotionSensor, LED
 | |
|     from signal import pause
 | |
| 
 | |
|     pir = MotionSensor(4)
 | |
|     led = LED(16)
 | |
| 
 | |
|     pir.when_motion = led.on
 | |
|     pir.when_no_motion = led.off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Light sensor
 | |
| ============
 | |
| 
 | |
| .. IMAGE TBD
 | |
| 
 | |
| Have a :class:`LightSensor` detect light and dark::
 | |
| 
 | |
|     from gpiozero import LightSensor
 | |
| 
 | |
|     sensor = LightSensor(18)
 | |
| 
 | |
|     while True:
 | |
|         sensor.wait_for_light()
 | |
|         print("It's light! :)")
 | |
|         sensor.wait_for_dark()
 | |
|         print("It's dark :(")
 | |
| 
 | |
| Run a function when the light changes::
 | |
| 
 | |
|     from gpiozero import LightSensor, LED
 | |
|     from signal import pause
 | |
| 
 | |
|     sensor = LightSensor(18)
 | |
|     led = LED(16)
 | |
| 
 | |
|     sensor.when_dark = led.on
 | |
|     sensor.when_light = led.off
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Or make a :class:`PWMLED` change brightness according to the detected light
 | |
| level::
 | |
| 
 | |
|     from gpiozero import LightSensor, LED
 | |
|     from signal import pause
 | |
| 
 | |
|     sensor = LightSensor(18)
 | |
|     led = PWMLED(16)
 | |
| 
 | |
|     led.source = sensor.values
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Motors
 | |
| ======
 | |
| 
 | |
| .. IMAGE TBD
 | |
| 
 | |
| Spin a :class:`Motor` around forwards and backwards::
 | |
| 
 | |
|     from gpiozero import Motor
 | |
|     from time import sleep
 | |
| 
 | |
|     motor = Motor(forward=4, back=14)
 | |
| 
 | |
|     while True:
 | |
|         motor.forward()
 | |
|         sleep(5)
 | |
|         motor.backward()
 | |
|         sleep(5)
 | |
| 
 | |
| 
 | |
| Robot
 | |
| =====
 | |
| 
 | |
| .. IMAGE TBD
 | |
| 
 | |
| Make a :class:`Robot` drive around in (roughly) a square::
 | |
| 
 | |
|     from gpiozero import Robot
 | |
|     from time import sleep
 | |
| 
 | |
|     robot = Robot(left=(4, 14), right=(17, 18))
 | |
| 
 | |
|     for i in range(4):
 | |
|         robot.forward()
 | |
|         sleep(10)
 | |
|         robot.right()
 | |
|         sleep(1)
 | |
| 
 | |
| 
 | |
| Button controlled robot
 | |
| =======================
 | |
| 
 | |
| Use four GPIO buttons as forward/back/left/right controls for a robot::
 | |
| 
 | |
|     from gpiozero import RyanteckRobot, Button
 | |
|     from signal import pause
 | |
| 
 | |
|     robot = RyanteckRobot()
 | |
| 
 | |
|     left = Button(26)
 | |
|     right = Button(16)
 | |
|     fw = Button(21)
 | |
|     bw = Button(20)
 | |
| 
 | |
|     fw.when_pressed = robot.forward
 | |
|     fw.when_released = robot.stop
 | |
| 
 | |
|     left.when_pressed = robot.left
 | |
|     left.when_released = robot.stop
 | |
| 
 | |
|     right.when_pressed = robot.right
 | |
|     right.when_released = robot.stop
 | |
| 
 | |
|     bw.when_pressed = robot.backward
 | |
|     bw.when_released = robot.stop
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Keyboard controlled robot
 | |
| =========================
 | |
| 
 | |
| .. XXX Rewrite this using curses (to avoid evdev dep, which isn't packaged
 | |
|    on Rapsbian)
 | |
| 
 | |
| Use up/down/left/right keys to control a robot::
 | |
| 
 | |
|     from gpiozero import RyanteckRobot
 | |
|     from evdev import InputDevice, list_devices, ecodes
 | |
| 
 | |
|     robot = RyanteckRobot()
 | |
| 
 | |
|     devices = [InputDevice(device) for device in list_devices()]
 | |
|     keyboard = devices[0]  # this may vary
 | |
| 
 | |
|     keypress_actions = {
 | |
|         ecodes.KEY_UP: robot.forward,
 | |
|         ecodes.KEY_DOWN: robot.backward,
 | |
|         ecodes.KEY_LEFT: robot.left,
 | |
|         ecodes.KEY_RIGHT: robot.right,
 | |
|     }
 | |
| 
 | |
|     for event in keyboard.read_loop():
 | |
|         if event.type == ecodes.EV_KEY:
 | |
|             if event.value == 1:  # key down
 | |
|                 keypress_actions[event.code]()
 | |
|             if event.value == 0:  # key up
 | |
|                 robot.stop()
 | |
| 
 | |
| 
 | |
| Motion sensor robot
 | |
| ===================
 | |
| 
 | |
| Make a robot drive forward when it detects motion::
 | |
| 
 | |
|     from gpiozero import Robot, MotionSensor
 | |
|     from signal import pause
 | |
| 
 | |
|     robot = Robot(left=(4, 14), right=(17, 18))
 | |
|     pir = MotionSensor(5)
 | |
| 
 | |
|     pir.when_motion = robot.forward
 | |
|     pir.when_no_motion = robot.stop
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Alternatively::
 | |
| 
 | |
|     from gpiozero import Robot, MotionSensor
 | |
|     from signal import pause
 | |
| 
 | |
|     robot = Robot(left=(4, 14), right=(17, 18))
 | |
|     pir = MotionSensor(5)
 | |
| 
 | |
|     robot.source = zip(pir.values, pir.values)
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| 
 | |
| Potentiometer
 | |
| =============
 | |
| 
 | |
| .. IMAGE TBD
 | |
| 
 | |
| Continually print the value of a potentiometer (values between 0 and 1)
 | |
| connected to a :class:`MCP3008` analog to digital converter::
 | |
| 
 | |
|     from gpiozero import MCP3008
 | |
| 
 | |
|     while True:
 | |
|         with MCP3008(channel=0) as pot:
 | |
|             print(pot.value)
 | |
| 
 | |
| 
 | |
| Measure temperature with an ADC
 | |
| ===============================
 | |
| 
 | |
| .. IMAGE TBD
 | |
| 
 | |
| Wire a TMP36 temperature sensor to the first channel of an :class:`MCP3008`
 | |
| analog to digital converter::
 | |
| 
 | |
|     from gpiozero import MCP3008
 | |
|     from time import sleep
 | |
| 
 | |
|     def convert_temp(gen):
 | |
|         for value in gen:
 | |
|             yield (value * 3.3 - 0.5) * 100
 | |
| 
 | |
|     adc = MCP3008(channel=0)
 | |
| 
 | |
|     for temp in convert_temp(adc.values):
 | |
|         print('The temperature is', temp, 'C')
 | |
|         sleep(1)
 | |
| 
 | |
| 
 | |
| Full color LED controlled by 3 potentiometers
 | |
| =============================================
 | |
| 
 | |
| Wire up three potentiometers (for red, green and blue) and use each of their
 | |
| values to make up the colour of the LED::
 | |
| 
 | |
|     from gpiozero import RGBLED, MCP3008
 | |
| 
 | |
|     led = RGBLED(red=2, green=3, blue=4)
 | |
|     red_pot = MCP3008(channel=0)
 | |
|     green_pot = MCP3008(channel=1)
 | |
|     blue_pot = MCP3008(channel=2)
 | |
| 
 | |
|     while True:
 | |
|         led.red = red_pot.value
 | |
|         led.green = green_pot.value
 | |
|         led.blue = blue_pot.value
 | |
| 
 | |
| Alternatively, the following example is identical, but uses the
 | |
| :attr:`~SourceMixin.source` property rather than a :keyword:`while` loop::
 | |
| 
 | |
|     from gpiozero import RGBLED, MCP3008
 | |
|     from signal import pause
 | |
| 
 | |
|     led = RGBLED(2, 3, 4)
 | |
|     red_pot = MCP3008(0)
 | |
|     green_pot = MCP3008(1)
 | |
|     blue_pot = MCP3008(2)
 | |
| 
 | |
|     led.source = zip(red_pot.values, green_pot.values, blue_pot.values)
 | |
| 
 | |
|     pause()
 | |
| 
 | |
| Please note the example above requires Python 3. In Python 2, :func:`zip`
 | |
| doesn't support lazy evaluation so the script will simply hang.
 | |
| 
 | |
| 
 | |
| .. _Push Button Stop Motion: https://www.raspberrypi.org/learning/quick-reaction-game/
 | |
| .. _Quick Reaction Game: https://www.raspberrypi.org/learning/quick-reaction-game/
 | |
| .. _GPIO Music Box: https://www.raspberrypi.org/learning/gpio-music-box/
 | |
| 
 |