Projet DIY

Station météo connectée avec Raspberry Pi : construire, coder, afficher

Construire une station météo Raspberry Pi avec un capteur BME280 : câblage I2C, code Python en venv, dashboard Flask + Chart.js, service systemd, FAQ et dépannage. Testé Bookworm.

Même principe pour le dashboard Flask : créer /etc/systemd/system/meteo-dashboard.service, pointer son ExecStart vers ~/meteo/venv/bin/python /home/pi/meteo/dashboard.py, puis enable et start. Après ça, le Pi démarre et commence à mesurer en autonome.

Avec cette configuration, un Pi Zero 2 W tourne typiquement 4 à 6 mois en mesure continue avant que la carte microSD ne montre les premiers signes de fatigue (latences d’écriture, secteurs réalloués). Sur une carte industrielle SLC ou en boot SSD USB, on dépasse facilement 2 à 3 ans sans intervention.

Améliorations possibles

  • Écran OLED SSD1306 (5 euros) : afficher les mesures en temps réel sur un petit écran 128×64 pixels fixé au boîtier, sans avoir à ouvrir un navigateur.
  • Alertes par Telegram : un bot Telegram qui envoie un message si la température descend sous 5 °C ou si l’humidité dépasse 80 %. Vingt lignes de Python avec la bibliothèque python-telegram-bot.
  • Capteur d’indice de qualité d’air (CCS811 ou SGP30) : ces capteurs mesurent les composés organiques volatils (COV) et estiment un eCO₂ par corrélation, ce n’est pas une mesure directe de CO₂. Pour mesurer le CO₂ ambiant réel, il faut un capteur NDIR comme le Sensirion SCD41 (~30 €) ou le MH-Z19 (~15 €). Connexion I2C, même bus que le BME280.
  • Envoi vers InfluxDB + Grafana : pour les utilisateurs avancés qui veulent un dashboard professionnel avec rétention longue et agrégations temporelles. InfluxDB tourne sur Pi 4/5 sans problème.

Pour creuser : le guide ultime du Raspberry Pi si tu débutes, installer Raspberry Pi OS pas-à-pas pour préparer ta carte SD, SSH headless pour administrer ton Pi sans écran, les 4 protocoles GPIO/I2C/SPI/UART pour comprendre I2C en profondeur, et les 10 problèmes Pi les plus courants si quelque chose coince.

Pour un capteur température seul (sans humidité ni pression), le DS18B20 reste une alternative intéressante : IC nu à ~1 €, sonde étanche câblée à 3-5 €, idéal pour mesurer la température d’un bassin, d’un congélateur ou d’un sol extérieur. Bus 1-Wire Dallas/Maxim, plusieurs capteurs en parallèle sur la même ligne grâce aux adresses 64 bits uniques de chaque sonde.

Dépannage : 6 problèmes courants

Si quelque chose ne marche pas du premier coup, voici les six symptômes les plus fréquents et comment les diagnostiquer.

SymptômeCause probableSolution
i2cdetect videI2C désactivé ou SDA/SCL inverséssudo raspi-config, Interface, I2C, Enable, puis vérifier les câbles (SDA = GPIO 2, SCL = GPIO 3)
Adresse 0x77 au lieu de 0x76Pad SDO du breakout en position alternativeAdapter le code : address=0x77 dans l’instanciation
Température lue 2-3 °C trop hauteSelf-heating BME280 en mode normal (mesure continue)Basculer en mode forced : bme.mode = adafruit_bme280.MODE_FORCE
Dashboard Flask inaccessibleMauvais hostname mDNS ou pare-feuTester http://IP_DU_PI:5000 avec l’IP, vérifier sudo ufw status
CSV grossit trop viteSleep trop court ou logging non rotatifVérifier sleep(60), ajouter logrotate mensuel
Pi Zero 2 W gèle après 24 hRAM saturée (Flask, script et desktop)Désactiver le desktop, passer en mode headless via SSH (cf. tutoriel SSH headless)

Questions fréquentes

BME280 ou BMP280, quelle différence ?

Le BMP280 mesure température et pression. Le BME280 ajoute l’humidité. Le BMP280 coûte 1 euro de moins. Pour une station météo complète, prends le BME280. Attention : certains vendeurs vendent du BMP280 estampillé BME280, vérifie en lisant l’humidité (un BMP280 retourne toujours 0 % ou une valeur fixe).

Quelle carte microSD choisir pour de la mesure 24/7 sur Raspberry Pi ?

