Last updated September 2026. Some links on this page may be affiliate links, which means RPi4U may earn a small commission at no extra cost to you.
By the end of this project you will have a small Raspberry Pi that measures temperature, humidity and air pressure once a minute and saves every reading to a spreadsheet-friendly CSV file. It starts by itself whenever the Pi powers up, so you can tuck it somewhere and forget about it.
The sensor is a SparkFun Qwiic BME280, which plugs in with a single four-wire cable. There is no soldering on the sensor side and no breadboard. It is a good first step into I2C sensors, Python and running your own code as a background service.
At a glance
| Difficulty | Intermediate |
| Time | About 60 minutes |
| Works on | Pi 5 · Pi 4 · Zero 2 W |
| Parts cost (approx, US) | About $52 (Zero 2 W $15, BME280 $17, Qwiic cable $2, power supply $8, microSD card $10) |
What you need
- Raspberry Pi Zero 2 W with a soldered 40-pin header (a Pi 4 or Pi 5 also works). The plain Zero 2 W ships without header pins, so either buy the “WH” version with the header already fitted or solder one on.
- Micro-USB power supply for the Zero 2 W (or the official USB-C supply for a Pi 4 or Pi 5)
- microSD card, 16GB or larger
- SparkFun Qwiic BME280 atmospheric sensor breakout
- SparkFun Flexible Qwiic Cable with female jumper ends (4-pin)
- Optional: a few male-to-female jumper wires to add extra length between the sensor and the Pi
- A computer with a microSD card reader to flash the card and connect over SSH
- Wi-Fi network name and password
Step 1: Flash Raspberry Pi OS
The current Raspberry Pi OS is based on Debian “Trixie”. Because this project runs without a screen, the Lite (no desktop) version is the best fit, especially on the Zero 2 W with its 512MB of RAM.
- Install Raspberry Pi Imager on your computer and insert the microSD card.
- Choose your Pi model, then pick Raspberry Pi OS Lite (64-bit) from the operating system list.
- In the customization settings, set a hostname such as
weatherpi, create a username and password, enter your Wi-Fi details and turn on SSH. - Write the card, put it in the Pi and power it on. The first boot takes a few minutes.
- From your computer, connect with
ssh yourname@weatherpi.local, using the username you picked.
Bring everything up to date before you start:
sudo apt update
sudo apt full-upgrade -y
Shut the Pi down with sudo poweroff and unplug it before wiring anything.
Step 2: Wire the sensor
Plug the small Qwiic connector into either Qwiic port on the BME280 board. The other end has four loose female jumpers. SparkFun uses the same color code on every Qwiic cable, so connect them to the Pi’s header like this:
| Wire color | Signal | Pi physical pin |
| Black | GND | Pin 6 (or pin 9) |
| Red | 3.3V | Pin 1 (3V3) |
| Blue | SDA | Pin 3 (GPIO2) |
| Yellow | SCL | Pin 5 (GPIO3) |
If you are unsure which pin is which, compare your board with a diagram on pinout.xyz. Pin 1 is the one with a square solder pad on the underside of the board. Use the 3.3V pin, never 5V, because the BME280 is a 3.3V part. You do not need pull-up resistors, since the Pi already has them on GPIO2 and GPIO3.
Placement matters. The Pi’s processor gets warm, and a sensor sitting right on top of it will read several degrees too high. Let the sensor hang at the end of the cable, away from the board. If it still reads warm, add jumper wires for more distance. Outdoors, keep it shaded and out of the rain but with free airflow, for example inside a vented radiation shield, never in a sealed box.
Step 3: Enable I2C and find the sensor
Power the Pi back on, reconnect over SSH and turn on the I2C bus:
- Run
sudo raspi-config. - Choose Interface Options, then I2C.
- Answer Yes to enabling the I2C interface, then select Finish.
If you prefer a single command, sudo raspi-config nonint do_i2c 0 does the same thing. Next, install the I2C tools and scan the bus:
sudo apt install -y i2c-tools
i2cdetect -y 1
You should see 77 in the grid. That is the SparkFun board’s default address. If someone has cut the ADR jumper on the back of the board, it shows up as 76 instead. An empty grid means a wiring problem, so recheck Step 2.
Step 4: Set up Python
Since Bookworm, Raspberry Pi OS blocks pip from installing into the system Python, so you need a virtual environment. This project uses Adafruit’s maintained BME280 library, which runs on the Pi through Adafruit’s Blinka compatibility layer.
sudo apt install -y python3-venv
mkdir ~/weather
cd ~/weather
python3 -m venv env --system-site-packages
source env/bin/activate
pip install --upgrade adafruit-blinka adafruit-circuitpython-bme280
The --system-site-packages option lets the environment see GPIO packages that Raspberry Pi OS already provides. Installing can take several minutes on a Zero 2 W.
Step 5: Write the logging script
Create the script with nano ~/weather/logger.py and paste in the following:
#!/usr/bin/env python3
"""Read a BME280 once a minute and append the results to a CSV file."""
import csv
import time
from datetime import datetime
from pathlib import Path
import board
from adafruit_bme280 import basic as adafruit_bme280
ADDRESS = 0x77 # change to 0x76 if the ADR jumper is cut
INTERVAL = 60 # seconds between readings
CSV_PATH = Path(__file__).resolve().parent / "readings.csv"
HEADER = ["timestamp", "temp_c", "temp_f", "humidity_pct", "pressure_hpa"]
sensor = adafruit_bme280.Adafruit_BME280_I2C(board.I2C(), address=ADDRESS)
if not CSV_PATH.exists():
with CSV_PATH.open("w", newline="") as f:
csv.writer(f).writerow(HEADER)
while True:
temp_c = sensor.temperature
row = [
datetime.now().isoformat(timespec="seconds"),
round(temp_c, 2),
round(temp_c * 9 / 5 + 32, 2),
round(sensor.relative_humidity, 1),
round(sensor.pressure, 1),
]
with CSV_PATH.open("a", newline="") as f:
csv.writer(f).writerow(row)
print(row, flush=True)
time.sleep(INTERVAL)
Save with Ctrl+O, Enter, then exit with Ctrl+X. Test it while the virtual environment is still active:
python ~/weather/logger.py
A line of readings should print right away and then once a minute. Breathe on the sensor and the humidity should jump. Press Ctrl+C to stop. Pressure is in hectopascals (hPa) as measured at your location, so it will read lower than the sea-level figure your local forecast quotes if you live well above sea level.
Step 6: Run it on boot with systemd
A systemd service starts the logger at boot and restarts it if it ever crashes. This command writes the service file and fills in your username automatically:
sudo tee /etc/systemd/system/weather.service > /dev/null <<EOF
[Unit]
Description=BME280 weather logger
After=multi-user.target
[Service]
User=$USER
WorkingDirectory=/home/$USER/weather
ExecStart=/home/$USER/weather/env/bin/python /home/$USER/weather/logger.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
Pointing ExecStart at the Python inside env means the service uses your virtual environment without needing to activate it. Now load, enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now weather.service
systemctl status weather.service
The status should say active (running). Reboot with sudo reboot and check again to confirm it comes back on its own.
Step 7: View your data
For a quick look on the Pi, show the latest five readings:
tail -n 5 ~/weather/readings.csv
To chart it, copy the file to your computer. Run this on your computer, not the Pi, swapping in your username:
scp yourname@weatherpi.local:~/weather/readings.csv .
Open readings.csv in Excel, Google Sheets or LibreOffice Calc. Select the timestamp column plus one reading column, such as temp_f, and insert a line chart. After a day you will see the daily temperature swing, and pressure dropping ahead of a storm is easy to spot after a few days. At one row per minute the file grows by only a couple of megabytes a month, so space is not a concern.
Troubleshooting
i2cdetectshows nothing: Check that I2C is enabled and that blue goes to pin 3 and yellow to pin 5. Swapped SDA and SCL is the most common mistake. Make sure the jumpers are pushed fully onto the header pins.ValueErroror “No I2C device at address”: The address in the script does not match the scan. SetADDRESSto whateveri2cdetectshowed (0x77 or 0x76).- “externally-managed-environment” error from pip: The virtual environment is not active. Run
source ~/weather/env/bin/activateand try again. - Errors about GPIO on a Pi 5: Adafruit recommends removing the old RPi.GPIO package from the environment with
pip uninstall -y RPi.GPIOwhile the environment is active. - Temperature reads several degrees high: The sensor is picking up heat from the Pi or direct sun. Move it farther away on the cable and keep it shaded and ventilated. Some warming from the board itself is normal, so compare against a trusted thermometer and subtract a fixed offset in the script if needed.
For anything else, journalctl -u weather.service -n 30 shows the service’s recent output and any Python errors.
Where to go next
- Send your readings to a dashboard. Our Home Assistant tutorial is a good place to start if you want graphs and alerts on your phone.
- Want more processing power for extra sensors or a local web dashboard? Use our Pi picker to find the right board.
- Comparing models before you buy? Our Raspberry Pi buying guide covers every current board and what each one is good at.
Sources: Raspberry Pi OS documentation, Raspberry Pi documentation: Using Linux (systemd), Pinout.xyz I2C, SparkFun Flexible Qwiic Cable – Female Jumper, SparkFun Atmospheric Sensor Breakout BME280 (Qwiic), SparkFun Qwiic BME280 Hookup Guide, Adafruit: Installing Blinka on Raspberry Pi, Adafruit CircuitPython BME280 documentation