Learn

gpiozero on Raspberry Pi 4B and 5 — LEDs, PWM and Buttons in Python

Learn gpiozero, the beginner-friendly Python GPIO library Raspberry Pi recommends. Blink an LED, fade it with PWM and read a button — the same code runs on a Raspberry Pi 4B and a Raspberry Pi 5, in the free ZOLB simulator.

Try this directly in the free Raspberry Pi 4B simulator — no hardware or signup required. New to the GPIO header? Start with the interactive pinout guide.

What you’ll need

  • Raspberry Pi 4B or Raspberry Pi 5
  • LED
  • Resistor (220Ω)
  • Tact Switch (for the button part)

Step by step

gpiozero is the GPIO library Raspberry Pi recommends for beginners. It works on the Pi 4B and the Pi 5 (the older RPi.GPIO library does not work on a real Pi 5), so code written with gpiozero carries over between the two boards without changes. It talks about devices (an LED, a Button) instead of raw pins and HIGH/LOW.

  1. Drag a Raspberry Pi 4B (or a Raspberry Pi 5), an LED and a Resistor (220Ω) onto the Canvas. Wire Pi pin 37 → the resistor, the resistor → the LED's anode (long leg), and the LED's cathode → a Pi GND pin (for example pin 39).

gpiozero numbers pins by BCM (GPIO) number, not by physical position. Physical pin 37 is GPIO26, so in gpiozero code you write LED(26). This is different from the RPi.GPIO tutorials, which use GPIO.BOARD physical numbers.

  1. Go to the Code tab and write a blink script, then click Start:
from gpiozero import LED
from time import sleep
 
led = LED(26) # GPIO26 = physical pin 37
 
for _ in range(5):
led.on()
sleep(0.5)
led.off()
sleep(0.5)
  1. Watch the LED blink five times. The Console also shows the pin changes (Pin 37 → HIGH / LOW).
  2. Now fade the LED with PWM. Stop the simulation, replace the script with the one below and click Start. PWMLED takes a brightness from 0 (off) to 1 (full):
from gpiozero import PWMLED
from time import sleep
 
led = PWMLED(26)
 
for level in (0.1, 0.3, 0.6, 1.0, 0.6, 0.3, 0.0):
led.value = level
sleep(0.5)
  1. Add a Tact Switch: wire one side to Pi pin 40 (GPIO21) and the other side to a GND pin. gpiozero's Button turns on the Pi's internal pull-up for you, so pressing the button connects the pin to ground. Use this script and click Start, then click and hold the switch on the Canvas:
from gpiozero import LED, Button
from time import sleep
 
led = LED(26)
button = Button(21) # GPIO21 = physical pin 40
 
button.when_pressed = led.on
button.when_released = led.off
 
sleep(30) # keep the program running so it can react to the button
gpiozero classUse it forWorks in the simulator
LED, BuzzerOn/off outputsYes
PWMLED, RGBLEDBrightness and colour with PWMYes
Servo, AngularServo, MotorHobby servos and DC motorsYes
Button, DigitalInputDeviceSwitches and digital inputsYes
led.blink(), pulse(), source=, when_heldBackground effectsNot yet — these need threads
MotionSensor, DistanceSensor, LightSensor, LineSensorSensors polled in the backgroundNot yet — these need threads

For a servo, gpiozero's default pulse range (1–2 ms) moves the simulator's SG90 through about 45°–135°. Add min_pulse_width=0.5/1000 and max_pulse_width=2.5/1000 when you create it for the full 0°–180° sweep, for example AngularServo(13, min_angle=0, max_angle=180, min_pulse_width=0.5/1000, max_pulse_width=2.5/1000).

What “working correctly” looks like

  • The blink script turns the LED on and off five times, half a second each, then ends.
  • The PWM script changes the LED's brightness in steps instead of just on and off.
  • The button script lights the LED while you hold the switch and turns it off when you let go.
  • The same scripts behave identically whether you placed a Raspberry Pi 4B or a Raspberry Pi 5.

If something’s wrong

  • ModuleNotFoundError or a message about setting up gpiozero → the first run downloads gpiozero, so wait a few seconds and click Start again; check your internet connection.
  • The LED is on the wrong pin → gpiozero uses GPIO (BCM) numbers: LED(26) is physical pin 37 and Button(21) is physical pin 40.
  • NotImplementedError mentioning background threads → you used blink(), pulse(), source=, when_held or a sensor class that polls in the background. These aren't supported in the simulator yet; use a for or while loop with sleep() instead.
  • The button does nothing → make sure the other switch terminal goes to GND, and that the script keeps running (for example with sleep(30) or signal.pause()) so it can watch the pin.
  • The servo only moves part of the way → set min_pulse_width=0.5/1000 and max_pulse_width=2.5/1000, as described above.
  • Nothing happens when you press Start → check the LED's anode/cathode orientation and that the resistor is in series between pin 37 and the LED.