Une carte microSD classe A1 ou A2, minimum 16 Go, de marque connue (SanDisk, Samsung, Kingston). Évite les cartes no-name : leur durée de vie en écriture continue se compte en semaines. Pour du long terme (1 an et plus), une carte industrielle SLC est recommandée, ou un boot sur SSD USB sur Pi 4 et Pi 5.

Comment accéder au dashboard depuis l’extérieur de la maison ?

La solution propre est un VPN auto-hébergé (WireGuard) sur le Pi ou sur le routeur. Tu te connectes au VPN depuis ton téléphone, puis tu accèdes à http://nom-du-pi.local:5000 comme si tu étais à la maison. Ne pas exposer le port 5000 directement sur Internet : Flask en mode développement n’est pas conçu pour ça et ouvre un risque de sécurité.

Le BME280 fonctionne-t-il en extérieur sous la pluie ?

Le BME280 nu n’est pas étanche : la pluie sur le PCB peut le tuer rapidement. Pour de l’extérieur, utiliser soit un boîtier IP65 avec une membrane Gore-Tex (laisse passer l’humidité de l’air mais pas la pluie), soit un abri Stevenson DIY ventilé. Sans protection, compter 2 à 6 mois en extérieur selon le climat.

Comment archiver les CSV sur le long terme ?

Trois options selon le besoin : un cron de rotation mensuelle qui compresse en data-YYYY-MM.csv.gz dans un dossier /archives/, un envoi périodique vers un NAS via rsync, ou une base SQLite avec partitionnement mensuel. Pour un projet domestique, la rotation cron+gzip suffit largement et tient des années sur 16 Go.

Peut-on connecter plusieurs BME280 sur le même Raspberry Pi ?

Deux maximum avec le bus I2C standard : un sur 0x76 et un sur 0x77 (en changeant le pad SDO du second breakout). Pour aller au-delà, utiliser un multiplexeur I2C comme le TCA9548A (8 canaux), ce qui permet de gérer 8 × 2 = 16 BME280 sur un seul Pi.

Sources et références

Une station météo Raspberry Pi reste l’un des meilleurs premiers projets IoT : peu de composants, câblage I2C en quatre fils, mesures visibles dès la première minute, et marge d’évolution claire vers Grafana ou Home Assistant. Dans ce tutoriel, on mesure température, humidité et pression atmosphérique avec un BME280, on stocke les données toutes les minutes dans un CSV, et on affiche les 24 dernières heures dans un mini-dashboard web Flask servi en local.

  • Durée : 45 à 90 minutes
  • 🔧 Niveau : Débutant / Intermédiaire
  • 💰 Coût hors Pi : 5 à 15 €
  • 📦 Matériel : Pi, BME280, câbles dupont, carte microSD
  • 🧪 Testé avec : Raspberry Pi OS Bookworm, Python 3.11, BME280 I2C

En résumé. Pour construire une station météo Raspberry Pi : branche un capteur BME280 en I2C sur les broches GPIO2 (SDA) et GPIO3 (SCL), lis température, humidité et pression avec la bibliothèque Adafruit en Python, stocke les mesures en CSV toutes les minutes, et affiche les 24 dernières heures dans un dashboard Flask avec Chart.js.

Matériel nécessaire

ComposantPrix indicatifRôle
Raspberry Pi (Zero 2 W, Pi 4 ou Pi 5)20-90 €Cerveau de la station, selon modèle choisi
Capteur BME280 (breakout board I2C)4-8 €Température + humidité + pression en un seul module
Câbles dupont femelle-femelle (4 fils)1 €Connexion I2C (VCC, GND, SDA, SCL)
Carte microSD + alim (si pas déjà en place)15-20 €Système + stockage données

Total hors Pi : 5 à 15 euros. C’est l’un des projets les moins chers qui existent en IoT domestique. Si tu hésitais entre un BME280 et un DHT22 (l’autre capteur classique), le BME280 a l’avantage dans la majorité des projets : il mesure aussi la pression atmosphérique (le DHT22 ne le fait pas), dérive moins sur la durée, répond plus vite, et utilise le bus I2C standard plutôt qu’un protocole single-wire spécifique au fabricant Aosong (à ne pas confondre avec le bus 1-Wire Dallas/Maxim utilisé par le DS18B20).

Côté précision de température, le DHT22 est légèrement meilleur sur sa plage garantie : ±0,5 °C de 0 à 50 °C, là où le BME280 affiche ±1 °C. La plage opérationnelle du DHT22 va de -40 à +80 °C selon la datasheet Aosong AM2302, mais la précision se dégrade en dehors de 0-50 °C. Sa précision humidité (±2 % RH) est garantie de 0 à 80 % RH, avec un risque de condensation au-dessus de 80 % qui peut endommager le capteur à long terme.

