To control mains voltage or high-current DC loads with Raspberry Pi Python, use a 5V optocoupler-isolated relay module driven by GPIO17 (Physical Pin 11). The modern, robust software stack targets Raspberry Pi OS (Bookworm or later) using the gpiozero library with the lgpio backend. This guide provides the exact wiring, production-ready code, and bench-tested debugging paths for the most common hardware and software failures.

Project Specs & Decision-Forward Parts List

This build targets the Raspberry Pi 4 Model B (4GB). While the Raspberry Pi 5 is fully compatible via gpiozero, its RP1 southbridge chip routes GPIO through a different I2C expander, which can introduce microsecond latency and requires specific pull-up configurations on custom PCBs. For standard jumper-wire relay projects, the Pi 4 remains the most predictable baseline.

Component Exact Variant / Part Number Estimated Cost (2026) Why This Part
Microcontroller Raspberry Pi 4 Model B (4GB RAM) $55.00 Native 3.3V logic, massive community support, stable lgpio mapping.
Power Supply CanaKit 3.5A USB-C (Pi 4 Official) $20.00 Relay coils draw ~70mA; a 3.5A supply prevents brownouts when the coil energizes.
Switching Module Elegoo 5V 1-Channel Relay (SRD-05VDC-SL-C) $6.50 Includes onboard optocoupler and flyback diode. 10A @ 120VAC rating.
Wiring 20AWG Silicone Female-to-Female Jumpers $8.00 Silicone insulation won't melt if routed near the relay coil or mains terminals.

Decision Path: Which Switching Component to Use?

Do not default to a mechanical relay for every project. Use this decision tree to select the right switching hardware:

  • If switching < 30V DC at < 5A (e.g., LED strips, small motors): Pick a Logic-Level MOSFET module (IRLZ44N). It switches silently, handles PWM, and has no mechanical lifespan limit.
  • If switching 120V/240V AC or requiring strict galvanic isolation: Pick the Optocoupler-isolated 5V Relay Module (SRD-05VDC-SL-C). This is the default recommendation for mains-voltage hobby projects.
  • If switching high-power AC loads (>10A) frequently: Pick a Solid State Relay (SSR) like the Omron G3NA-220B. Mechanical relays will pit and weld their contacts under heavy inductive loads.

Pin Mapping & Wiring Procedure

⚠️ MAINS VOLTAGE SAFETY: Wiring the COM/NO/NC terminals to 120V/240V AC is lethal. De-energize the circuit at the breaker, verify dead with a non-contact voltage tester and a multimeter, and ensure all mains connections are housed in a grounded, insulated junction box. NEC-style guidance requires proper strain relief on all mains cables. If you are unsure, hire a licensed electrician.

The Raspberry Pi GPIO pins output 3.3V logic. The SRD-05VDC-SL-C relay module contains an optocoupler (usually a PC817) that safely bridges the 3.3V Pi logic and the 5V relay coil circuit.

Raspberry Pi Pin (BCM / Physical) Relay Module Pin Function
GPIO 17 (Physical Pin 11) IN (Signal) 3.3V logic trigger to the optocoupler LED.
5V Power (Physical Pin 2) VCC Provides 5V to the relay coil and optocoupler supply.
GND (Physical Pin 6) GND Common ground reference for the logic signal.
  1. Power Down: Disconnect the USB-C power from the Raspberry Pi.
  2. Connect Logic: Plug a female-to-female jumper from Pi Physical Pin 11 (GPIO17) to the Relay Module IN pin.
  3. Connect Ground: Plug a jumper from Pi Physical Pin 6 (GND) to the Relay Module GND pin.
  4. Connect Power: Plug a jumper from Pi Physical Pin 2 (5V) to the Relay Module VCC pin.
  5. Verify Jumper: Ensure the blue plastic jumper cap on the relay module is connecting VCC to JD-VCC. (Leave this in place for single-module setups powered directly from the Pi).
  6. Mains Wiring: Cut the hot (black/brown) wire of your AC load. Connect the source side to the relay COM (Common) terminal, and the load side to the NO (Normally Open) terminal. Leave the neutral and ground wires continuous and properly bonded.

The Raspberry Pi Python Control Code

Forget the legacy RPi.GPIO library. The modern standard for Raspberry Pi Python GPIO control is gpiozero, which abstracts pin numbering and handles cleanup automatically. On Raspberry Pi OS Bookworm, it uses the lgpio backend under the hood (gpiozero documentation).

Install the required packages via terminal:

sudo apt update
sudo apt install python3-gpiozero python3-lgpio

Save the following code as relay_control.py. This script includes explicit pin definitions, active-high logic configuration, and robust error handling to prevent the relay from getting stuck in the "ON" state if the script crashes.

import time
import signal
import sys
from gpiozero import OutputDevice

# --- PIN DEFINITIONS ---
# Using BCM numbering (GPIO17 = Physical Pin 11)
RELAY_PIN = 17

