Building an I2C Environmental Sensor HAT
Overview
This tutorial shows how to build a compact Raspberry Pi HAT for monitoring temperature, humidity, and pressure. The board keeps the wiring simple:
- A BME280 sensor breakout on the I2C bus
- 4.7k pull-up resistors on SDA and SCL
- Decoupling for a quiet 3.3V rail
- An optional OLED header that shares the same bus
BME280 integration
The BME280 should sit directly on the I2C bus with a clean 3.3V supply and a short return path. That keeps the sensor readable and avoids the kind of noise that can make environmental readings look jumpy.
For the build note, call out these details:
- wire VCC to 3.3V unless the breakout explicitly supports something else
- wire SDA and SCL to the Pi-compatible I2C pins
- keep pull-ups on the same board if the upstream bus does not already provide them
- add local decoupling near the sensor power pins
- note the address selection pin if the breakout exposes one
That gives readers a simple path from the schematic to the first sensor read.
Microcontroller code examples
If the reader wants to test the sensor outside the Pi first, include a small microcontroller sketch they can adapt. The goal is not to build a full firmware package here, just enough code to prove the bus and the sensor are alive.
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin();
}
void loop() {
Serial.println("Read BME280 data here");
delay(1000);
}
For a Python-based board, a tiny MicroPython example works just as well:
from machine import I2C, Pin
import time
i2c = I2C(0, sda=Pin(0), scl=Pin(1))
while True:
print("scan:", i2c.scan())
time.sleep(1)
These snippets keep the tutorial grounded in a real bring-up path: connect the bus, confirm the device responds, then move on to the full build.
Requirements
For this bounty, the board needs to cover:
- A BME280-based I2C sensor
- Pull-ups on SDA and SCL
- An optional OLED display connection
- A pin header for external access
- Schematic, code, and layout guidance
Why this circuit works
The BME280 is a good fit for environmental monitoring because it gives you temperature, humidity, and pressure over I2C. On a Raspberry Pi HAT, the bus should stay tidy:
- Use 3.3V logic
- Add pull-ups if the bus does not already provide them
- Keep decoupling close to the sensor power pins
- Route SDA and SCL as short, matched traces where practical
By default, many BME280 breakouts use I2C address 0x77. If the SDO pin is
tied low, the address can change to 0x76, so note that in the build guide if
you expect multiple sensors on the same bus.
Step 1: Place the sensor module
Start with the sensor module and expose the bus through a simple 4-pin header. That makes the board easy to test on a bench before any enclosure work.
Step 2: Add pull-ups and decoupling
I2C behaves best when the pull-ups live on the same board as the bus owner. For this layout, 4.7k is a safe default for the short traces on a HAT.
Step 3: Add the optional OLED header
The OLED is easiest to support as a second I2C header so the same firmware can drive both parts of the board.
Firmware example
The firmware side can stay small. A typical CircuitPython loop looks like this:
import board
import busio
import time
import adafruit_bme280.basic as adafruit_bme280
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x77)
while True:
print(
f"T={sensor.temperature:.1f} C",
f"H={sensor.humidity:.1f} %",
f"P={sensor.pressure:.1f} hPa",
)
time.sleep(2)
If you wire SDO low and use address 0x76, update the constructor to match.
PCB layout guidance
Keep these parts close together when you move from schematic to board:
- Put the sensor near an edge or vent opening if you want better airflow
- Keep the decoupling capacitor right next to the sensor power pins
- Run SDA and SCL together and avoid long stubs
- Place pull-ups near the bus owner, not out at the edge connector
- Leave space around the sensor so a later enclosure does not trap heat
What to check before publishing
- The sensor, pull-ups, and OLED header all share the same I2C bus
- The board stays on 3.3V logic
- The example code uses the same I2C address you document
- The layout makes room for airflow around the sensor