Tableau comparatif BME280 vs DHT22 vs DS18B20

CapteurHumiditéPressionPrécision T°PrixBus
BME280ouiouioui±1 °C4-8 €I2C standard
DHT22ouiouinon±0,5 °C (0-50 °C)6-10 €single-wire Aosong
DS18B20ouinonnon±0,5 °C1-5 €1-Wire Dallas/Maxim

Câblage I2C

Quatre fils, aucun composant supplémentaire à ajouter dans la majorité des cas : la plupart des breakouts BME280 du commerce intègrent déjà les résistances de pull-up I2C (10 kΩ), et les broches GPIO2/GPIO3 du Raspberry Pi ont également des pull-ups fixes sur le PCB (1,8 kΩ). Si tu utilises un BME280 nu sans breakout, ajoute deux résistances 4,7 kΩ entre SDA et 3,3 V, ainsi qu’entre SCL et 3,3 V.

Broche BME280Broche PiNom
VIN (ou VCC)Pin 1 (3,3V)Alimentation
GNDPin 6 (GND)Masse
SDAGPIO 2 (Pin 3)Data I2C
SCLGPIO 3 (Pin 5)Clock I2C

Après branchement, active I2C si ce n’est pas déjà fait (sudo raspi-config → Interface Options → I2C → Enable). Vérifie que le capteur est détecté :

sudo i2cdetect -y 1

Tu devrais voir l’adresse 0x76 ou 0x77 dans la grille. Si rien n’apparaît : vérifie les soudures sur le breakout, inverse SDA et SCL (ça arrive souvent), et confirme que l’alimentation est sur 3,3V et non 5V (certains breakouts tolèrent les deux, mais pas tous).

💡 L’emplacement du capteur compte autant que le capteur. Un BME280 dans un boîtier fermé posé sur un rebord de fenêtre en plein soleil va lire la température de la fenêtre, pas celle de l’air. Pour une vraie mesure météo : abri ventilé (type abri Stevenson DIY), à 1,5 m du sol, à l’ombre ou orienté nord, à distance d’un mur chauffé. Pour une mesure intérieure ou un projet pédagogique sans prétention météo professionnelle, l’emplacement importe moins.

Script Python de lecture

#!/usr/bin/env python3
"""
meteo.py — Lecture du BME280 + stockage CSV
"""

import board
import adafruit_bme280.advanced as adafruit_bme280
import csv
import os
from datetime import datetime
from time import sleep

# Initialisation I2C + capteur
i2c = board.I2C()
bme = adafruit_bme280.Adafruit_BME280_I2C(i2c, address=0x76)

# Calibration altitude locale (optionnel, améliore la pression affichée)
bme.sea_level_pressure = 1013.25  # hPa, ajuster selon météo du jour
# Note self-heating : le BME280 chauffe légèrement (~0,5-1°C) en mode normal
# (mesure continue). Pour minimiser, basculer en mode forced :
# bme.mode = adafruit_bme280.MODE_FORCE  # mesure à la demande puis sleep

CSV_FILE = "/home/pi/meteo/data.csv"
os.makedirs(os.path.dirname(CSV_FILE), exist_ok=True)

# Écrire l'en-tête si fichier inexistant
if not os.path.exists(CSV_FILE):
    with open(CSV_FILE, "w", newline="") as f:
        csv.writer(f).writerow(["timestamp", "temp_c", "humidity_pct", "pressure_hpa"])

print("Station météo démarrée. Ctrl+C pour arrêter.")

try:
    while True:
        now = datetime.now().isoformat(timespec="seconds")
        temp = round(bme.temperature, 1)
        hum = round(bme.relative_humidity, 1)
        pres = round(bme.pressure, 1)

        print(f"[{now}] {temp}°C | {hum}% HR | {pres} hPa")

        with open(CSV_FILE, "a", newline="") as f:
            csv.writer(f).writerow([now, temp, hum, pres])

        sleep(60)  # une mesure par minute

except KeyboardInterrupt:
    print()  # saut de ligne
    print("Arrêt propre.")

Installe les dépendances avant de lancer :

⚠️ Sur Raspberry Pi OS Bookworm, l’installation directe via pip3 est bloquée par PEP 668 (« externally-managed-environment »). Utilise un environnement virtuel Python :

sudo apt install python3-venv python3-pip -y
python3 -m venv ~/meteo/venv
source ~/meteo/venv/bin/activate
pip install adafruit-circuitpython-bme280

Le script écrit une ligne par minute dans un fichier CSV. Au bout de 24 heures, tu as 1440 points de mesure, soit un graphique de température avec une résolution d’une minute. Le fichier CSV grossit de moins de 1 Mo par mois, ce qui est négligeable même sur une carte SD de 16 Go.

