If you are building raspberry pi smart home projects in 2026, the default architecture has shifted. The days of running a Pi 3B+ headless with a messy web server are over. Modern smart home hubs require hardware acceleration, robust I/O isolation, and native MQTT integration to communicate with platforms like Home Assistant. The direct answer for a new build: use a Raspberry Pi 5 (4GB) running Raspberry Pi OS Bookworm, driving an optocoupler-isolated relay bank via MQTT, and reading environmental data over I2C.

This guide walks through building a 4-channel MQTT relay hub with a BME280 environmental sensor. We will cover the hardware decision matrix, the critical optocoupler wiring trap that destroys Pi logic boards, and the exact Python code required to navigate the Pi 5's new libgpiod backend.

The Decision Path: Which Pi for Your Smart Home Hub?

Do not default to the cheapest board on your workbench. Smart home hubs run 24/7, manage local network traffic, and often host Docker containers (like Zigbee2MQTT or Frigate). Use this decision matrix to select your board.

Board Variant RAM I/O & Network Verdict & Use Case
Raspberry Pi 3B+ 1GB USB 2.0, 2.4GHz WiFi only Reject. 1GB RAM chokes on modern Home Assistant OS. SD card corruption is highly likely under continuous logging.
Raspberry Pi 4 Model B 2GB / 4GB USB 3.0, Gigabit Ethernet Acceptable for legacy. Good for basic MQTT nodes, but lacks the PCIe lane for NVMe booting and runs hot without massive heatsinks.
Raspberry Pi 5 4GB / 8GB PCIe 2.0, Dual 4K, RTC DEFAULT PICK. The 4GB variant handles HAOS, MQTT brokers, and local LLMs effortlessly. Built-in RTC maintains time during network outages.
The Concrete Pick: Buy the Raspberry Pi 5 (4GB) paired with the official 27W USB-C PD power supply. The 27W PSU is mandatory; standard 5V/3A supplies will trigger USB current limiting on the Pi 5 when you attach relays and sensors.

Parts List & Spec Sheet

Here is the exact bill of materials for this build. Prices reflect typical 2026 market rates for genuine components.

Component Exact Variant / Model Est. Cost Why This Specific Part?
Microcontroller Raspberry Pi 5 (4GB) $60 RPi silicon RP1 I/O chip handles GPIO interrupts natively without CPU spiking.
Power Supply Official 27W USB-C PD (5V/5A) $12 Prevents brownouts when 4 relay coils energize simultaneously.
Cooling Pi 5 Active Cooler $5 PWM-controlled. Keeps SoC under 60°C in enclosed smart home panels.
Relay Module 4-Channel 5V Relay with Optocoupler (LC-04A) $8 Optocouplers physically isolate mains AC noise from the Pi's 3.3V logic.
Sensor Adafruit BME280 I2C (Part 2652) $15 Measures temp, humidity, and pressure. I2C avoids the SPI pin conflicts on Pi 5.

Pin Mapping & The Optocoupler Jumper Trap

Wiring a 5V relay module to a 3.3V logic board (like any Raspberry Pi) is where most hobbyists fry their GPIO pins. Standard relay boards feature a JDVCC jumper. If you leave this jumper in place and power the board from the Pi's 5V pin, the 5V logic from the optocoupler output can backfeed into the Pi's 3.3V GPIO header when the pin is pulled low.

The Fix: Remove the JDVCC jumper. Feed the relay coils (JDVCC and GND) from the Pi's 5V and GND pins. Feed the optocoupler LEDs (VCC and GND) from the Pi's 3.3V and GND pins. This ensures complete electrical isolation.

