Skip to main content
Raspberry Pi HATs

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

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.

Schematic Circuit Preview

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.

Schematic Circuit Preview

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.

Schematic Circuit Preview

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