The most reliable home automation project using Raspberry Pi isn't a cloud-dependent smart plug—it is a locally hosted, MQTT-driven GPIO relay node. By running your own broker and switching loads via the Pi's GPIO pins, you eliminate cloud latency, privacy concerns, and the inevitable 'device offline' errors when your ISP hiccups. This guide walks through building a 4-channel relay controller targeting the Raspberry Pi 5, addressing the specific silicon and OS changes introduced in the Bookworm release.

Project Spec Sheet & Difficulty Rating

ParameterSpecification
Target BoardRaspberry Pi 5 (8GB variant)
OS RequirementRaspberry Pi OS Bookworm (64-bit)
DifficultyIntermediate (Requires basic Linux & Python)
Estimated Time2 hours (Hardware 45m, Software 1h 15m)
Estimated Cost$95 - $110 USD

Hardware BOM & Pin Mapping

The Raspberry Pi 5 utilizes the new RP1 I/O controller chip, which changes how GPIO is accessed at the kernel level. Furthermore, the Pi 5 GPIO pins operate strictly at 3.3V logic. Feeding 5V logic back into a Pi 5 GPIO pin will fry the RP1 chip. Therefore, your relay module must be 3.3V logic compatible.

Parts List

  • Microcontroller: Raspberry Pi 5 (8GB RAM) - The 8GB variant handles local MQTT brokers (Mosquitto) and Home Assistant simultaneously without swapping.
  • Power Supply: Official Raspberry Pi 27W USB-C PD Power Supply (5V/5A) - Standard 5V/3A phone chargers will trigger brownout warnings on the Pi 5 under relay load.
  • Relay Module: 4-Channel 3.3V Low-Level Trigger Relay Module (Optocoupler isolated) - Do not use the standard blue 5V Songle relay modules without a logic level shifter.
  • Wiring: 22 AWG solid copper hook-up wire and female-to-female Dupont jumper cables.

Pin Mapping Table (BCM Numbering)

Raspberry Pi 5 Pin (BCM)Physical Pin #Relay Module PinFunction
3V31VCCLogic Power (3.3V)
GND6GNDCommon Ground
GPIO 1711IN1Relay 1 Control (Lighting)
GPIO 2713IN2Relay 2 Control (Fan)
GPIO 2215IN3Relay 3 Control (Valve)
GPIO 2316IN4Relay 4 Control (Spare)
⚠️ Mains Voltage Safety Warning: The relay module's screw terminals can switch up to 10A at 120V/240V AC. However, wiring mains voltage requires strict adherence to local electrical codes, proper enclosure grounding, and strain relief. If you are not comfortable with AC mains wiring, restrict the relay load side to low-voltage DC applications (e.g., 12V LED strips or 24V AC HVAC fan controls) and consult a licensed electrician for 120V+ installations.

Step-by-Step Wiring & Setup

  1. Power Down: Ensure the Raspberry Pi 5 is completely unplugged from the 27W USB-C PSU before touching any GPIO pins.
  2. Connect Logic Power: Connect Pi Physical Pin 1 (3V3) to the Relay Module VCC. Connect Pi Physical Pin 6 (GND) to the Relay Module GND.
  3. Connect Control Pins: Wire BCM 17, 27, 22, and 23 to IN1 through IN4 on the relay module.
  4. Install OS Dependencies: Boot your Pi 5 into Raspberry Pi OS Bookworm. Open the terminal and install the required backend for GPIO access and the MQTT client library:
    sudo apt update
    sudo apt install python3-rpi-lgpio python3-pip mosquitto mosquitto-clients
    pip3 install paho-mqtt gpiozero --break-system-packages
    Note: The python3-rpi-lgpio package is mandatory for Pi 5. The legacy RPi.GPIO library is deprecated and will fail on the RP1 chip.

Complete Python MQTT Control Code

This script targets the Raspberry Pi 5 (8GB). It uses gpiozero with the lgpio backend and paho-mqtt v2.0. It listens for MQTT payloads ('ON'/'OFF') on specific topics and toggles the relays accordingly.

import paho.mqtt.client as mqtt
from gpiozero import OutputDevice
from signal import pause
import logging
import sys

# --- PIN DEFINITIONS (BCM) ---
RELAY_PINS = {
    'home/lights': 17,
    'home/fan': 27,
    'home/valve': 22,
    'home/spare': 23
}

# --- MQTT CONFIGURATION ---
BROKER_IP = '192.168.1.100'  # Replace with your local Mosquitto broker IP
BROKER_PORT = 1883
CLIENT_ID = 'pi5_relay_node_01'

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Initialize Relays (Active Low for most 3.3V optocoupler modules)
relays = {}
try:
    for topic, pin in RELAY_PINS.items():
        # active_high=False means GPIO LOW turns the relay ON
        relays[topic] = OutputDevice(pin, active_high=False, initial_value=False)
        logging.info(f'Initialized relay on BCM {pin} for topic {topic}')
except Exception as e:
    logging.critical(f'GPIO Initialization Failed: {e}')
    sys.exit(1)

# --- PAHO MQTT V2.0 CALLBACKS ---
def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code == 0:
        logging.info('Connected to MQTT Broker successfully.')
        for topic in RELAY_PINS.keys():
            client.subscribe(f'{topic}/set')
            logging.info(f'Subscribed to {topic}/set')
    else:
        logging.error(f'MQTT Connection failed with reason code: {reason_code}')

