Build Your Own Raspberry Pi Weather Station: Complete Project Guide

Build Your Own Raspberry Pi Weather Station

A Raspberry Pi weather station is one of those projects that starts simple and expands as far as you want to take it. Wire up a temperature sensor, write twenty lines of Python, and you have local readings in minutes. Add a pressure sensor, a rain gauge, a web dashboard, and cloud logging, and you have something genuinely useful running on your wall or windowsill for years.

I have built a few of these over the years in different configurations. This guide covers the practical path from hardware selection through sensor wiring, Python data collection, local storage, and visualization. It skips the parts that sound impressive but rarely work in practice, and it fixes the outdated library and OS instructions that are all over the internet and cause most of the early frustration.

Key Takeaways

  • The DHT22 is the right starting sensor for most builds. The old Adafruit_DHT library is deprecated. Use adafruit-circuitpython-dht with libgpiod2 instead.
  • The wpa_supplicant.conf headless Wi-Fi method no longer works on Bookworm. Use Raspberry Pi Imager to configure everything before flashing.
  • Pi Zero 2 W is the right choice for a low-power outdoor or remote station. Pi 4 is right for a dashboard-heavy indoor setup.
  • SQLite handles local storage well for most personal weather stations. InfluxDB and Grafana are worth the setup effort if you want a proper time-series dashboard.
  • Cron is how you automate data collection. Set it up early and leave it alone.
  • SD card longevity matters on a 24/7 data-logging build. zram and noatime are the two changes that make the most difference.

Choosing the Right Raspberry Pi Model

The right Pi for a weather station depends on what you are logging, where the station lives, and how much you want to display locally.

Raspberry Pi 4

The Pi 4 is the right choice if you are running a Grafana dashboard, managing multiple sensors, or doing any local data processing. It has the CPU headroom to run a database, a web server, and sensor polling at the same time without complaint. The trade-off is power consumption. A Pi 4 draws 3 to 6 watts at idle, which adds up for a solar or battery-powered remote installation.

Raspberry Pi Zero 2 W

The Zero 2 W is the better choice for outdoor, remote, or battery-powered setups. It draws under 1 watt at idle, has built-in Wi-Fi, and is small enough to fit inside most weatherproof enclosures. It handles sensor polling, local logging, and MQTT publishing without any issues. Where it struggles is running a full Grafana stack locally. For that workload, keep it on a Pi 4 and let the Zero 2 W be the field collector.

Raspberry Pi Pico

The Pico is a microcontroller, not a Linux computer. It runs MicroPython, has no operating system overhead, and draws almost nothing from a battery. It is worth considering for a sensor node that just needs to read a DHT22 and push readings over MQTT or serial. It is not the right choice if you want to run Python scripts, store data in SQLite, or serve a web interface.

Sensors and What They Measure

DHT22: Temperature and Humidity

The DHT22 is the standard starting point for most weather station builds. It measures temperature from -40C to +80C and humidity from 0 to 100 percent relative humidity with decent accuracy. It uses a single data wire and connects directly to a GPIO pin with a 10k pull-up resistor between the data pin and the 3.3V supply. One important note: the old Adafruit_DHT Python library is deprecated and unmaintained. The current library is adafruit-circuitpython-dht, and it requires libgpiod2 to be installed first. More on installation below.

HiLetgo 2pcs DHT22/AM2302 Digital Temperature and Humidity Sensor Module Temperature Humidity Monitor Sensor Replace SHT11 SHT15 for Arduino Electronic…

5.0
Amazon.com

BMP280: Barometric Pressure and Temperature

The BMP280 measures barometric pressure (300 to 1100 hPa) and temperature. It connects via I2C, which means two wires shared with other I2C devices and a simple address configuration. The older BMP180 still works but the BMP280 is more accurate and more widely supported by current libraries. Barometric pressure is useful for weather trend prediction. A falling pressure reading often precedes a storm, a rising reading suggests clearing conditions.

SHILLEHTEK PRE-SOLDERED BMP280 3.3V I2C IIC Digital Atmospheric Pressure, Temperature, and Altitude Sensor Module for Raspberry Pi, Arduino, ESP32, and Other…

