The 2026 Reality: Why the Pi 3 is an Edge Node, Not a Server

If you are trying to install the full Home Assistant OS (HAOS) supervisor stack on a Raspberry Pi 3 in 2026, you are setting yourself up for failure. Modern Home Assistant requires a minimum of 2GB RAM just to keep the Supervisor, Docker engine, and core database stable. The Pi 3 Model B+ maxes out at 1GB LPDDR2. When the RAM fills up, the system relies on the SD card for swap space, which destroys the card's flash cells via write-amplification within weeks. You will end up with a corrupted filesystem and a dead smart home.

However, the Raspberry Pi 3 for Home Assistant is far from e-waste. Its 40-pin GPIO header and low power draw make it the perfect dedicated Edge Node. By running a lightweight Raspberry Pi OS Lite installation and using Python to bridge physical GPIO sensors to your main HA server via MQTT, you offload hardware interfacing from your primary server while giving old hardware a permanent, stable job.

Home Assistant Node Comparison (2026 Baseline)
Board Variant RAM HAOS Primary Server Viability Edge Node / GPIO Bridge Viability Typical Used Market Price
Raspberry Pi 3B+ (BCM2837B0) 1GB Poor (Swap thrashing kills SD) Excellent (Low idle power, full GPIO) $15 - $25
Raspberry Pi 4 Model B 4GB / 8GB Good (Requires active cooling & USB SSD) Overkill (Wastes 5W idle power) $45 - $65
Raspberry Pi 5 8GB Excellent (PCIe NVMe boot supported) Poor (GPIO voltage quirks, high cost) $80 - $100
Intel N100 Mini PC 8GB+ Best (Native x86, Proxmox support) Terrible (No native GPIO header) $130 - $160 (New)

Hardware BOM and GPIO Pin Mapping

For this build, we are targeting the Raspberry Pi 3 Model B+ (BCM2837B0). We will wire an Adafruit PIR (Passive Infrared) motion sensor to the GPIO header and publish state changes to the main Home Assistant MQTT broker.