Mains Voltage Safety: The relay module switches up to 120V/240V AC. De-energize your breaker, verify dead with a CAT III multimeter, and ensure all mains terminals are covered with polycarbonate shields before testing. Local electrical codes may require a licensed electrician for permanent in-wall mains wiring.
Pi 5 GPIO (Physical Pin) Function Relay / Sensor Target Voltage Level
GPIO 5 (Pin 29) Relay 1 Control IN1 (Optocoupler LED) 3.3V Logic
GPIO 6 (Pin 31) Relay 2 Control IN2 (Optocoupler LED) 3.3V Logic
GPIO 13 (Pin 33) Relay 3 Control IN3 (Optocoupler LED) 3.3V Logic
GPIO 19 (Pin 35) Relay 4 Control IN4 (Optocoupler LED) 3.3V Logic
GPIO 2 (Pin 3) / GPIO 3 (Pin 5) I2C SDA / SCL BME280 Sensor 3.3V Logic
5V (Pin 2) / GND (Pin 6) Coil Power JDVCC / GND (Jumper Removed) 5V Power
3.3V (Pin 1) / GND (Pin 9) Opto LED Power VCC / GND (Optocoupler side) 3.3V Power

Python Control Code (MQTT & GPIO)

This script targets the Raspberry Pi 5 running Bookworm (64-bit). It uses gpiozero (which automatically leverages the rpi-lgpio backend on Bookworm) and Paho MQTT v2.0.

Install dependencies first:
sudo apt install python3-rpi-lgpio python3-smbus2
pip3 install paho-mqtt adafruit-circuitpython-bme280

import time
import json
import board
import adafruit_bme280
import paho.mqtt.client as mqtt
from gpiozero import OutputDevice
from paho.mqtt.enums import CallbackAPIVersion

# --- PIN DEFINITIONS ---
RELAY_PINS = {
    "relay_1": OutputDevice(5, active_high=False),  # Active low for most optocouplers
    "relay_2": OutputDevice(6, active_high=False),
    "relay_3": OutputDevice(13, active_high=False),
    "relay_4": OutputDevice(19, active_high=False)
}

# --- MQTT CONFIGURATION ---
MQTT_BROKER = "homeassistant.local"
MQTT_PORT = 1883
MQTT_USER = "pi_hub"
MQTT_PASS = "your_secure_password"
TOPIC_CMD = "smarthome/relays/+/set"
TOPIC_TELE = "smarthome/telemetry/environment"

def on_connect(client, userdata, flags, reason_code, properties):
    """Paho MQTT v2.0 connection callback."""
    if reason_code == 0:
        print("Connected to MQTT Broker successfully.")
        client.subscribe(TOPIC_CMD)
    else:
        print(f"MQTT Connection failed with code: {reason_code}")

def on_message(client, userdata, msg):
    """Handle incoming relay commands."""
    try:
        topic_parts = msg.topic.split('/')
        relay_name = topic_parts[2] # e.g., 'relay_1'
        payload = msg.payload.decode().upper()
        
        if relay_name in RELAY_PINS:
            if payload == "ON":
                RELAY_PINS[relay_name].on()
                print(f"{relay_name} ENGAGED")
            elif payload == "OFF":
                RELAY_PINS[relay_name].off()
                print(f"{relay_name} DISENGAGED")
    except Exception as e:
        print(f"Error processing MQTT message: {e}")

def main():
    # Initialize I2C Sensor
    try:
        i2c = board.I2C()
        bme280 = adafruit_bme280.basic.Adafruit_BME280_I2C(i2c, address=0x77)
        print("BME280 Sensor initialized on I2C.")
    except ValueError as e:
        print(f"BME280 Init Error: {e}. Check I2C address (0x76 vs 0x77).")
        bme280 = None

    # Initialize MQTT Client (Using v2 API)
    client = mqtt.Client(CallbackAPIVersion.VERSION2, client_id="Pi5_RelayHub")
    client.username_pw_set(MQTT_USER, MQTT_PASS)
    client.on_connect = on_connect
    client.on_message = on_message

    try:
        client.connect(MQTT_BROKER, MQTT_PORT, 60)
    except ConnectionRefusedError:
        print("MQTT Broker unreachable. Check network and Mosquitto service.")
        return

    client.loop_start()

    # Main Telemetry Loop
    try:
        while True:
            if bme280:
                telemetry = {
                    "temp_c": round(bme280.temperature, 2),
                    "humidity": round(bme280.relative_humidity, 2),
                    "pressure_hpa": round(bme280.pressure, 2)
                }
                client.publish(TOPIC_TELE, json.dumps(telemetry))
            
            # Sleep 60s between telemetry pushes to avoid broker spam
            time.sleep(60)
            
    except KeyboardInterrupt:
        print("Shutting down safely...")
    finally:
        client.loop_stop()
        client.disconnect()
        for relay in RELAY_PINS.values():
            relay.off()
            relay.close()

