Heim Der Blog Blog Details

Erstellen Sie eine Wetterstation mit Raspberry Pi und DHT22

September 23 2025
Ampheo

Anfrage

Globaler Lieferant elektronischer Komponenten AMPHEO PTY LTD: Umfangreiches Inventar für One-Stop-Shopping. Einfache Anfragen, schnelle, individuelle Lösungen und Angebote.

SCHNELLE ANFRAGE
ZUR RFQ-LISTE HINZUFÜGEN
Hier ist eine saubere, ganzheitliche Möglichkeit, eine Raspberry Pi + DHT22-Wetterstation zu erstellen, die Daten protokolliert und ein winziges Web-Dashboard bedient.

Hier ist eine saubere, ganzheitliche Möglichkeit, eine Raspberry Pi + DHT22-Wetterstation zu erstellen, die Daten protokolliert und ein winziges Web-Dashboard bedient.

Erstellen Sie eine Wetterstation mit Raspberry Pi und DHT22

1) Was du brauchst

  • Raspberry Pi (jedes Modell mit GPIO; Pi 3/4/5 empfohlen)

  • microSD-Karte mit Raspberry Pi OS

  • DHT22 (auch als AM2302 bekannt). Beim nackten Sensor zusätzlich einen 10-kΩ-Pull-Up-Widerstand einplanen.

  • Breadboard + Jumperkabel

  • (Optional) DHT22-Module enthalten oft bereits den Pull-Up—dann brauchst du keinen extra Widerstand.

2) Verdrahtung (3,3-V-Logik!)

DHT22-Pinbelegung (links→rechts, wenn du auf die Gitter/Schlitze schaust):

  1. VCC

  2. DATA

  3. (NC) – nicht belegt

  4. GND

Anschluss am Pi:

  • DHT22 VCC → Pi 3,3 V (Pin 1)

  • DHT22 GND → Pi GND (Pin 6)

  • DHT22 DATA → Pi GPIO4 (BCM 4, Pin 7)

  • Beim nackten DHT22: 10-kΩ zwischen VCC und DATA als Pull-Up

DHT22-Spezifikation: nicht schneller als alle 2 Sekunden auslesen.

3) OS-Vorbereitung & Bibliotheken installieren

 
sudo apt update
sudo apt install -y python3-pip python3-venv libgpiod2
python3 -m venv ~/weather-venv
source ~/weather-venv/bin/activate
pip install --upgrade pip
pip install adafruit-circuitpython-dht flask

4) Schnelltest-Script

Erstelle dht_test.py:

 

# dht_test.py
# Kurzer Funktionstest für den DHT22 an GPIO4 (BCM 4)
import time, adafruit_dht, board

# GPIO4 (Pin 7) verwenden
dht = adafruit_dht.DHT22(board.D4, use_pulseio=False)

while True:
    try:
        t = dht.temperature  # °C
        h = dht.humidity     # % rF
        if t is not None and h is not None:
            print(f"{time.strftime('%F %T')}  {t:.1f}°C  {h:.1f}%rF")
        else:
            print("Sensor lieferte None – versuche erneut ...")
    except RuntimeError as e:
        # Bei DHT-Sensoren sind gelegentliche Timing-Fehler normal
        print("Lese-Fehler:", e)
    time.sleep(2)  # DHT22 max. ~0,5 Hz

Start:

 
source ~/weather-venv/bin/activate
python dht_test.py

Wenn alle ~2 s Werte erscheinen, passt es.

5) In CSV protokollieren (für Diagramme/Analysen)

Projektordner anlegen:

 
mkdir -p ~/weather
cd ~/weather

Erstelle dht_logger.py:

 

# dht_logger.py
# Kontinuierliches Logging des DHT22 nach CSV
import time, csv, os, adafruit_dht, board

LOG = "weather.csv"
INTERVAL_SEC = 60  # alle 60 s loggen (sicher für DHT22)

dht = adafruit_dht.DHT22(board.D4, use_pulseio=False)

# CSV mit Header anlegen, falls nicht vorhanden
new_file = not os.path.exists(LOG)
with open(LOG, "a", newline="") as f:
    w = csv.writer(f)
    if new_file:
        # WICHTIG: Feldnamen NICHT übersetzen – sie werden später im Server verwendet
        w.writerow(["timestamp","temp_c","humidity_percent"])