4.0
Amazon.com

DS18B20: Waterproof Temperature Probe

The DS18B20 comes in a waterproof stainless probe form factor, which makes it useful for measuring outdoor air temperature, soil temperature, or water temperature depending on how you mount it. It uses the 1-Wire protocol and supports multiple sensors on a single GPIO pin. Temperature range is -55C to +125C.

HiLetgo 5pcs DS18B20 Temperature Sensor Temperature Probe Stainless Steel Package Waterproof 1M

Amazon.com

Rain gauge, anemometer, and wind vane

A tipping bucket rain gauge sends a digital pulse to a GPIO pin each time it tips, typically representing 0.2mm or 0.3mm of rainfall depending on the gauge. An anemometer measures wind speed using reed switches or optical encoders. A wind vane measures direction using a potentiometer, which requires an ADC chip (like the MCP3008) since the Raspberry Pi has no built-in analog input. These three sensors together are what separate a proper weather station from a desk sensor.

UV index sensor

A UV index sensor like the VEML6075 or LTR390 measures ultraviolet radiation via I2C. It is a useful addition for gardening applications or any build where sun exposure matters. Not essential for a basic station but straightforward to add once the rest is working.

Weather station wiring diagram

Setting Up Raspberry Pi OS

Use Raspberry Pi OS Lite 64-bit for a headless weather station. It boots faster, uses less memory, and has no desktop environment consuming resources in the background.

Flashing and headless configuration

The old method of creating a blank ssh file and a wpa_supplicant.conf file on the boot partition does not work on Raspberry Pi OS Bookworm. Raspberry Pi Imager now handles all of this through the settings panel before flashing. Click the gear icon (or press Ctrl+Shift+X), set your hostname, username, password, Wi-Fi credentials, and enable SSH before writing the image. That is the correct method for current OS images.

After first boot, update the system before installing anything else:

sudo apt update && sudo apt upgrade -y

Enable I2C for pressure and other sensors

If you are using I2C sensors like the BMP280, enable the I2C interface:

sudo raspi-config
# Interface Options > I2C > Enable

# Verify I2C devices are detected after connecting sensors
sudo apt install -y i2c-tools
i2cdetect -y 1

The BMP280 typically shows at address 0x76 or 0x77. If nothing shows, check your wiring.

SD card longevity for a 24/7 logging build

A weather station that logs data every five minutes writes to the SD card thousands of times per day. Two changes make a meaningful difference to card life. First, add noatime,commit=300 to your fstab root partition entry to reduce unnecessary writes. Second, set up zram to keep swap off the card entirely. Both are covered in detail at Preventing SD Card Corruption on Raspberry Pi and Setting Up zram on Raspberry Pi. Worth doing before you start logging.

Installing Python Libraries

Install the core dependencies before writing any sensor code:

# Required for DHT sensor support on current OS images
sudo apt install -y python3-pip libgpiod2

# Current DHT library (replaces the deprecated Adafruit_DHT)
pip3 install adafruit-circuitpython-dht --break-system-packages

# BMP280 library
pip3 install adafruit-circuitpython-bmp280 --break-system-packages

# DS18B20 (1-Wire temperature sensor)
pip3 install w1thermsensor --break-system-packages

# For HTTP requests to cloud platforms
pip3 install requests --break-system-packages

# For MQTT publishing
pip3 install paho-mqtt --break-system-packages

The --break-system-packages flag is required on Bookworm because pip installs into system Python by default on older commands. Alternatively, use a virtual environment if you prefer to keep things tidy.

Reading Sensor Data with Python

DHT22: Temperature and Humidity

The current library uses CircuitPython board abstraction. Connect the DHT22 data pin to GPIO4 (physical pin 7), with a 10k resistor between data and 3.3V:

import board
import adafruit_dht
import time

# Initialize DHT22 on GPIO4
dht = adafruit_dht.DHT22(board.D4)

try:
    temperature = dht.temperature
    humidity = dht.humidity
    print(f"Temperature: {temperature:.1f}C  Humidity: {humidity:.1f}%")
