import machine
import time
import dht
import network
from machine import Pin, I2C, ADC, PWM
from neopixel import NeoPixel
# --- MINI LIBRAIRIE LCD I2C (Pour simplifier la vie des étudiants) ---
class I2cLcd:
def __init__(self, i2c, i2c_addr, num_lines, num_columns):
self.i2c = i2c
self.i2c_addr = i2c_addr
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x33]))
time.sleep(0.005)
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x32]))
time.sleep(0.005)
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x28]))
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x0C]))
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x06]))
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x01]))
def putstr(self, string):
for char in string:
self.i2c.writeto(self.i2c_addr, bytearray([0x40, ord(char)]))
def clear(self):
self.i2c.writeto(self.i2c_addr, bytearray([0, 0x01]))
def move_to(self, cursor_x, cursor_y):
addr = 0x80 + 0x40 * cursor_y + cursor_x
self.i2c.writeto(self.i2c_addr, bytearray([0, addr]))
# --- CONFIGURATION MATÉRIEL ---
# 1. Capteurs
sensor_dht = dht.DHT22(Pin(15))
sensor_ldr = ADC(Pin(34))
sensor_ldr.atten(ADC.ATTN_11DB) # Pour lire jusqu'à 3.3V
# 2. Actionneurs
servo = PWM(Pin(13), freq=50) # Servo 50Hz
relay_pompe = Pin(4, Pin.OUT)
# 3. Lumières
np = NeoPixel(Pin(5), 16) # Anneau de 16 LEDs
# 4. Affichage
i2c = I2C(0, sda=Pin(21), scl=Pin(22), freq=400000)
lcd = I2cLcd(i2c, 0x27, 2, 16) # Adresse 0x27 standard
# 5. Logique (Shift Register 74HC595)
sr_data = Pin(12, Pin.OUT)
sr_clock = Pin(14, Pin.OUT)
sr_latch = Pin(33, Pin.OUT)
# --- FONCTIONS UTILITAIRES ---
def set_servo_angle(angle):
# Conversion angle 0-180 vers duty cycle PWM
duty = int(((angle / 180) * 102 + 26))
servo.duty(duty)
def update_shift_register(valeur_byte):
# Envoi de 8 bits vers le 74HC595 (Bit-banging simple)
sr_latch.off()
for i in range(8):
bit = (valeur_byte >> i) & 1
sr_data.value(bit)
sr_clock.on()
sr_clock.off()
sr_latch.on()
def set_grow_light(color):
for i in range(16):
np[i] = color
np.write()
def connect_wifi():
print("Connexion au WiFi...", end="")
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("Wokwi-GUEST", "")
timeout = 10
while not wlan.isconnected() and timeout > 0:
time.sleep(1)
timeout -= 1
print(".", end="")
if wlan.isconnected():
print(" Connecté! IP:", wlan.ifconfig()[0])
lcd.clear()
lcd.putstr("WiFi OK!")
time.sleep(1)
else:
print(" Echec WiFi")
lcd.putstr("No WiFi")
# --- MAIN PROGRAM ---
lcd.putstr("Demarrage Serre...")
set_servo_angle(0) # Fenêtre fermée
connect_wifi()
while True:
# 1. ACQUISITION (Lire les capteurs)
try:
sensor_dht.measure()
temp = sensor_dht.temperature()
hum = sensor_dht.humidity()
except:
temp = 0
hum = 0
lux_raw = sensor_ldr.read() # 0-4095
# Inversion : Sur Wokwi LDR, valeur basse = sombre, haute = clair (ou inverse selon modèle)
# Disons que < 1000 = Nuit
# 2. LOGIQUE DE DÉCISION (Le Cerveau)
# A. Gestion Température -> Fenêtre (Servo)
if temp > 30:
set_servo_angle(90) # Ouvrir fenêtre
etat_fenetre = "OUV"
else:
set_servo_angle(0) # Fermer fenêtre
etat_fenetre = "FRM"
# B. Gestion Humidité -> Pompe (Relais)
if hum < 40:
relay_pompe.value(1) # Arroser
etat_pompe = "ON"
else:
relay_pompe.value(0) # Stop
etat_pompe = "OFF"
# C. Gestion Lumière -> NeoPixels
if lux_raw < 1000: # S'il fait nuit
set_grow_light((50, 0, 50)) # Lumière Violette (Croissance)
else:
set_grow_light((0, 0, 0)) # Éteindre
# D. Gestion Shift Register (Barre de statut)
# On affiche le niveau d'humidité sur 8 LEDs
# Map 0-100% vers 0-8 LEDs
nb_leds = int((hum / 100) * 8)
masque_binaire = (1 << nb_leds) - 1 # Ex: 3 leds -> 00000111
update_shift_register(masque_binaire)
# 3. AFFICHAGE (LCD)
lcd.clear()
lcd.move_to(0,0)
lcd.putstr("T:{}C H:{}%".format(temp, hum))
lcd.move_to(0,1)
lcd.putstr("F:{} P:{}".format(etat_fenetre, etat_pompe))
# 4. DATA LOGGING (Simulation Envoi Cloud via Console)
print(f"DATA >> Temp:{temp}, Hum:{hum}, Lux:{lux_raw}")
time.sleep(2)