if __name__ == "__main__":
    main()

Debugging: "lgpio.error" and Pi 5 GPIO Failures

When migrating older smart home scripts to the Pi 5, you will inevitably hit the new GPIO subsystem. Bookworm replaced the legacy sysfs interface with libgpiod. If your code throws the following error, do not attempt to downgrade your OS; fix the backend.

lgpio.error: 'gpiochip4' is not a valid chip

This exact error string occurs because the Pi 5's RP1 I/O chip maps to gpiochip4, but legacy libraries (like RPi.GPIO) are hardcoded to look for gpiochip0 on the BCM2711 SoC.

Ranked Causes and Fixes

  1. Missing rpi-lgpio backend (Most Likely): gpiozero requires the rpi-lgpio package to translate commands to the Pi 5's hardware. Fix: Run sudo apt install python3-rpi-lgpio.
  2. Using Legacy RPi.GPIO: The RPi.GPIO library is effectively dead on Bookworm. Fix: Refactor your code to use gpiozero or direct lgpio bindings as shown in the script above.
  3. I2C Bus Mapping Collision: The Pi 5 uses I2C0 for the HAT EEPROM and I2C1 for the GPIO header. If you are using a HAT that hardcodes I2C0, the BME280 will fail to initialize. Fix: Wire raw sensors directly to Physical Pins 3 and 5 (I2C1), bypassing HAT headers.

The First Three Things to Check When It Fails

If your relays aren't clicking or Home Assistant isn't seeing the MQTT payloads, run this triage sequence:

  1. Verify OS Version: Run cat /etc/os-release. If it says "Bullseye", your libgpiod assumptions are wrong. You must be on Bookworm or newer for Pi 5 stability.
  2. Check I2C Interface Toggle: Bookworm moved I2C configuration. Run sudo raspi-config, navigate to Interface Options > I2C, and ensure it is explicitly enabled. Reboot after changing.
  3. Inspect MQTT ACLs: If the script connects but publishes nothing, your Mosquitto broker's Access Control List is blocking the smarthome/ topic. Check /etc/mosquitto/acl on your broker.

Extending and Simplifying the Build

A centralized Pi 5 hub is excellent for logic, but running 20-foot I2C or GPIO wires to remote rooms violates signal integrity limits and invites EMI noise. Here is how to scale the architecture correctly.

How to Simplify (Downscale)

If you only need to control a single HVAC damper or read one room's temperature, drop the Pi entirely. Use an ESP32-C3 SuperMini ($4). Flash it with ESPHome, which natively compiles YAML into C++ and pushes data directly to Home Assistant via the ESPHome API, eliminating the need for a standalone MQTT broker and Python scripts.

How to Extend (Upscale)

To expand this Pi 5 hub into a whole-home nerve center without running miles of copper wire:

  • Add a Zigbee Coordinator: Plug a Home Assistant SkyConnect (or Sonoff ZBDongle-P) into the Pi 5's USB 2.0 port. Use a 1-meter USB extension cable to move the dongle away from the Pi 5's USB 3.0 controller, which generates severe 2.4GHz RF interference that will cripple Zigbee mesh networks.
  • Remote Nodes via PoE: For remote relay control (e.g., garden lighting, garage doors), deploy Waveshare ESP32-S3 Ethernet boards powered via PoE. They communicate back to this Pi 5's MQTT broker over your existing CAT6 network, keeping mains voltage and logic completely localized to the remote enclosure.

By anchoring your smart home on the Pi 5's isolated I/O and modern MQTT standards, you eliminate the fragile web-scraping integrations of the past. Lock in your optocoupler wiring, respect the libgpiod backend, and let the broker handle the routing.