last_ok = 0
while True:
    try:
        t = dht.temperature
        h = dht.humidity
        now = int(time.time())
        if t is not None and h is not None:
            with open(LOG, "a", newline="") as f:
                csv.writer(f).writerow([now, f"{t:.2f}", f"{h:.2f}"])
            last_ok = now
            print(time.strftime("%F %T"), f"{t:.2f}°C {h:.2f}%rF")
        else:
            print("None-Messung – überspringe Eintrag.")
    except RuntimeError as e:
        print("Vorübergehender Lese-Fehler:", e)
    except Exception as e:
        # z. B. Rechteprobleme – nicht abstürzen
        print("Unerwarteter Fehler:", e)
    time.sleep(INTERVAL_SEC)

Lass es ein paar Minuten laufen:

 
source ~/weather-venv/bin/activate
python dht_logger.py

Mit Strg+C stoppen.

6) Autostart beim Booten (systemd)

Service anlegen:

 
sudo nano /etc/systemd/system/dht-logger.service

Einfügen:

 

[Unit]
Description=DHT22 CSV Logger
After=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/weather
Environment=PYTHONUNBUFFERED=1
ExecStart=/home/pi/weather-venv/bin/python /home/pi/weather/dht_logger.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Aktivieren:

 
sudo systemctl daemon-reload
sudo systemctl enable --now dht-logger
sudo systemctl status dht-logger

7) Mini-Web-Dashboard (Flask + HTML)

Zeigt den aktuellsten Wert und einfache Diagramme aus der CSV.

Erstelle server.py:

 

# server.py
# Einfaches Flask-API für aktuelle Messwerte & Historie aus weather.csv
import time, csv, os, adafruit_dht, board
from flask import Flask, jsonify, send_from_directory

CSV_PATH = "/home/pi/weather/weather.csv"
CACHE_TTL = 3  # Sekunden; vermeidet übermäßiges Abfragen des Sensors
app = Flask(__name__)

# Optional: Live-Lesung mit kleinem Cache
_dht = adafruit_dht.DHT22(board.D4, use_pulseio=False)
_last = {"ts": 0, "t": None, "h": None}

def read_sensor():
    global _last
    now = time.time()
    if now - _last["ts"] >= CACHE_TTL:
        try:
            t = _dht.temperature
            h = _dht.humidity
            if t is not None and h is not None:
                _last = {"ts": now, "t": round(t,2), "h": round(h,2)}
        except Exception:
            pass
    return _last

@app.get("/api/latest")
def api_latest():
    # Bevorzugt den neuesten Eintrag aus CSV; fällt auf Live-Wert zurück
    if os.path.exists(CSV_PATH):
        try:
            with open(CSV_PATH, newline="") as f:
                rows = list(csv.DictReader(f))
                if rows:
                    last = rows[-1]
                    return jsonify({
                        "timestamp": int(last["timestamp"]),
                        "temp_c": float(last["temp_c"]),
                        "humidity": float(last["humidity_percent"])
                    })
        except Exception:
            pass
    r = read_sensor()
    return jsonify({
        "timestamp": int(r["ts"]),
        "temp_c": r["t"],
        "humidity": r["h"]
    })

@app.get("/api/history")
def api_history():
    data = []
    if os.path.exists(CSV_PATH):
        with open(CSV_PATH, newline="") as f:
            for row in csv.DictReader(f):
                data.append({
                    "timestamp": int(row["timestamp"]),
                    "temp_c": float(row["temp_c"]),
                    "humidity": float(row["humidity_percent"])
                })
    return jsonify(data)

@app.get("/")
def root():
    return send_from_directory(".", "index.html")

@app.get("/<path:path>")
def static_files(path):
    return send_from_directory(".", path)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

Erstelle index.html (neben server.py ablegen):

 

