Theory done. Today you'll build three complete projects: a weather station, a motion-triggered camera, and an LED strip controller.
Combine the DHT22 (temperature/humidity) and BMP280 (barometric pressure) to build a weather station. Log readings to a SQLite database. Serve a Flask web app on port 5000 that displays a live chart using Chart.js. The Pi stays on your local network — visit http://raspberrypi.local:5000 from any device. This is a complete IoT device with persistent storage and a web UI.
Connect a Pi Camera Module or USB webcam. Use the picamera2 library (Pi Camera) or opencv-python (USB cam) to capture images. Connect a PIR motion sensor to GPIO17 — it outputs HIGH when motion is detected. Write a loop: when PIR is HIGH, capture a photo, save with timestamp filename, send an email notification using Python's smtplib.
WS2812B NeoPixels (addressable RGB LEDs) are controlled over a single data wire using precise timing. The rpi_ws281x library handles the protocol. Connect data to GPIO18 (hardware PWM), 5V power to a separate 5V supply (strips draw 60mA per LED at full brightness — 300-LED strip = 18A at 5V), and a common ground. Build animations: rainbow cycle, theater chase, color wipe, sparkle.
#!/usr/bin/env python3
# Weather station with SQLite + Flask dashboard
# pip3 install flask adafruit-circuitpython-dht
import sqlite3, time, threading
from flask import Flask, jsonify, render_template_string
import board, adafruit_dht
app = Flask(__name__)
dht = adafruit_dht.DHT22(board.D4, use_pulseio=False)
# Initialize database
def init_db():
conn = sqlite3.connect('weather.db')
conn.execute('''CREATE TABLE IF NOT EXISTS readings
(id INTEGER PRIMARY KEY, ts REAL, temp REAL, humidity REAL)''')
conn.commit(); conn.close()
def record_reading():
while True:
try:
t, h = dht.temperature, dht.humidity
conn = sqlite3.connect('weather.db')
conn.execute('INSERT INTO readings (ts,temp,humidity) VALUES (?,?,?)',
(time.time(), t, h))
conn.commit(); conn.close()
except: pass
time.sleep(30)
@app.route('/api/data')
def data():
conn = sqlite3.connect('weather.db')
rows = conn.execute('SELECT ts,temp,humidity FROM readings ORDER BY ts DESC LIMIT 100').fetchall()
conn.close()
return jsonify([{'ts':r[0],'temp':r[1],'hum':r[2]} for r in reversed(rows)])
HTML = '''<!DOCTYPE html><html><head><title>Weather Station</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script></head><body>
<h2>Pi Weather Station</h2>
<canvas id="chart" width="800" height="300"></canvas>
<script>
async function update(){
const d=await fetch('/api/data').then(r=>r.json());
new Chart(document.getElementById('chart'),{type:'line',
data:{labels:d.map(r=>new Date(r.ts*1000).toLocaleTimeString()),
datasets:[{label:'Temp (C)',data:d.map(r=>r.temp),borderColor:'red',tension:.3},
{label:'Humidity (%)',data:d.map(r=>r.hum),borderColor:'blue',tension:.3}]},
options:{responsive:true}});
}
update(); setInterval(update,30000);
</script></body></html>'''
@app.route('/')
def index(): return HTML
if __name__=='__main__':
init_db()
threading.Thread(target=record_reading, daemon=True).start()
app.run(host='0.0.0.0', port=5000, debug=False)
print('Visit http://raspberrypi.local:5000')
/etc/systemd/system/weather.service with ExecStart=/usr/bin/python3 /home/pi/weather.py, then sudo systemctl enable weather && sudo systemctl start weather.pip3 install flask adafruit-circuitpython-dhtpython3 weather.py. Visit http://raspberrypi.local:5000 from another device on the same network.Add email alerts to the weather station: when temperature exceeds 30°C or drops below 10°C, send an email using Python's smtplib with Gmail SMTP. Implement a cooldown so you don't get spammed (max one alert per 30 minutes per condition). Store the Gmail credentials in environment variables, not in the code.