except RuntimeError as e:
    # DHT sensors occasionally fail a read -- this is normal
    print(f"Read error: {e}")
finally:
    dht.exit()

DHT sensors occasionally fail a single read. The RuntimeError catch is intentional. Wrap repeated reads in a retry loop for production use.

BMP280: Barometric Pressure

Connect SDA to GPIO2 (pin 3) and SCL to GPIO3 (pin 5). Both also need 3.3V and GND:

import board
import busio
import adafruit_bmp280

i2c = busio.I2C(board.SCL, board.SDA)
bmp = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, address=0x76)

# Set sea level pressure for your location (hPa)
bmp.sea_level_pressure = 1013.25

print(f"Temperature: {bmp.temperature:.1f}C")
print(f"Pressure: {bmp.pressure:.1f} hPa")
print(f"Altitude: {bmp.altitude:.1f} m")

DS18B20: 1-Wire Temperature Probe

Enable 1-Wire in raspi-config (Interface Options > 1-Wire) and connect the sensor to GPIO4 with a 4.7k resistor between data and 3.3V:

from w1thermsensor import W1ThermSensor

sensor = W1ThermSensor()
temperature = sensor.get_temperature()
print(f"Temperature: {temperature:.1f}C")

Storing Data Locally with SQLite

SQLite works well for a personal weather station. It requires no server, no configuration, and handles years of sensor readings without complaint. Here is a complete logging script that reads from a DHT22 and BMP280 and stores everything to a local database:

import sqlite3
import time
import board
import busio
import adafruit_dht
import adafruit_bmp280

