If you are asking "what can I use a Raspberry Pi for" beyond running a retro gaming emulator or a Kodi media center, the most practical answer for a DIY maker is edge computing and home automation. While microcontrollers like the ESP32 are great for battery-powered sensor nodes, the Raspberry Pi excels as a central hub that aggregates local sensor data, runs local databases, and bridges protocols like I2C to MQTT without relying on cloud servers.
In this guide, we will build a multi-sensor I2C environmental monitor that reads temperature, humidity, pressure, and ambient light, then publishes the payload to a local MQTT broker. This project targets the Raspberry Pi 5 (4GB variant) running Raspberry Pi OS (64-bit Bookworm), though the code and wiring are fully backward-compatible with the Pi 4 and Pi 3B+.
Project Spec Sheet & Parts List
Estimated Time: 45 minutes
Estimated Cost: ~$82 USD
| Component | Exact Variant / Model | Approx. Cost | Notes |
|---|---|---|---|
| Single Board Computer | Raspberry Pi 5 (4GB RAM) | $60.00 | Pi 4 (4GB) also works perfectly. |
| Environmental Sensor | Bosch BME280 (I2C Breakout) | $8.00 | Ensure it has 3.3V logic and onboard pull-ups. |
| Light Sensor | Rohm BH1750 (I2C Breakout) | $4.00 | Measures ambient light in lux. |
| Wiring & Prototyping | Half-size breadboard + 22 AWG solid jumpers | $10.00 | Use 22 AWG solid core for secure breadboard contacts. |
Hardware Wiring & Pin Mapping
Both the BME280 and BH1750 communicate over the I2C bus. Because they have different default I2C addresses (typically 0x76 for the BME280 and 0x23 for the BH1750), we can wire them to the exact same I2C pins on the Pi's 40-pin header. Always reference Pinout.xyz if you are unsure about physical pin numbering versus BCM GPIO numbering.
| Pi 5 Physical Pin | BCM GPIO | Function | Sensor Connection |
|---|---|---|---|
| Pin 1 | N/A (Power) | 3.3V DC | BME280 VIN & BH1750 VCC |
| Pin 6 | N/A (Ground) | GND | BME280 GND & BH1750 GND |
| Pin 3 | GPIO 2 | I2C SDA1 | BME280 SDA & BH1750 SDA |
| Pin 5 | GPIO 3 | I2C SCL1 | BME280 SCL & BH1750 SCL |
Pro-Tip for Pi 5 Users: The Pi 5's I2C bus runs at 100kHz by default. If you experience slow read times or bus congestion, you can bump the baud rate to 400kHz (Fast Mode) by adding dtparam=i2c_arm_baudrate=400000 to your /boot/firmware/config.txt file and rebooting.
Python MQTT Code with Error Handling
This script uses the smbus2 and bme280 libraries to read the sensor, and the Eclipse Paho MQTT client to publish the data. Before running, install the dependencies via your terminal:
sudo apt update && sudo apt install python3-smbus i2c-tools
pip3 install bme280 paho-mqtt
import time
import json
import smbus2
import bme280
import paho.mqtt.client as mqtt
# --- HARDWARE PIN & BUS DEFINITIONS ---
# Raspberry Pi 5 / 4 uses I2C bus 1 (GPIO 2 / GPIO 3)
I2C_BUS_ID = 1
BME280_I2C_ADDR = 0x76 # Check your breakout board; some are 0x77
# --- MQTT CONFIGURATION ---
MQTT_BROKER_IP = "192.168.1.100"
MQTT_PORT = 1883
MQTT_TOPIC = "home/livingroom/environment"
# Initialize I2C Bus
bus = smbus2.SMBus(I2C_BUS_ID)
# Load BME280 calibration parameters from the sensor's internal ROM
try:
calibration_params = bme280.load_calibration_params(bus, BME280_I2C_ADDR)
print("BME280 calibration loaded successfully.")
except Exception as e:
print(f"Fatal: Could not load BME280 calibration. Check wiring. Error: {e}")
exit(1)
# MQTT Callback for connection verification
def on_connect(client, userdata, flags, rc):
if rc == 0:
print(f"Connected to MQTT Broker at {MQTT_BROKER_IP}")
else:
print(f"MQTT Connection failed with code {rc}")
client = mqtt.Client()
client.on_connect = on_connect
try:
client.connect(MQTT_BROKER_IP, MQTT_PORT, 60)
client.loop_start()
except Exception as e:
print(f"Warning: MQTT Broker unreachable. Data will only print to console. ({e})")
print("Starting sensor loop. Press Ctrl+C to exit.")
try:
while True:
try:
# Read BME280 Data
bme_data = bme280.sample(bus, BME280_I2C_ADDR, calibration_params)
payload = {
"temperature_c": round(bme_data.temperature, 2),
"humidity_pct": round(bme_data.humidity, 2),
"pressure_hpa": round(bme_data.pressure, 2),
"timestamp": time.time()
}
json_payload = json.dumps(payload)
print(f"Publishing: {json_payload}")
# Publish to MQTT
client.publish(MQTT_TOPIC, json_payload)
except OSError as oe:
# Catch specific I2C hardware timeouts
print(f"I2C Read Error: {oe}. Retrying in 5 seconds...")
time.sleep(10)
except KeyboardInterrupt:
print("\nStopping loop and disconnecting MQTT...")
client.loop_stop()
client.disconnect()
bus.close()
Debugging: "OSError: [Errno 121] Remote I/O error"
When working with I2C on the Raspberry Pi, you will inevitably encounter the dreaded OSError: [Errno 121] Remote I/O error. This is a low-level Linux kernel error indicating that the Pi sent a clock signal on the SCL line, but the sensor failed to pull the SDA line low to acknowledge (ACK) the request.
1. Run
i2cdetect -y 1 in the terminal. If the grid is entirely empty (only dashes), you have a physical layer problem, not a software problem.2. Verify you haven't swapped SDA and SCL. This is the #1 cause of Errno 121.
3. Check your power rail. Feeding 5V into a 3.3V BME280 breakout will fry the sensor's internal I2C pull-up resistors, permanently causing this timeout.
Ranked Causes for Errno 121:
- Loose Dupont/Jumper Wires: Breadboard contacts wear out. Wiggle the wires while running
i2cdetect. If the device address (e.g.,76) flickers in and out of the terminal grid, crimp a new wire or move to a fresh breadboard row. - Missing Pull-Up Resistors: The I2C protocol requires pull-up resistors on SDA and SCL. While the Pi has onboard 1.8kΩ pull-ups, they are sometimes too weak for long wire runs. If your sensor breakout board lacks onboard 4.7kΩ pull-ups, add them externally between 3.3V and the SDA/SCL lines.
- I2C Address Collision: If you wired two sensors that share the exact same default address (e.g., two BME280s both strapped to
0x76), the bus will lock up. Desolder the address jumper pad on one of the breakouts to shift it to0x77.
How to Extend or Simplify the Build
Depending on your infrastructure, you might want to scale this project up or down.
- Simplify (No MQTT Broker): If you don't want to run Home Assistant or Mosquitto, swap the MQTT publish block with a simple
sqlite3Python import to log the JSON payloads to a local.dbfile on the Pi's SD card. This makes the Pi a standalone data logger. - Extend (Add Actuation): Wire a 5V relay module to GPIO 17 (Pin 11). Add an
if payload["humidity_pct"] > 65.0:block in the Python loop to trigger the relay, which can switch on a bathroom exhaust fan or a dehumidifier automatically. - Extend (Add a Display): Connect an SSD1306 128x64 OLED display to the same I2C bus (address
0x3C) to show real-time readings locally without needing to check your phone.
Frequently Asked Questions
What can I use a Raspberry Pi for besides a media center?
Beyond OSMC or LibreELEC media centers, the Raspberry Pi is a powerhouse for local network services. You can use it as a Pi-hole (network-wide ad blocker), a local MQTT broker for IoT devices, a NAS (Network Attached Storage) using OpenMediaVault, or an edge-computing node running local AI models via TensorFlow Lite to process camera feeds without sending video to the cloud.
What can I use a Raspberry Pi for in home automation?
In home automation, the Pi acts as the "brain" or gateway. You can use it to run Home Assistant, which bridges incompatible protocols (like Zigbee, Z-Wave, and WiFi) into a single dashboard. It can also run Node-RED for visual flow-based programming, allowing you to create complex automation logic—like turning on porch lights only if the BH1750 light sensor reads below 20 lux AND the local weather API reports clear skies.
What can I use an old Raspberry Pi for?
If you have an older Raspberry Pi 3B+ or Pi Zero W sitting in a drawer, they are perfectly suited for low-overhead, always-on tasks. The Pi Zero W draws less than 1.5W, making it ideal for a dedicated MQTT broker, a digital signage controller, or a remote temperature probe in a greenhouse where running a full Pi 5 would be overkill and waste power. Just ensure you use a high-quality SD card or boot from USB, as older Pi models are notorious for corrupting SD cards during frequent write cycles.