# Initialize the relay. 
# active_high=True means setting the pin HIGH (3.3V) triggers the optocoupler.
# initial_value=False ensures the relay starts in the OFF (Normally Open) state.
relay = OutputDevice(RELAY_PIN, active_high=True, initial_value=False)

def safe_exit(signum, frame):
    """Graceful shutdown handler to ensure relay turns off on Ctrl+C or kill."""
    print("\n[INFO] Shutdown signal received. De-energizing relay...")
    relay.off()
    relay.close()
    sys.exit(0)

# Bind SIGINT (Ctrl+C) and SIGTERM to the safe exit function
signal.signal(signal.SIGINT, safe_exit)
signal.signal(signal.SIGTERM, safe_exit)

def main():
    print(f"[INFO] Relay control started on GPIO {RELAY_PIN}.")
    print("[INFO] Press Ctrl+C to exit safely.")
    
    try:
        while True:
            # Energize relay (Closes COM to NO)
            relay.on()
            print("[STATE] Relay ON - Load energized.")
            time.sleep(5)
            
            # De-energize relay (Opens COM to NO)
            relay.off()
            print("[STATE] Relay OFF - Load disconnected.")
            time.sleep(5)
            
    except Exception as e:
        print(f"[ERROR] Unexpected failure: {e}")
        relay.off()
        relay.close()
        sys.exit(1)

if __name__ == "__main__":
    main()

Debugging: Exact Errors and the First Three Checks

When a Raspberry Pi Python GPIO project fails, it rarely fails silently. Here is the decision path for the most common bench errors.

Error 1: gpiozero.exc.BadPinFactory: Unable to load any default pin factory

This is the most common error on fresh Raspberry Pi OS Bookworm installs when running headless. It means gpiozero cannot find the underlying C-library to talk to the GPIO hardware.

  • Cause A (Most Likely): The lgpio Python bindings are missing. Fix: Run sudo apt install python3-lgpio.
  • Cause B: You are running the script inside a Docker container without passing the /dev/gpiochip0 device. Fix: Add --device /dev/gpiochip0 to your docker run command.

Error 2: RuntimeError: No access to /dev/mem. Try running with sudo

If you are forced to use the legacy RPi.GPIO library, or an older version of gpiozero falling back to RPi.GPIO, you will hit this memory access violation.

  • Cause A: The user is not in the gpio group. Fix: Run sudo usermod -aG gpio $USER, then log out and log back in.
  • Cause B: Running on a Pi 5 with legacy code. The Pi 5 RP1 chip does not map GPIO to /dev/mem the same way the Pi 4 BCM2711 does. Fix: Migrate to gpiozero with lgpio as shown in the code block above.

The First Three Things to Check When the Relay Fails to Click

If the Python script runs without errors, but the physical relay refuses to click and the load stays dead:

  1. Check the VCC Power Sag: The relay coil draws ~70mA when it first pulls in. If your Pi power supply is marginal, the 5V rail will dip below 4.5V, and the coil won't generate enough magnetic force to pull the armature. Measure the VCC pin with a multimeter while the script triggers. If it drops below 4.6V, power the relay module from a dedicated 5V 2A USB phone charger (tying the grounds together).
  2. Check the Logic Level Threshold: The Pi outputs 3.3V HIGH. Some cheap optocoupler modules require 4V+ to reliably turn off the internal LED (active-low logic confusion). If the relay clicks ON when the Pi boots (before the script runs) and turns OFF when the script says ON, your module is Active-Low. Change the code to OutputDevice(RELAY_PIN, active_high=False, initial_value=True).
  3. Check for the Flyback Diode: Look at the PCB. Is there a small black cylinder (1N4007 diode) wired in reverse-parallel across the relay coil? If not, the inductive kickback from the coil collapsing will eventually fry the optocoupler or the Pi's GPIO pin. Never use a bare relay without a flyback diode or snubber circuit.

Extending or Simplifying the Build

Once the baseline circuit is proven on the bench, you must decide whether to scale the hardware or simplify the architecture. Do not build custom mains-voltage relay boxes for simple home automation if off-the-shelf alternatives exist.

Goal Implementation Path When to Choose This
Simplify (No Mains Wiring) Buy a TP-Link Tapo P110 smart plug. Use the python-kasa library to control it over WiFi via Python. When you just need to turn a lamp or fan on/off and want to avoid NEC code compliance and junction boxes entirely.
Extend (Home Assistant) Add the paho-mqtt Python library. Publish GPIO state to an MQTT broker (Mosquitto) and subscribe to command topics. When integrating the Pi relay into a larger smart home ecosystem where physical switches and automations coexist.
Scale (Multiple Loads) Replace the Pi GPIO with an I2C MCP23017 16-channel I/O expander, driving ULN2803 Darlington arrays to switch multiple relays. When controlling irrigation valves or theater lighting where 17 GPIO pins are insufficient.

For 90% of hobbyist makers building a single or dual-load controller, the SRD-05VDC-SL-C module driven by gpiozero on a Pi 4 remains the definitive, most reliable setup. Secure your mains connections, use the lgpio backend, and always implement a software fallback to de-energize the coil on exit.