# Database setup
conn = sqlite3.connect('/home/pi/weather.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS readings (
    timestamp TEXT,
    temp_dht REAL,
    humidity REAL,
    temp_bmp REAL,
    pressure REAL
)''')
conn.commit()

# Sensor setup
dht = adafruit_dht.DHT22(board.D4)
i2c = busio.I2C(board.SCL, board.SDA)
bmp = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, address=0x76)

try:
    temp_dht = dht.temperature
    humidity = dht.humidity
except RuntimeError:
    temp_dht = None
    humidity = None
finally:
    dht.exit()

temp_bmp = bmp.temperature
pressure = bmp.pressure
timestamp = time.strftime('%Y-%m-%d %H:%M:%S')

c.execute("INSERT INTO readings VALUES (?,?,?,?,?)",
          (timestamp, temp_dht, humidity, temp_bmp, pressure))
conn.commit()
conn.close()

print(f"{timestamp}: {temp_dht}C, {humidity}%, {pressure:.1f} hPa")

Automating Data Collection with Cron

Set up a cron job to run the logging script every five minutes. This is how the station goes from a manual script to an always-on data collector:

crontab -e

# Add this line to log every 5 minutes:
*/5 * * * * /usr/bin/python3 /home/pi/weather_log.py >> /home/pi/weather.log 2>&1

The >> /home/pi/weather.log 2>&1 part redirects both stdout and stderr to a log file, which is useful for catching read errors without them silently disappearing. Check the log file after a few cycles to confirm readings are coming through cleanly.

Sending Data to the Cloud

ThingSpeak

ThingSpeak is a straightforward option for logging and visualizing sensor data remotely. Create a free account, create a channel with fields for each measurement, then add the API write call to your logging script:

import requests

API_KEY = 'YOUR_THINGSPEAK_API_KEY'
temperature = 22.5
humidity = 58.0

payload = {
    'api_key': API_KEY,
    'field1': temperature,
    'field2': humidity
}
response = requests.post('https://api.thingspeak.com/update', params=payload)
print(f"ThingSpeak response: {response.status_code}")

MQTT for home automation integration

If you are running Home Assistant or any MQTT broker on your network, publishing sensor readings via MQTT is the cleanest integration path. Install Mosquitto on the Pi or use an existing broker:

import paho.mqtt.client as mqtt

client = mqtt.Client()
client.connect("YOUR_BROKER_IP", 1883, 60)

client.publish("weather/temperature", "22.5")
client.publish("weather/humidity", "58.0")
client.publish("weather/pressure", "1013.2")
client.disconnect()

Home Assistant can pick up these topics automatically once you add the MQTT integration and configure the sensor entities in your configuration.

Communication Options for Remote Stations

For stations with Wi-Fi coverage, MQTT or HTTP over Wi-Fi is the simplest approach. For remote stations outside Wi-Fi range, two other options are worth knowing about.

LoRa is a low-power, long-range radio protocol that can transmit small data packets up to 10 to 15 kilometers in open terrain. It is the right choice for a field sensor with no network access. You need a LoRa HAT or module for the Pi and a LoRa gateway connected to your network to receive the data. Power consumption is very low, which makes it compatible with solar or battery operation.

Cellular via a 4G USB modem or HAT is the option for remote stations that need real-time data and have no Wi-Fi or LoRa gateway nearby. It costs more to run but requires no additional infrastructure. Useful for monitoring agricultural land or remote sites where a proper internet connection is genuinely not available.

Visualizing Data with Grafana and InfluxDB

Grafana with InfluxDB is the standard stack for a proper time-series dashboard. InfluxDB stores the readings efficiently over time. Grafana queries the database and draws the charts. Together they give you historical graphs, alerting, and a clean dashboard you can view from any browser on your network.

Install InfluxDB v2

# Add InfluxDB repository
curl https://repos.influxdata.com/influxdata-archive.key | gpg --dearmor | sudo tee /usr/share/keyrings/influxdb-archive-keyring.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/influxdb-archive-keyring.gpg] https://repos.influxdata.com/debian stable main" | sudo tee /etc/apt/sources.list.d/influxdb.list

sudo apt update
sudo apt install -y influxdb2

sudo systemctl enable influxdb
sudo systemctl start influxdb

Access the InfluxDB setup UI at http://YOUR_PI_IP:8086 to create your organization, bucket, and initial API token. Keep that token. You will need it for writing data from Python and for connecting Grafana.

Write sensor data to InfluxDB from Python

pip3 install influxdb-client --break-system-packages
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS

INFLUX_URL = "http://localhost:8086"
INFLUX_TOKEN = "YOUR_TOKEN"
INFLUX_ORG = "YOUR_ORG"
INFLUX_BUCKET = "weather"

client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG)
write_api = client.write_api(write_options=SYNCHRONOUS)

point = (
    Point("environment")
    .field("temperature", 22.5)
    .field("humidity", 58.0)
    .field("pressure", 1013.2)
)
write_api.write(bucket=INFLUX_BUCKET, org=INFLUX_ORG, record=point)
client.close()

Install Grafana

sudo apt install -y adduser libfontconfig1
wget https://dl.grafana.com/oss/release/grafana_10.4.2_arm64.deb
sudo dpkg -i grafana_10.4.2_arm64.deb

sudo systemctl enable grafana-server
sudo systemctl start grafana-server

Access Grafana at http://YOUR_PI_IP:3000. Default login is admin/admin, change it on first login. Add InfluxDB as a data source using your token and org name, then create a dashboard with panels querying your weather bucket. From there you can build temperature, humidity, and pressure graphs with historical ranges, thresholds, and alerts.

Building a Simple Web Interface with Flask

Flask gives you a lightweight local web page showing current readings without the complexity of Grafana. Good for a simple display on a phone or tablet on your network.

pip3 install flask --break-system-packages

Create weather_app.py. The app has two routes: / serves the HTML page, and /data returns a JSON object with the current readings. JavaScript on the page fetches /data every 10 seconds and updates the display without a page reload.

from flask import Flask, jsonify, render_template_string
import board
import adafruit_dht

app = Flask(__name__)

# Minimal single-page template -- paste your own HTML/CSS here
PAGE = (
    "<!DOCTYPE html>"
    "<html><head><title>Weather Station</title></head>"
    "<body>"
    "<h1>Weather Station</h1>"
    "<p id='temp'>Loading...</p>"
    "<p id='hum'>Loading...</p>"
    "<script>"
    "function update(){"
    "fetch('/data').then(r=>r.json()).then(d=>{"
    "document.getElementById('temp').innerText=d.temperature+' C';"
    "document.getElementById('hum').innerText=d.humidity+' %';})}"
    "update();setInterval(update,10000);"
    "</script></body></html>"
)

@app.route('/')
def index():
    return render_template_string(PAGE)

@app.route('/data')
def data():
    dht = adafruit_dht.DHT22(board.D4)
    try:
        temp = dht.temperature
        hum = dht.humidity
    except RuntimeError:
        temp = None
        hum = None
    finally:
        dht.exit()
    return jsonify({'temperature': temp, 'humidity': hum})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Run it and access it at http://YOUR_PI_IP:5000. The page updates every 10 seconds via JavaScript without reloading. To make it start at boot, add it to a systemd service or manage it with PM2 the same way you would a MagicMirror install.

Power Supply for Remote Stations

For indoor stations plugged into a wall, a standard 5V 3A USB-C supply for the Pi 4 or a 5V 2.5A supply for a Pi Zero 2 W is all you need. For outdoor or off-grid stations, the options are solar panels with a charge controller and battery pack, or a large lithium power bank with a UPS HAT that handles smooth power transitions.

A 10W solar panel paired with a 10,000mAh battery and a charge controller handles a Pi Zero 2 W station through most weather conditions. Size up if your enclosure gets significant shade or if you are in a cloudy climate. The Pi does not care where the power comes from as long as the voltage stays stable. Undervoltage on a remote station is harder to diagnose than on a desk setup, so err toward a larger battery than you think you need.

To reduce power draw on battery-powered builds, disable HDMI output if you have no display connected:

# Disable HDMI output to save power (add to /etc/rc.local before exit 0)
/usr/bin/tvservice -o

For a more thorough look at what is causing unnecessary writes and power draw on a Pi running 24/7, see Booting Raspberry Pi from USB SSD, which also covers moving the root filesystem off the SD card, which is useful for any outdoor station that would be difficult to access for a repair.

FAQ

What sensors do I need for a basic Raspberry Pi weather station?

Start with a DHT22 for temperature and humidity. Add a BMP280 for barometric pressure. Those two sensors together give you the most useful everyday readings with minimal wiring complexity. Everything else, rain gauges, anemometers, UV sensors, is an expansion you add once the core build is working reliably.

Why is the Adafruit_DHT library not working on my Raspberry Pi?

The old Adafruit_DHT library is deprecated and no longer maintained. It does not work reliably on current Raspberry Pi OS images. The replacement is adafruit-circuitpython-dht, which requires libgpiod2 to be installed via apt first. See the installation section above for the correct commands.

How do I set up headless Wi-Fi on Raspberry Pi for a weather station?

On current Raspberry Pi OS (Bookworm), the old wpa_supplicant.conf method does not work. Use Raspberry Pi Imager, click the settings gear icon before writing the image, and configure your Wi-Fi credentials, hostname, username, password, and SSH access there. The Pi will connect automatically on first boot.

Can I power a Raspberry Pi weather station with solar energy?

Yes. A Pi Zero 2 W drawing under 1 watt at idle is well matched to a small solar setup. A 10W panel with a 10,000mAh battery and a charge controller handles most conditions. The Pi 4 draws significantly more power and needs a larger panel and battery for reliable off-grid operation.

How do I store weather data from a Raspberry Pi?

SQLite is the simplest option and works well for personal use. It requires no server and stores years of readings in a single file. For a proper time-series dashboard with historical graphs and alerting, InfluxDB with Grafana is the more capable option and worth the setup effort if you plan to keep the station running long term.

How do I automate data collection on a Raspberry Pi weather station?

Use cron. Add a line to your crontab to run your Python logging script at whatever interval you want, typically every 5 or 10 minutes. Run crontab -e and add */5 * * * * /usr/bin/python3 /home/pi/weather_log.py to log every five minutes. Set it up early and leave it alone.

What is the best Raspberry Pi for a weather station?

For an indoor station running Grafana dashboards and multiple sensors, the Pi 4 with 2GB RAM. For a remote or battery-powered outdoor station, the Pi Zero 2 W. For a pure sensor node with no operating system, the Raspberry Pi Pico running MicroPython.

References

Was this helpful?

Yes
No
Thanks for your feedback!