Building a personal weather station is one of the most satisfying Raspberry Pi projects you can undertake. With the BME680 environmental sensor and a crisp e-ink display, you can monitor temperature, humidity, air pressure, and even air quality — all from a low-power, always-on device sitting on your desk or mounted outside your window. This guide walks you through the complete build from hardware selection to a polished, working system.
Why the BME680 Is the Best Sensor for This Project
The BME680 from Bosch Sensortec is not just another temperature-humidity sensor. It packs four sensing elements into a single compact package: temperature, relative humidity, barometric pressure, and a gas resistance sensor that doubles as a proxy for indoor air quality (VOC levels). Compared to the popular DHT11, DHT22, or even the BME280, the BME680 gives you significantly more environmental data with excellent accuracy.
Key specs worth knowing:
- Temperature range: -40°C to +85°C (±1°C accuracy)
- Humidity: 0–100% RH (±3% accuracy)
- Pressure: 300–1100 hPa (±1 hPa)
- Gas sensor: measures VOC concentration, responds to alcohol, ethanol, CO2 proxies
- Interface: I2C or SPI (I2C is simpler for Pi builds)
- Supply voltage: 1.71V to 3.6V — 3.3V GPIO safe
For outdoor deployments, house the BME680 in a radiation shield (a stack of louvered plastic discs) so direct sun and wind don’t skew readings. Indoors, it can sit freely on a breadboard or soldered to a HAT.
Choosing the Right Raspberry Pi
Almost any Raspberry Pi model with GPIO will work for this project, but your choice affects power consumption, casing options, and expandability.
Raspberry Pi 5 (4GB or 8GB): The latest generation brings PCIe, faster I2C buses, and a real-time clock built in — useful for timestamping weather logs without an NTP connection. Overkill for a simple station, but ideal if you plan to add a camera, web dashboard, or Home Assistant integration.
Raspberry Pi Zero 2 W: Best choice if you want a battery-powered or wall-wart-powered station with minimal footprint. The quad-core ARM Cortex-A53 handles Python logging and display updates effortlessly while drawing under 500mA.
Raspberry Pi 4 (2GB): Good middle ground if you want to run a local web server alongside the sensor logging.
Full Hardware List and Wiring
Here is everything you need for the complete build:
- Raspberry Pi (any model with 40-pin GPIO)
- BME680 breakout board (3.3V I2C variant)
- Waveshare 2.13-inch or 4.2-inch e-ink display (SPI)
- Female-to-female jumper wires
- Half-size breadboard (optional, for prototyping)
- MicroSD card (16GB+, Class 10)
- Official USB-C power supply
BME680 Wiring (I2C)
Connect the BME680 to the Pi’s I2C pins:
- VCC → Pin 1 (3.3V)
- GND → Pin 6 (Ground)
- SDA → Pin 3 (GPIO2, I2C1 SDA)
- SCL → Pin 5 (GPIO3, I2C1 SCL)
E-Ink Display Wiring (SPI)
Waveshare e-ink displays use SPI0. Connect as follows:
- VCC → 3.3V (Pin 1)
- GND → Ground (Pin 6)
- DIN → GPIO10 (MOSI, Pin 19)
- CLK → GPIO11 (SCLK, Pin 23)
- CS → GPIO8 (CE0, Pin 24)
- DC → GPIO25 (Pin 22)
- RST → GPIO17 (Pin 11)
- BUSY → GPIO24 (Pin 18)
Enable I2C and SPI via sudo raspi-config → Interface Options before proceeding.
Software Setup: OS, Libraries, and Python Environment
Start with Raspberry Pi OS Lite (64-bit) for a headless setup or the full desktop if you want a local GUI.
Step 1: Update and install dependencies
sudo apt update && sudo apt upgrade -y
sudo apt install python3-pip python3-venv git i2c-tools -y
python3 -m venv ~/weather-env
source ~/weather-env/bin/activate
Step 2: Install the BME680 library
Pimoroni’s BME680 library is the most well-maintained option:
pip install bme680 smbus2
Verify the sensor is detected:
sudo i2cdetect -y 1
You should see address 0x76 or 0x77 depending on how the SDO pin is connected.
Step 3: Install the e-ink display library
pip install Pillow
git clone https://github.com/waveshare/e-Paper.git
cd e-Paper/RaspberryPi_JetsonNano/python
pip install -r requirements.txt
Python Code: Reading the BME680 and Updating the Display
Below is a complete, production-ready script that reads all four BME680 channels and renders them on the e-ink display. It also logs data to a CSV file for later analysis.
#!/usr/bin/env python3
import bme680
import time
import csv
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont
# Adjust import path for your Waveshare display model
from waveshare_epd import epd2in13_V4
# --- Sensor setup ---
sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)
sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
sensor.set_gas_heater_temperature(320)
sensor.set_gas_heater_duration(150)
sensor.select_gas_heater_profile(0)
# --- Display setup ---
epd = epd2in13_V4.EPD()
epd.init()
font24 = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 24)
font16 = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 16)
def update_display(temp, hum, pres, gas):
image = Image.new('1', (epd.width, epd.height), 255)
draw = ImageDraw.Draw(image)
draw.text((5, 2), f'Temp: {temp:.1f} C', font=font24, fill=0)
draw.text((5, 34), f'Humidity: {hum:.1f}%', font=font16, fill=0)
draw.text((5, 56), f'Pressure: {pres:.1f} hPa', font=font16, fill=0)
draw.text((5, 78), f'Air Quality: {gas/1000:.1f} kOhm', font=font16, fill=0)
draw.text((5, 100), datetime.now().strftime('%H:%M %d-%b-%Y'), font=font16, fill=0)
epd.display(epd.getbuffer(image))
LOG_FILE = '/home/pi/weather_log.csv'
with open(LOG_FILE, 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow(['timestamp','temp_c','humidity','pressure_hpa','gas_resistance_ohm'])
print('Weather station running. Press Ctrl+C to stop.')
try:
while True:
if sensor.get_sensor_data():
t = sensor.data.temperature
h = sensor.data.humidity
p = sensor.data.pressure
g = sensor.data.gas_resistance if sensor.data.heat_stable else 0
update_display(t, h, p, g)
with open(LOG_FILE, 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow([datetime.now().isoformat(), t, h, p, g])
time.sleep(300) # Update every 5 minutes
except KeyboardInterrupt:
epd.sleep()
print('Station stopped.')
Run it with: source ~/weather-env/bin/activate && python3 weather_station.py
Auto-Starting on Boot with systemd
Create a service file so the station starts automatically after a power cut:
sudo nano /etc/systemd/system/weather-station.service
[Unit]
Description=Raspberry Pi Weather Station
After=network.target
[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/weather-env/bin/python3 /home/pi/weather_station.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable weather-station
sudo systemctl start weather-station
Optional: Local Web Dashboard with Flask
The CSV log is useful, but a live web dashboard lets you check readings from any device on your home network. A minimal Flask app can serve this in under 50 lines of code.
pip install flask
# app.py
from flask import Flask, jsonify
import csv
app = Flask(__name__)
@app.route('/data')
def get_data():
rows = []
with open('/home/pi/weather_log.csv') as f:
reader = csv.DictReader(f)
rows = list(reader)[-50:] # last 50 readings
return jsonify(rows)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Browse to http://<Pi-IP>:5000/data to see JSON readings. Build a simple Chart.js frontend on top to visualise temperature trends over 24 hours.
Calibration Tips for Accurate Readings
Raw BME680 readings are good out of the box, but a few adjustments improve accuracy significantly:
- Temperature offset: The Pi’s own heat can warm the BME680 if it’s mounted close to the board. Add an offset:
sensor.set_temp_offset(-3)if indoors without ventilation. - Humidity calibration: Place the sensor in a sealed bag with a damp cloth for 1 hour. If it reads outside ±5% of 95–100% RH, apply a linear correction factor in your script.
- Gas sensor burn-in: The BME680 gas sensor needs a 30-minute burn-in period on first use. Discard readings from the first 30 minutes of operation.
- Pressure altitude correction: If you know your altitude, compute sea-level pressure with:
sea_level_p = p / (1 - altitude / 44330) ** 5.255. - Outdoor placement: Always use a Stevenson screen or radiation shield when measuring outside. Direct sunlight can cause temperature errors of +10°C or more.
Frequently Asked Questions
Can the BME680 work outdoors permanently?
Yes, but it must be housed in a weatherproof enclosure with ventilation. The sensor is rated to -40°C and 85°C, covering most Indian climate extremes. Use silica gel packets inside the enclosure to manage condensation.
How often should the display refresh?
E-ink displays have a limited number of full refreshes (typically 1 million cycles for Waveshare panels). Refreshing every 5 minutes (288 times per day) means over 9 years of life at that rate. Avoid refreshing more than once per minute to prevent ghost images.
Why is my gas resistance reading always 0?
The gas sensor only produces valid readings when sensor.data.heat_stable returns True. This happens after the internal heater reaches 320°C (about 2–3 seconds after a reading starts). Always check the heat_stable flag before logging gas values.
Can I integrate this with Home Assistant?
Absolutely. Install the homeassistant MQTT client or use the official Home Assistant OS image on your Pi. The BME680 is natively supported via the bme680 integration. You can send readings via MQTT broker and build automations based on air quality thresholds.
What power supply does a 24/7 weather station need?
A Raspberry Pi 5 draws 5W idle. The official 27W USB-C supply is more than enough. If you need battery backup, a 10,000mAh UPS HAT with an 18650 cell will keep the station running for 8–12 hours during a power cut.
—
Ready to build your own weather station? Browse the full range of Raspberry Pi boards, sensors, and accessories at Zbotic.in — India’s trusted source for genuine components with fast delivery and expert support.
Add comment