Dashboard web avec Flask

Pour visualiser les données sans ouvrir le CSV à la main, on monte un mini-serveur web Flask qui affiche les dernières mesures et un graphique des 24 dernières heures.

#!/usr/bin/env python3
"""
dashboard.py — Serveur web Flask pour la station météo
"""

from flask import Flask, render_template_string
import csv

app = Flask(__name__)
CSV_FILE = "/home/pi/meteo/data.csv"

TEMPLATE = """


    
    
    Station météo Raspberry Pi
    
    


    

Station météo Raspberry Pi

{{ last.temp }} °CTempérature
{{ last.hum }} %Humidité
{{ last.pres }} hPaPression
""" @app.route("/") def index(): rows = [] with open(CSV_FILE) as f: for row in csv.DictReader(f): rows.append(row) last_24h = rows[-1440:] if len(rows) > 1440 else rows chart_data = { "labels": [r["timestamp"][-8:-3] for r in last_24h[::10]], "temp": [float(r["temp_c"]) for r in last_24h[::10]], "hum": [float(r["humidity_pct"]) for r in last_24h[::10]], } import json last = {"temp": rows[-1]["temp_c"], "hum": rows[-1]["humidity_pct"], "pres": rows[-1]["pressure_hpa"]} if rows else {} return render_template_string(TEMPLATE, last=last, chart_data=json.dumps(chart_data)) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)
source ~/meteo/venv/bin/activate
pip install flask
python dashboard.py

Ouvre http://nom-du-pi.local:5000 depuis n’importe quel navigateur du réseau local. Tu verras la dernière mesure en gros et un graphique Chart.js des dernières 24 heures. L’échantillonnage à 1 point sur 10 (une mesure toutes les 10 minutes affichée) garde le graphique lisible sans noyer le navigateur. Pour accéder au dashboard en dehors de chez toi, la solution propre est un VPN (WireGuard), pas d’exposer le port 5000 sur Internet.

Faire tourner en continu avec systemd

Pour que le script de lecture et le dashboard se lancent automatiquement au démarrage du Pi, on crée deux services systemd :

# /etc/systemd/system/meteo-reader.service
[Unit]
Description=Station météo - lecteur BME280
After=network.target

[Service]
ExecStart=/home/pi/meteo/venv/bin/python /home/pi/meteo/meteo.py
WorkingDirectory=/home/pi/meteo
Restart=always
User=pi

[Install]
WantedBy=multi-user.target
sudo systemctl enable meteo-reader
sudo systemctl start meteo-reader
sudo systemctl status meteo-reader

Même principe pour le dashboard Flask : créer /etc/systemd/system/meteo-dashboard.service, pointer son ExecStart vers ~/meteo/venv/bin/python /home/pi/meteo/dashboard.py, puis enable et start. Après ça, le Pi démarre et commence à mesurer en autonome.

Avec cette configuration, un Pi Zero 2 W tourne typiquement 4 à 6 mois en mesure continue avant que la carte microSD ne montre les premiers signes de fatigue (latences d’écriture, secteurs réalloués). Sur une carte industrielle SLC ou en boot SSD USB, on dépasse facilement 2 à 3 ans sans intervention.

Améliorations possibles

  • Écran OLED SSD1306 (5 euros) : afficher les mesures en temps réel sur un petit écran 128×64 pixels fixé au boîtier, sans avoir à ouvrir un navigateur.
  • Alertes par Telegram : un bot Telegram qui envoie un message si la température descend sous 5 °C ou si l’humidité dépasse 80 %. Vingt lignes de Python avec la bibliothèque python-telegram-bot.
  • Capteur d’indice de qualité d’air (CCS811 ou SGP30) : ces capteurs mesurent les composés organiques volatils (COV) et estiment un eCO₂ par corrélation, ce n’est pas une mesure directe de CO₂. Pour mesurer le CO₂ ambiant réel, il faut un capteur NDIR comme le Sensirion SCD41 (~30 €) ou le MH-Z19 (~15 €). Connexion I2C, même bus que le BME280.
  • Envoi vers InfluxDB + Grafana : pour les utilisateurs avancés qui veulent un dashboard professionnel avec rétention longue et agrégations temporelles. InfluxDB tourne sur Pi 4/5 sans problème.

Pour creuser : le guide ultime du Raspberry Pi si tu débutes, installer Raspberry Pi OS pas-à-pas pour préparer ta carte SD, SSH headless pour administrer ton Pi sans écran, les 4 protocoles GPIO/I2C/SPI/UART pour comprendre I2C en profondeur, et les 10 problèmes Pi les plus courants si quelque chose coince.

