If you want to install Home Assistant on Raspberry Pi hardware while retaining direct access to the 40-pin GPIO header for local sensors, the standard Home Assistant OS (HAOS) image will block your path. HAOS locks down the host OS, making raw I2C/SPI access difficult without complex add-ons. The professional bench-standard for 2026 is to install Raspberry Pi OS Lite 64-bit and run Home Assistant Container via Docker. This gives you a rock-solid smart home hub and native Python access to the GPIO pins for local environmental monitoring.
This guide targets the Raspberry Pi 5 (8GB variant) running Raspberry Pi OS Lite 64-bit (Bookworm). We will pair it with an NVMe SSD for database longevity and wire a BME280 I2C sensor to push local climate data to Home Assistant via MQTT.
The Decision Path: Choosing Your Home Assistant Hardware
Before flashing an SD card, you need to select the right compute and storage tier. MicroSD cards will destroy themselves within a year under Home Assistant's constant database write load. Use this decision matrix to select your hardware.
| Criteria | Budget / Low Load | Standard / Medium Load | Pro / High Load (2026 Standard) |
|---|---|---|---|
| Compute Board | Raspberry Pi 4 (4GB) | Raspberry Pi 5 (4GB) | Raspberry Pi 5 (8GB) |
| Storage | High-Endurance microSD | USB 3.0 SATA SSD | NVMe M.2 via PCIe HAT |
| Zigbee/Matter | USB Dongle (Direct) | USB Dongle (Direct) | USB Dongle + Powered Hub |
| Use Case | < 20 devices, basic automations | 20-100 devices, standard dashboards | 100+ devices, local LLMs, heavy logging |
Exact Parts List and GPIO Pin Mapping
Here is the exact bill of materials and the physical pin mapping required for this build. We are integrating a Bosch BME280 sensor to monitor the server closet or living room environment directly from the Pi.
Bill of Materials
- Compute: Raspberry Pi 5 (8GB RAM) - ~$80 USD
- Case/Storage: Argon ONE V3 M.2 NVMe Raspberry Pi 5 Case - ~$45 USD
- Drive: WD Blue SN580 256GB NVMe M.2 2242 SSD - ~$35 USD
- Power: Official Raspberry Pi 27W USB-C Power Supply (Critical for Pi 5 PCIe stability) - ~$12 USD
- Sensor: Adafruit BME280 I2C/SPI Breakout (Product ID: 2652) - ~$15 USD
- Radios: Sonoff Zigbee 3.0 USB Dongle Plus (P-Version, CC2652P) - ~$25 USD
BME280 to Raspberry Pi 5 Pin Mapping
The Raspberry Pi 5 maintains the standard 40-pin layout. We are using the primary I2C bus (i2c-1). Ensure your BME280 breakout has the I2C pull-up resistors enabled (most Adafruit/SparkFun boards do by default).
| BME280 Pin | Pi 5 GPIO / Function | Physical Pin # | Wire Color (Standard) |
|---|---|---|---|
| VIN / VCC | 3.3V Power | Pin 1 | Red |
| GND | Ground | Pin 6 | Black |
| SDA | GPIO 2 (I2C1 SDA) | Pin 3 | Blue |
| SCL | GPIO 3 (I2C1 SCL) | Pin 5 | Yellow |
Step-by-Step: Install Home Assistant on Raspberry Pi
We bypass the standard Home Assistant OS installation to keep host-level I2C access. Follow these steps precisely.
- Flash the Base OS: Use Raspberry Pi Imager to flash Raspberry Pi OS Lite (64-bit) to your NVMe drive (via a USB NVMe enclosure) or a temporary microSD card. In the Imager's OS Customization settings, enable SSH, set your hostname to
ha-pi5, and configure your WiFi/Ethernet. - Boot and Enable PCIe/I2C: Boot the Pi. If using the Argon ONE V3, you must enable the PCIe interface. Edit the boot config:
sudo nano /boot/firmware/config.txt. Adddtparam=pciex1anddtparam=pciex1_gen=3to the bottom. Also ensuredtparam=i2c_arm=onis present. Reboot. - Verify I2C Hardware: Run
sudo i2cdetect -y 1. You should see76or77in the grid, confirming the BME280 is physically detected on the I2C bus. - Install Docker and Dependencies: Run the official Docker convenience script:
curl -fsSL https://get.docker.com | sh
Then install required packages:sudo apt-get install -y jq apparmor-utils. - Pull Home Assistant Container: Create your config directory and launch the container using the official Raspberry Pi 5 compatible image:
mkdir -p /opt/homeassistant/config sudo docker run -d \ --name homeassistant \ --privileged \ --restart=unless-stopped \ -e TZ=America/New_York \ -v /opt/homeassistant/config:/config \ -v /etc/localtime:/etc/localtime:ro \ --net=host \ ghcr.io/home-assistant/home-assistant:stable - Install Mosquitto MQTT Broker: Home Assistant needs a broker to receive the sensor data. Install it via Docker:
Note: Addmkdir -p /opt/mosquitto/config /opt/mosquitto/data /opt/mosquitto/log sudo docker run -d --name mosquitto --restart=unless-stopped -p 1883:1883 -v /opt/mosquitto/config:/mosquitto/config -v /opt/mosquitto/data:/mosquitto/data -v /opt/mosquitto/log:/mosquitto/log eclipse-mosquittolistener 1883andallow_anonymous trueto yourmosquitto.conffile for local testing, then restart the container. - Onboard HA: Navigate to
http://ha-pi5.local:8123. Create your admin account. Go to Settings > Devices & Services > Add Integration > MQTT. Point it to127.0.0.1on port 1883.
Extending the Build: I2C Sensor to MQTT Integration
With the host OS exposed, we can write a Python script to read the BME280 and publish the payload to Home Assistant. This script targets the Raspberry Pi 5 (8GB) running the 64-bit Bookworm architecture.
First, install the Python dependencies on the host OS:
sudo apt install python3-pip python3-smbus2
pip3 install paho-mqtt bme280
Create the file /opt/homeassistant/bme280_publisher.py and paste the following complete, compilable code:
#!/usr/bin/env python3
"""
BME280 to Home Assistant MQTT Publisher
Target Board: Raspberry Pi 5 (8GB) running Pi OS Lite 64-bit
Pin Definitions: SDA=GPIO2 (Pin 3), SCL=GPIO3 (Pin 5)
"""
import smbus2
import bme280
import paho.mqtt.client as mqtt
import time
import json
import sys
# --- Configuration & Pin Definitions ---
I2C_BUS = 1
BME280_I2C_ADDRESS = 0x76 # Use 0x77 if your breakout board has the alternate address
MQTT_BROKER_IP = "127.0.0.1"
MQTT_PORT = 1883
MQTT_TOPIC = "homeassistant/sensor/pi5_closet/state"
POLL_INTERVAL_SEC = 60
# --- MQTT Callbacks ---
def on_connect(client, userdata, flags, rc, properties=None):
if rc == 0:
print(f"[INFO] Connected to MQTT Broker at {MQTT_BROKER_IP}")
else:
print(f"[ERROR] MQTT Connection failed with code {rc}")
def on_publish(client, userdata, mid, rc, properties=None):
pass # Silent success
# --- Main Execution Loop ---
def main():
# Initialize I2C Bus and Sensor Calibration
try:
bus = smbus2.SMBus(I2C_BUS)
calibration_params = bme280.load_calibration_params(bus, BME280_I2C_ADDRESS)
print("[INFO] BME280 sensor calibrated successfully via I2C.")
except Exception as e:
print(f"[FATAL] I2C Initialization failed: {e}")
sys.exit(1)
# Initialize MQTT Client (Paho v2.0+ API)
client = mqtt.Client(client_id="pi5_bme280_publisher", protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_publish = on_publish
try:
client.connect(MQTT_BROKER_IP, MQTT_PORT, keepalive=120)
client.loop_start()
except Exception as e:
print(f"[FATAL] MQTT Connection failed: {e}")
sys.exit(1)
# Polling Loop
try:
while True:
try:
# Read sensor data
data = bme280.sample(bus, BME280_I2C_ADDRESS, calibration_params)
# Build HA-compatible JSON payload
payload = {
"temperature": round(data.temperature, 2),
"humidity": round(data.humidity, 2),
"pressure": round(data.pressure, 2)
}
# Publish to MQTT
result = client.publish(MQTT_TOPIC, json.dumps(payload), qos=1)
result.wait_for_publish()
print(f"[DATA] Published: {payload}")
except OSError as io_err:
print(f"[ERROR] I2C Read Failure: {io_err}. Check physical wiring.")
except Exception as loop_err:
print(f"[ERROR] Unexpected loop error: {loop_err}")
time.sleep(POLL_INTERVAL_SEC)
except KeyboardInterrupt:
print("\n[INFO] Stopping publisher...")
client.loop_stop()
client.disconnect()
bus.close()
if __name__ == "__main__":
main()
Run the script using python3 /opt/homeassistant/bme280_publisher.py. In Home Assistant, use the MQTT integration to listen to homeassistant/sensor/pi5_closet/state and configure your dashboard cards.
Troubleshooting: Boot and MQTT Failures
When working with bare-metal Pi OS and Docker, you will encounter specific errors. Here are the exact error strings and their ranked causes.
Error 1: OSError: [Errno 121] Remote I/O error
This occurs when the Python script attempts to read the BME280 via smbus2 but the hardware fails to acknowledge.
- Cause 1 (Most Likely): Loose Dupont wires on the physical Pin 3/Pin 5 header. I2C is highly sensitive to capacitance and poor contacts. Solder the header or use high-quality crimped connectors.
- Cause 2: Wrong I2C address. Run
sudo i2cdetect -y 1. If the sensor shows at0x77instead of0x76, update theBME280_I2C_ADDRESSvariable in the Python script. - Cause 3: I2C bus speed too high for long wire runs. Add
dtparam=i2c_arm_baudrate=10000to/boot/firmware/config.txtto slow the bus down to 10kHz.
Error 2: ConnectionRefusedError: [Errno 111] Connection refused
This occurs when the Python script tries to connect to the Mosquitto MQTT broker on localhost.
- Cause 1 (Most Likely): Mosquitto v2.0+ defaults to blocking external/unauthenticated connections. Ensure your
mosquitto.confexplicitly containslistener 1883andallow_anonymous true(for local testing only), and that you restarted the Docker container. - Cause 2: The Docker container crashed. Run
sudo docker psto verify Mosquitto is running. If not, check logs viasudo docker logs mosquitto. - Cause 3: Host firewall (UFW) blocking port 1883. Run
sudo ufw allow 1883/tcp.
1. Run
sudo i2cdetect -y 1 to verify the kernel sees the sensor at the hardware level.2. Run
sudo docker ps to ensure both the homeassistant and mosquitto containers are in the Up state.3. Verify your power supply. The Pi 5 will throttle the PCIe bus and USB ports if it detects a power supply under 27W, causing NVMe and Zigbee dongle dropouts. Check
vcgencmd get_throttled.
How to Extend or Simplify the Build
Depending on your long-term maintenance goals, you should make a deliberate choice on how to manage this stack moving forward.
To Simplify: Switch to ESPHome
Running a custom Python script on the host OS means you must manage systemd services, Python virtual environments, and OS updates manually. If you want a "set it and forget it" environment, drop the BME280 Python script entirely. Instead, wire the BME280 to an ESP32-WROOM-32 dev board and flash it with ESPHome. ESPHome integrates natively into the Home Assistant UI, handles WiFi reconnections, and pushes data via the native API without requiring a local MQTT broker or host-level Python scripts.
To Extend: Add a Thread/Matter Border Router
The Raspberry Pi 5 has the compute headroom to run local AI and advanced radio stacks. To extend this build into a 2026 Matter-ready hub, purchase a Sonoff Zigbee 3.0 USB Dongle Plus (P-Version) and flash it with the OpenThread Border Router firmware. Plug it into the Pi 5's USB 3.0 port (via a powered hub to prevent 2.4GHz USB interference) and install the Silicon Labs Multiprotocol add-on in Home Assistant. This allows your Pi to natively route Matter-over-Thread devices directly into your local network without relying on cloud hubs.