def on_message(client, userdata, msg):
    topic = msg.topic.replace('/set', '')
    payload = msg.payload.decode('utf-8').strip().upper()
    
    if topic in relays:
        try:
            if payload == 'ON':
                relays[topic].on()
                logging.info(f'{topic} turned ON')
            elif payload == 'OFF':
                relays[topic].off()
                logging.info(f'{topic} turned OFF')
            else:
                logging.warning(f'Invalid payload received for {topic}: {payload}')
        except Exception as e:
            logging.error(f'Error toggling relay for {topic}: {e}')

# --- CLIENT SETUP ---
try:
    # Explicitly declare V2 API to prevent ValueError on modern paho-mqtt installs
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
    client.on_connect = on_connect
    client.on_message = on_message
    
    client.connect(BROKER_IP, BROKER_PORT, 60)
    logging.info('Starting MQTT loop...')
    client.loop_forever()
except KeyboardInterrupt:
    logging.info('Shutting down gracefully...')
except Exception as e:
    logging.critical(f'MQTT Client Error: {e}')
finally:
    for relay in relays.values():
        relay.close()

Debugging: First Three Things to Check When It Fails

When migrating older tutorials to the Pi 5 and Bookworm OS, builders inevitably hit two specific roadblocks. If your script crashes on startup, check these three things in order:

1. The GPIO Permission Error

Exact Error String: PermissionError: [Errno 13] Permission denied: '/dev/gpiochip0'

Ranked Causes & Fixes:

  1. User not in GPIO group (Most Likely): Bookworm removed default root-level GPIO access for security. Fix: Run sudo usermod -aG gpio $USER, then log out and log back in.
  2. Conflicting Daemon: Another service (like pigpiod or an old Home Assistant integration) has locked the RP1 chip. Fix: Run sudo systemctl stop pigpiod.
  3. Missing Backend: You forgot to install the RP1 driver. Fix: Run sudo apt install python3-rpi-lgpio.

2. The Paho MQTT Callback Error

Exact Error String: ValueError: Callback API version 2 is required for paho-mqtt 2.0

Cause: The Paho MQTT library updated to v2.0 in 2024, changing the on_connect signature. Most online tutorials still use v1.x syntax.

Fix: Ensure your client instantiation explicitly includes mqtt.CallbackAPIVersion.VERSION2 and that your on_connect function accepts reason_code and properties as arguments (as shown in the code block above). See the Paho MQTT Python v2.0 migration guide for deeper details.

3. The Brownout Throttling Warning

Symptom: The Pi 5 randomly reboots or drops the USB bus when multiple relays click simultaneously.

Cause: Mechanical relays draw a massive inrush current (up to 100mA per coil) when engaging. A standard 5V/3A USB-C charger cannot handle the Pi 5 baseline draw plus a 400mA relay spike.

Fix: Use the official 27W Raspberry Pi USB-C PD power supply, which guarantees 5A at 5V. If using a third-party supply, ensure it supports the 5V/5A PD profile, not just 9V/3A.

Extending or Simplifying the Build

To Simplify: If you do not want to run a dedicated MQTT broker (like Mosquitto), strip the networking layer and use gpiozero paired with a local FastAPI web server. This turns the Pi into a standalone REST API endpoint that you can trigger directly from a smartphone shortcut or a simple HTML dashboard on your LAN.

To Extend: Integrate this node into Home Assistant using MQTT Discovery. Instead of manually defining YAML switches in Home Assistant, modify the Python script to publish a JSON configuration payload to the homeassistant/switch/pi5_node_1/config topic on boot. Home Assistant will automatically detect the Pi 5 node and populate your dashboard with toggle switches. For deep integration, refer to the gpiozero documentation for Raspberry Pi 5 to explore PWM dimming if you swap the mechanical relays for MOSFET modules.

Frequently Asked Questions

Is a Raspberry Pi 5 overkill for a basic home automation project?

For a simple 4-channel relay switch, yes, the Pi 5's quad-core Cortex-A76 is overkill. A Raspberry Pi Zero 2 W or an ESP32 would handle the GPIO and MQTT tasks for a fraction of the cost and power draw. However, the Pi 5 is the correct choice if this single board will also host your local MQTT broker (Mosquitto), run Home Assistant in a Docker container, and process local voice commands via Whisper. Using the Pi 5 as a centralized 'brain' rather than just a dumb switch node justifies the $80+ price tag.

How do I keep my Raspberry Pi home automation project running after a power outage?

First, ensure your Python script is wrapped in a systemd service so it auto-starts on boot. Second, configure your Mosquitto broker to retain messages (retain=true), so when the Pi reconnects, it immediately knows the last known state of your switches. Finally, to survive the outage itself, power the Pi 5 via a 12V-to-5V USB-C PD buck converter connected to a 12V LiFePO4 battery backup system, or use a dedicated DC UPS HAT designed for the Pi 5's 5V/5A requirement.

Can I use this Raspberry Pi home automation project to switch 120V AC mains directly?

Electrically, the relay module's output side (Common, NO, NC) is completely isolated from the Pi's 3.3V logic side via optocouplers, meaning it can safely switch 120V or 240V AC. However, legally and safely, you cannot just leave exposed mains screw terminals on a workbench. You must mount the relay module in a grounded, fire-rated electrical enclosure, use proper ferrule crimps on the AC wires, and ensure the enclosure has strain reliefs. If you are wiring this into your home's branch circuits, NEC-style guidance dictates you must treat it as a permanent fixture; consult your local AHJ (Authority Having Jurisdiction) or a licensed electrician to ensure compliance.