# ==========================================================
# WeatherStation Pro - Code complet
# Plateforme : Raspberry Pi Pico + MicroPython
# Simulateur : Wokwi
# ==========================================================
from machine import Pin, I2C, PWM, ADC
from time import sleep, ticks_ms
import ssd1306
import bmp180
import dht
from servo import Servo
# ==========================================================
# 1. INITIALISATION DES COMPOSANTS
# ==========================================================
# --- Bus I2C (OLED + BMP180) ---
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
# --- Ecran OLED 128x64 ---
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# --- Capteur BMP180 (pression atmospherique) ---
bmp = bmp180.BMP180(i2c)
# --- Capteurs DHT22 (temperature + humidite) ---
dht1 = dht.DHT22(Pin(2)) # Zone 1
dht2 = dht.DHT22(Pin(3)) # Zone 2
# --- LED RGB (3 broches PWM) ---
led_r = PWM(Pin(10))
led_g = PWM(Pin(11))
led_b = PWM(Pin(12))
led_r.freq(1000)
led_g.freq(1000)
led_b.freq(1000)
# --- Servomoteur (ventilation simulee) ---
servo = Servo(pin=16)
# --- Buzzer passif ---
buzzer = PWM(Pin(20))
buzzer.duty_u16(0)
# --- Boutons (pull-up interne) ---
btn_nav = Pin(18, Pin.IN, Pin.PULL_UP) # Navigation ecrans
btn_reset = Pin(19, Pin.IN, Pin.PULL_UP) # Reset alarme
# --- Potentiometre (simulation CO2) ---
co2_sim = ADC(26)
# ==========================================================
# 2. VARIABLES GLOBALES
# ==========================================================
# Valeurs des capteurs
temp1 = 24.0
hum1 = 40.0
temp2 = 24.0
hum2 = 40.0
pression = 1013.25
temp_bmp = 25.0
co2 = 0
# Ecran courant (0 a 3)
ecran_actuel = 0
# Historique min/max par zone
temp1_max = -999
temp1_min = 999
temp2_max = -999
temp2_min = 999
hum1_max = -999
hum1_min = 999
hum2_max = -999
hum2_min = 999
# Etat de chaque type d'alerte (True = active, False = inactive)
alerte_temp_active = False
alerte_hum_active = False
alerte_co2_active = False
# Position actuelle du servo (pour eviter les ordres redondants)
position_servo = -1 # -1 = inconnu au demarrage
# Anti-rebond boutons
dernier_appui_nav = 0
dernier_appui_reset = 0
# ==========================================================
# 3. FONCTIONS UTILITAIRES (LED RGB et BUZZER)
# ==========================================================
def set_rgb(r, g, b):
"""Definit la couleur de la LED RGB (chaque valeur entre 0 et 65535)"""
led_r.duty_u16(r)
led_g.duty_u16(g)
led_b.duty_u16(b)
def rgb_off():
set_rgb(0, 0, 0)
def rgb_rouge():
set_rgb(65535, 0, 0)
def rgb_vert():
set_rgb(0, 65535, 0)
def rgb_bleu():
set_rgb(0, 0, 65535)
def beep(freq, duree):
"""Joue un bip a la frequence et duree donnees"""
buzzer.freq(freq)
buzzer.duty_u16(30000)
sleep(duree)
buzzer.duty_u16(0)
def alerte_temp():
"""Alerte temperature : 2 bips moyens"""
beep(1000, 0.2)
sleep(0.1)
beep(1000, 0.2)
def alerte_hum():
"""Alerte humidite : 1 bip long grave"""
beep(700, 0.5)
def alerte_co2():
"""Alerte CO2 : 3 bips rapides aigus"""
for _ in range(3):
beep(1500, 0.1)
sleep(0.05)
# ==========================================================
# 4. LECTURE DES CAPTEURS
# ==========================================================
def lire_capteurs():
"""Met a jour toutes les variables globales avec les nouvelles valeurs"""
global temp1, hum1, temp2, hum2
global pression, temp_bmp, co2
# --- DHT22 Zone 1 ---
try:
dht1.measure()
temp1 = dht1.temperature()
hum1 = dht1.humidity()
except OSError:
pass
# --- DHT22 Zone 2 ---
try:
dht2.measure()
temp2 = dht2.temperature()
hum2 = dht2.humidity()
except OSError:
pass
# --- BMP180 ---
pression = bmp.pressure
temp_bmp = bmp.temperature
# --- CO2 simule (potard) ---
co2 = int((co2_sim.read_u16() / 65535) * 100)
# --- Mise a jour de l'historique par zone ---
global temp1_max, temp1_min, temp2_max, temp2_min
global hum1_max, hum1_min, hum2_max, hum2_min
# Zone 1 : temperature
if temp1 > temp1_max:
temp1_max = temp1
if temp1 < temp1_min:
temp1_min = temp1
# Zone 2 : temperature
if temp2 > temp2_max:
temp2_max = temp2
if temp2 < temp2_min:
temp2_min = temp2
# Zone 1 : humidite
if hum1 > hum1_max:
hum1_max = hum1
if hum1 < hum1_min:
hum1_min = hum1
# Zone 2 : humidite
if hum2 > hum2_max:
hum2_max = hum2
if hum2 < hum2_min:
hum2_min = hum2
# ==========================================================
# 5. AFFICHAGE OLED - 4 ECRANS
# ==========================================================
def ecran_temperatures():
"""Ecran 0 : Temperatures des 2 zones"""
oled.fill(0)
oled.text("TEMPERATURES", 25, 0)
oled.text("------------", 25, 10)
oled.text("Zone 1: {}C".format(temp1), 0, 24)
oled.text("Zone 2: {}C".format(temp2), 0, 36)
oled.text("Ecran 1/4", 25, 54)
oled.show()
def ecran_humidite_pression():
"""Ecran 1 : Humidite + Pression atmospherique"""
oled.fill(0)
oled.text("HUM + PRESSION", 12, 0)
oled.text("--------------", 12, 10)
oled.text("H1: {}%".format(hum1), 0, 22)
oled.text("H2: {}%".format(hum2), 0, 32)
oled.text("P: {}hPa".format(round(pression, 1)), 0, 44)
oled.text("Ecran 2/4", 25, 54)
oled.show()
def ecran_air_statut():
"""Ecran 2 : Qualite air + Statut global"""
oled.fill(0)
oled.text("QUALITE AIR", 25, 0)
oled.text("-----------", 25, 10)
oled.text("CO2: {}%".format(co2), 0, 22)
if co2 > 70:
oled.text("STATUT: ALERTE", 0, 36)
else:
oled.text("STATUT: NORMAL", 0, 36)
oled.text("Ecran 3/4", 25, 54)
oled.show()
def ecran_historique():
"""Ecran 3 : Historique min/max par zone"""
oled.fill(0)
oled.text("HISTORIQUE", 25, 0)
oled.text("----------", 25, 10)
# Temperatures (Z1 et Z2)
oled.text("T1 {}/{}".format(round(temp1_min, 0), round(temp1_max, 0)), 0, 22)
oled.text("T2 {}/{}".format(round(temp2_min, 0), round(temp2_max, 0)), 0, 32)
# Humidites (Z1 et Z2)
oled.text("H1 {}/{}".format(round(hum1_min, 0), round(hum1_max, 0)), 0, 44)
oled.text("H2 {}/{}".format(round(hum2_min, 0), round(hum2_max, 0)), 0, 54)
oled.show()
def afficher_ecran_actuel():
"""Affiche l'ecran selon la variable ecran_actuel"""
if ecran_actuel == 0:
ecran_temperatures()
elif ecran_actuel == 1:
ecran_humidite_pression()
elif ecran_actuel == 2:
ecran_air_statut()
elif ecran_actuel == 3:
ecran_historique()
# ==========================================================
# 6. LOGIQUE : ALERTES ET BOUTONS
# ==========================================================
def gerer_alertes():
"""Verifie chaque seuil independamment et signale chaque nouvelle alerte"""
global alerte_temp_active, alerte_hum_active, alerte_co2_active
global position_servo
# Conditions d'alerte
temp_haute = temp1 > 35 or temp2 > 35
hum_haute = hum1 > 80 or hum2 > 80
co2_eleve = co2 > 70
# --- Detection des NOUVELLES alertes (transitions inactive -> active) ---
if temp_haute and not alerte_temp_active:
print("NOUVELLE ALERTE : Temperature")
alerte_temp()
alerte_temp_active = True
elif not temp_haute and alerte_temp_active:
print("Fin alerte temperature")
alerte_temp_active = False
if hum_haute and not alerte_hum_active:
print("NOUVELLE ALERTE : Humidite")
alerte_hum()
alerte_hum_active = True
elif not hum_haute and alerte_hum_active:
print("Fin alerte humidite")
alerte_hum_active = False
if co2_eleve and not alerte_co2_active:
print("NOUVELLE ALERTE : CO2")
alerte_co2()
alerte_co2_active = True
elif not co2_eleve and alerte_co2_active:
print("Fin alerte CO2")
alerte_co2_active = False
# --- Couleur de la LED selon les priorites ---
# Priorite : temp > co2 > hum > vert
if alerte_temp_active:
rgb_rouge()
elif alerte_co2_active:
rgb_rouge()
elif alerte_hum_active:
rgb_bleu()
else:
rgb_vert()
# --- Position du servo (ventilation) ---
if alerte_temp_active or alerte_co2_active:
nouvelle_position = 90
else:
nouvelle_position = 0
if nouvelle_position != position_servo:
servo.move(nouvelle_position)
position_servo = nouvelle_position
print("Servo deplace a {} degres".format(nouvelle_position))
def gerer_boutons():
"""Lit les boutons et applique l'action correspondante"""
global ecran_actuel
global alerte_temp_active, alerte_hum_active, alerte_co2_active
global dernier_appui_nav, dernier_appui_reset
maintenant = ticks_ms()
# --- Bouton navigation (anti-rebond 300 ms) ---
if btn_nav.value() == 0 and (maintenant - dernier_appui_nav) > 300:
ecran_actuel = (ecran_actuel + 1) % 4
print("Changement ecran -> {}".format(ecran_actuel))
dernier_appui_nav = maintenant
# --- Bouton reset alarme ---
if btn_reset.value() == 0 and (maintenant - dernier_appui_reset) > 300:
alerte_temp_active = False
alerte_hum_active = False
alerte_co2_active = False
buzzer.duty_u16(0)
print("Alarme reset")
dernier_appui_reset = maintenant
# ==========================================================
# 7. ECRAN DE DEMARRAGE
# ==========================================================
oled.fill(0)
oled.text("WeatherStation", 8, 12)
oled.text("Pro v1.0", 32, 24)
oled.text("EIC 2026", 28, 40)
oled.show()
rgb_vert()
servo.move(0)
sleep(2)
# ==========================================================
# 8. BOUCLE PRINCIPALE
# ==========================================================
print("=== WeatherStation Pro - Demarrage ===")
print("Bouton vert = changer ecran")
print("Bouton rouge = reset alarme")
while True:
lire_capteurs()
gerer_alertes()
gerer_boutons()
afficher_ecran_actuel()
sleep(0.05) # ← APRES : 50 ms