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
| Parameter | Specification |
|---|---|
| Target Board | Raspberry Pi 5 (8GB variant) |
| OS Requirement | Raspberry Pi OS Bookworm (64-bit) |
| Difficulty | Intermediate (Requires basic Linux & Python) |
| Estimated Time | 2 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 Pin | Function |
|---|---|---|---|
| 3V3 | 1 | VCC | Logic Power (3.3V) |
| GND | 6 | GND | Common Ground |
| GPIO 17 | 11 | IN1 | Relay 1 Control (Lighting) |
| GPIO 27 | 13 | IN2 | Relay 2 Control (Fan) |
| GPIO 22 | 15 | IN3 | Relay 3 Control (Valve) |
| GPIO 23 | 16 | IN4 | Relay 4 Control (Spare) |
Step-by-Step Wiring & Setup
- Power Down: Ensure the Raspberry Pi 5 is completely unplugged from the 27W USB-C PSU before touching any GPIO pins.
- 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.
- Connect Control Pins: Wire BCM 17, 27, 22, and 23 to IN1 through IN4 on the relay module.
- 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:
Note: Thesudo apt update sudo apt install python3-rpi-lgpio python3-pip mosquitto mosquitto-clients pip3 install paho-mqtt gpiozero --break-system-packagespython3-rpi-lgpiopackage is mandatory for Pi 5. The legacyRPi.GPIOlibrary 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:
- 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. - Conflicting Daemon: Another service (like
pigpiodor an old Home Assistant integration) has locked the RP1 chip. Fix: Runsudo systemctl stop pigpiod. - 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.