Parts List:
  • Compute: Raspberry Pi 3 Model B+ (1.4GHz quad-core, 1GB RAM)
  • Storage: 32GB SanDisk High Endurance microSD (Standard cards will fail; look for the 'High Endurance' or 'Max Endurance' label designed for dashcams and continuous logging)
  • Power: Official Raspberry Pi 5V 2.5A Micro-USB Power Supply (Do not use phone chargers; voltage drop triggers the Pi 3's brownout detector and disables the USB/GPIO rails)
  • Sensor: Adafruit PIR Motion Sensor (Product ID: 189) or generic HC-SR501
  • Wiring: 3x Female-to-Female jumper wires

Physical to BCM Pin Mapping Table

The Pi 3 uses the Broadcom (BCM) numbering system in software, which differs from the physical pin numbers on the header. The code below targets BCM 17.

Sensor Pin Pi 3 Physical Pin BCM GPIO Number Wire Color (Standard) Notes
VCC (Power) Pin 2 5V Power Rail Red PIR sensors require 5V, not 3.3V
GND (Ground) Pin 6 Ground Black Common ground reference
OUT (Signal) Pin 11 GPIO 17 Yellow Outputs 3.3V HIGH on motion detection

The Python MQTT Bridge Code

We use gpiozero for hardware abstraction (built into Raspberry Pi OS) and paho-mqtt for the network bridge. This script runs as a systemd service, reconnecting automatically if your main HA server reboots.

Install dependencies via terminal: sudo apt install python3-gpiozero python3-pip && pip3 install paho-mqtt==1.6.1

import time
import json
import paho.mqtt.client as mqtt
from gpiozero import MotionSensor
from signal import pause

# --- PIN & CONFIG DEFINITIONS ---
PIR_PIN = 17  # BCM 17 / Physical Pin 11
MQTT_BROKER = '192.168.1.50' # Replace with your main HA IP
MQTT_PORT = 1883
MQTT_USER = 'ha_mqtt_user'
MQTT_PASS = 'your_secure_password'
TOPIC = 'homeassistant/binary_sensor/pi3_pir/state'

# --- SENSOR INIT ---
# pull_up=False because the HC-SR501/Adafruit PIR drives the pin HIGH (3.3V) on motion
pir = MotionSensor(PIR_PIN, pull_up=False, queue_len=1)

# --- MQTT CALLBACKS ---
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print('Connected to HA MQTT Broker')
        # Publish initial state on connect
        current_state = 'ON' if pir.value else 'OFF'
        client.publish(TOPIC, current_state, retain=True)
    else:
        print(f'Connection failed with code {rc}')

# --- EVENT HANDLERS ---
def publish_motion():
    client.publish(TOPIC, 'ON', retain=True)
    print('Motion Detected -> Published ON')

def publish_clear():
    client.publish(TOPIC, 'OFF', retain=True)
    print('Motion Cleared -> Published OFF')

if __name__ == '__main__':
    # Using v1.6.1 API syntax for broad compatibility
    client = mqtt.Client(client_id='pi3_edge_node_pir')
    client.username_pw_set(MQTT_USER, MQTT_PASS)
    client.on_connect = on_connect

    try:
        client.connect(MQTT_BROKER, MQTT_PORT, 60)
    except ConnectionRefusedError as e:
        print(f'FATAL: {e}. Check broker IP and ensure Mosquitto is running.')
        exit(1)
    except Exception as e:
        print(f'Network Error: {e}')
        exit(1)

    # Bind GPIO events to MQTT publishers
    pir.when_motion = publish_motion
    pir.when_no_motion = publish_clear

    # Start non-blocking network loop
    client.loop_start()
    
    try:
        print('Edge node running. Press Ctrl+C to exit.')
        pause() # Keeps the main thread alive efficiently
    except KeyboardInterrupt:
        print('Shutting down edge node...')
        client.loop_stop()
        client.disconnect()

Debugging: Exact Errors and the 'First Three' Checklist

When bridging hardware to network protocols, failures usually happen at the boundary between the OS and the physical pins, or at the network firewall. If your script crashes or fails to report to Home Assistant, look for these exact error strings.

Common Error Strings and Fixes

  1. ConnectionRefusedError: [Errno 111] Connection refused
    Cause: The Python script reached the IP address, but the MQTT broker (Mosquitto) rejected the connection on port 1883.
    Fix: Verify that the Mosquitto add-on in Home Assistant is running. Check the Mosquitto configuration to ensure 'Allow anonymous connections' is false (if using passwords) and that the user credentials in the script match the HA MQTT integration credentials.
  2. gpiozero.exc.PinFactoryFallback: Falling back from rpigpio: No module named 'RPi.GPIO'
    Cause: You are running the script in a virtual environment that lacks the C-extensions for GPIO control, or you are using a 64-bit OS where legacy RPi.GPIO is deprecated.
    Fix: gpiozero will automatically fall back to lgpio or native factories on modern 64-bit Pi OS. If it fails entirely, ensure you installed the OS-level package via sudo apt install python3-gpiozero rather than just using pip.
  3. socket.error: [Errno 113] No route to host
    Cause: The Pi 3 cannot reach the main HA server at the network layer.
    Fix: Ping the HA IP from the Pi 3 terminal. If it fails, check if your router's AP Isolation (Client Isolation) is enabled, which prevents WiFi devices from talking to wired LAN devices.

The 'First Three' Hardware Checklist

Before rewriting code, verify these three physical realities when the sensor ghosts or drops offline:

  1. Measure the 5V Rail: Use a multimeter on Physical Pin 2 (5V) and Pin 6 (GND). If the reading is below 4.75V, the Pi 3's firmware will silently throttle the CPU and disable the USB/Network controller to save power. Upgrade your power supply and cable.
  2. Verify PIR Jumper Settings: The HC-SR501/Adafruit PIR has two potentiometers and a jumper. Ensure the jumper is set to 'H' (Retrigger mode). If set to 'L' (Non-retrigger), the sensor will lock out for 2.5 seconds after every pulse, causing missed motion events in HA.
  3. Check MQTT Retain Flags: If Home Assistant shows the sensor as 'Unknown' after a reboot, ensure retain=True is set in your client.publish() calls. This tells the broker to hold the last known state for when HA reconnects.

Extending or Simplifying the Build

Once your Pi 3 edge node is stable, you have two distinct paths depending on your project goals.

How to Extend: Add Zigbee2MQTT

The Pi 3B+ has enough USB bandwidth and CPU overhead to run a local Zigbee coordinator. Plug a Sonoff Zigbee 3.0 USB Dongle Plus (P-Version) into the Pi 3's USB port. Use a 1-meter USB 2.0 extension cable to move the dongle away from the Pi's WiFi/Bluetooth antenna (USB 3.0 and Pi WiFi interfere heavily with 2.4GHz Zigbee signals). You can then run a lightweight Docker container of Zigbee2MQTT on the Pi 3, turning it into a dedicated mesh router and coordinator bridge for your main HA server.

How to Simplify: Migrate to ESP32

If you realize you don't need the overhead of a full Linux OS just to read a single GPIO pin, simplify the build by migrating to an ESP32. Using ESPHome, you can flash a $6 ESP32-WROOM-32 dev board with a YAML configuration that natively integrates with the Home Assistant API over WiFi. This eliminates SD card corruption risks, Python dependency hell, and Linux OS patching, reducing the edge node to a pure, single-purpose microcontroller.

Safety & Code Caveat: When wiring 5V sensors to the Pi 3 GPIO, remember that the Pi's GPIO pins are strictly 3.3V tolerant. The PIR sensor OUT pin outputs 3.3V when powered by a 5V source with an onboard voltage regulator. If you use a raw 5V logic sensor, you must use a logic level shifter or a voltage divider, or you will permanently fry the BCM2837 silicon.