<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
  <title>Pi Wetterstation</title>
  <style>
    body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;max-width:900px;margin:24px auto;padding:0 16px}
    h1{margin-bottom:4px} .card{border:1px solid #eee;border-radius:12px;padding:16px;margin:12px 0;box-shadow:0 1px 6px rgba(0,0,0,.06)}
    .row{display:flex;gap:16px;flex-wrap:wrap} .metric{flex:1;min-width:180px}
    canvas{width:100%;height:360px}
    small{color:#666}
  </style>
</head>
<body>
  <h1>Raspberry Pi + DHT22 Wetter</h1>
  <small id="updated">—</small>

  <div class="card row">
    <div class="metric"><h2 id="t">-- °C</h2><small>Temperatur</small></div>
    <div class="metric"><h2 id="h">-- %</h2><small>Luftfeuchte</small></div>
  </div>

  <div class="card">
    <h3>Letzte 24 Stunden</h3>
    <canvas id="tempChart"></canvas>
    <canvas id="humChart"></canvas>
  </div>

  <script>
    async function fetchJSON(url){ const r = await fetch(url); return r.json(); }
    function tsToLocal(ts){ return new Date(ts*1000).toLocaleString(); }

    async function refresh(){
      const latest = await fetchJSON('/api/latest');
      if(latest.temp_c!=null){ document.getElementById('t').textContent = latest.temp_c.toFixed(1)+' °C'; }
      if(latest.humidity!=null){ document.getElementById('h').textContent = latest.humidity.toFixed(1)+' %'; }
      if(latest.timestamp){ document.getElementById('updated').textContent = 'Aktualisiert: '+tsToLocal(latest.timestamp); }

      const hist = await fetchJSON('/api/history');
      const cutoff = (Date.now()/1000) - 24*3600;
      const recent = hist.filter(x=>x.timestamp>=cutoff);
      const labels = recent.map(x=>new Date(x.timestamp*1000).toLocaleTimeString());
      const temps = recent.map(x=>x.temp_c);
      const hums  = recent.map(x=>x.humidity);

      // Chart.js bei Bedarf nachladen (kannst du später lokal hosten)
      if(!window.Chart){
        const s=document.createElement('script');
        s.src='https://cdn.jsdelivr.net/npm/chart.js';
        s.onload=()=>drawCharts(labels, temps, hums);
        document.body.appendChild(s);
      } else {
        drawCharts(labels, temps, hums);
      }
    }

    let tempChart, humChart;
    function drawCharts(labels, temps, hums){
      if(tempChart) tempChart.destroy();
      if(humChart) humChart.destroy();
      const ctxT = document.getElementById('tempChart').getContext('2d');
      const ctxH = document.getElementById('humChart').getContext('2d');

      tempChart = new Chart(ctxT, {
        type:'line',
        data:{ labels, datasets:[{ label:'Temperatur (°C)', data:temps }]},
        options:{ responsive:true, maintainAspectRatio:false, parsing:false }
      });

      humChart = new Chart(ctxH, {
        type:'line',
        data:{ labels, datasets:[{ label:'Luftfeuchte (%)', data:hums }]},
        options:{ responsive:true, maintainAspectRatio:false, parsing:false }
      });
    }

    refresh();
    setInterval(refresh, 10000);
  </script>
</body>
</html>

Server starten:

 
source ~/weather-venv/bin/activate
python server.py

Vom anderen Gerät öffnen: http://<pi-ip>:8080/

(Optional) Als Service einrichten:

 

sudo tee /etc/systemd/system/weather-server.service >/dev/null <<'EOF'
[Unit]
Description=Weather Flask Server
After=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/weather
Environment=PYTHONUNBUFFERED=1
ExecStart=/home/pi/weather-venv/bin/python /home/pi/weather/server.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now weather-server

8) Tipps, Genauigkeit & Fehlersuche

  • Abtastrate: DHT22 ist langsam; nicht schneller als alle 2 s auslesen.

  • Spannung: 3,3 V verwenden. 5 V gefährden die Pi-GPIOs.

  • Pull-Up: Nackter DHT22 braucht 10 kΩ an DATA. Module haben ihn meist schon.

  • Fehlwerte/Spitzen: Bei DHT-Sensoren normal—Code sollte None oder RuntimeError abfangen (siehe oben).

  • Berechtigungen: Bei Kanten-/GPIO-Rechten sicherstellen, dass libgpiod2 und CircuitPython DHT installiert sind (siehe Schritte).

  • Platzierung: Nicht in direkte Sonne und weg vom warmen Pi-Luftstrom für realistischere Raumwerte.

  • Einheiten: °F: temp_f = temp_c * 9/5 + 32.

Ampheo