Pour un capteur température seul (sans humidité ni pression), le DS18B20 reste une alternative intéressante : IC nu à ~1 €, sonde étanche câblée à 3-5 €, idéal pour mesurer la température d’un bassin, d’un congélateur ou d’un sol extérieur. Bus 1-Wire Dallas/Maxim, plusieurs capteurs en parallèle sur la même ligne grâce aux adresses 64 bits uniques de chaque sonde.

Dépannage : 6 problèmes courants

Si quelque chose ne marche pas du premier coup, voici les six symptômes les plus fréquents et comment les diagnostiquer.

SymptômeCause probableSolution
i2cdetect videI2C désactivé ou SDA/SCL inverséssudo raspi-config, Interface, I2C, Enable, puis vérifier les câbles (SDA = GPIO 2, SCL = GPIO 3)
Adresse 0x77 au lieu de 0x76Pad SDO du breakout en position alternativeAdapter le code : address=0x77 dans l’instanciation
Température lue 2-3 °C trop hauteSelf-heating BME280 en mode normal (mesure continue)Basculer en mode forced : bme.mode = adafruit_bme280.MODE_FORCE
Dashboard Flask inaccessibleMauvais hostname mDNS ou pare-feuTester http://IP_DU_PI:5000 avec l’IP, vérifier sudo ufw status
CSV grossit trop viteSleep trop court ou logging non rotatifVérifier sleep(60), ajouter logrotate mensuel
Pi Zero 2 W gèle après 24 hRAM saturée (Flask, script et desktop)Désactiver le desktop, passer en mode headless via SSH (cf. tutoriel SSH headless)

Questions fréquentes

BME280 ou BMP280, quelle différence ?

Le BMP280 mesure température et pression. Le BME280 ajoute l’humidité. Le BMP280 coûte 1 euro de moins. Pour une station météo complète, prends le BME280. Attention : certains vendeurs vendent du BMP280 estampillé BME280, vérifie en lisant l’humidité (un BMP280 retourne toujours 0 % ou une valeur fixe).

Quelle carte microSD choisir pour de la mesure 24/7 sur Raspberry Pi ?

Une carte microSD classe A1 ou A2, minimum 16 Go, de marque connue (SanDisk, Samsung, Kingston). Évite les cartes no-name : leur durée de vie en écriture continue se compte en semaines. Pour du long terme (1 an et plus), une carte industrielle SLC est recommandée, ou un boot sur SSD USB sur Pi 4 et Pi 5.

Comment accéder au dashboard depuis l’extérieur de la maison ?

La solution propre est un VPN auto-hébergé (WireGuard) sur le Pi ou sur le routeur. Tu te connectes au VPN depuis ton téléphone, puis tu accèdes à http://nom-du-pi.local:5000 comme si tu étais à la maison. Ne pas exposer le port 5000 directement sur Internet : Flask en mode développement n’est pas conçu pour ça et ouvre un risque de sécurité.

Le BME280 fonctionne-t-il en extérieur sous la pluie ?

Le BME280 nu n’est pas étanche : la pluie sur le PCB peut le tuer rapidement. Pour de l’extérieur, utiliser soit un boîtier IP65 avec une membrane Gore-Tex (laisse passer l’humidité de l’air mais pas la pluie), soit un abri Stevenson DIY ventilé. Sans protection, compter 2 à 6 mois en extérieur selon le climat.

Comment archiver les CSV sur le long terme ?

Trois options selon le besoin : un cron de rotation mensuelle qui compresse en data-YYYY-MM.csv.gz dans un dossier /archives/, un envoi périodique vers un NAS via rsync, ou une base SQLite avec partitionnement mensuel. Pour un projet domestique, la rotation cron+gzip suffit largement et tient des années sur 16 Go.

Peut-on connecter plusieurs BME280 sur le même Raspberry Pi ?

Deux maximum avec le bus I2C standard : un sur 0x76 et un sur 0x77 (en changeant le pad SDO du second breakout). Pour aller au-delà, utiliser un multiplexeur I2C comme le TCA9548A (8 canaux), ce qui permet de gérer 8 × 2 = 16 BME280 sur un seul Pi.

Sources et références

Autres projets DIY

Projet DIY

Robot 2 roues autonome avec Raspberry Pi : le tutoriel complet

Le projet parfait pour démarrer en robotique DIY : construire un petit robot mobile qui évite les obstacles, avec un Raspberry Pi, un module L298N, deux moteurs et un capteur ultrason. Matériel, câblage, code Python commenté.