import machine
import time
import network
import socket
import gc
# --- 1. CONFIGURATION MATÉRIELLE ---
i2c = machine.I2C(0, sda=machine.Pin(20), scl=machine.Pin(21))
RTC_ADDR = 0x68
capteur_lum = machine.ADC(machine.Pin(27))
relais = machine.Pin(2, machine.Pin.OUT)
led_pico = machine.Pin("LED", machine.Pin.OUT)
# --- 2. PARAMÈTRES (Variables globales) ---
SEUIL_LUM = 15000
MARGE = 2000
START_HOUR = 5
END_HOUR = 20
START_MIN = 0
END_MIN = 0
SSID = "MA SERRE JOYEUSE"
PASSWORD = "serre1234"
# --- 3. FONCTIONS UTILES ---
def bcd_to_dec(bcd):
return (bcd // 16) * 10 + (bcd % 16)
def dec_to_bcd(dec):
return (dec // 10) * 16 + (dec % 10)
def get_rtc_time():
try:
data = i2c.readfrom_mem(RTC_ADDR, 0x00, 7)
return bcd_to_dec(data[2] & 0x3F), bcd_to_dec(data[1]), bcd_to_dec(data[0])
except:
return None
def set_rtc_time(h, m, s):
try:
data = bytearray([dec_to_bcd(s), dec_to_bcd(m), dec_to_bcd(h)])
i2c.writeto_mem(RTC_ADDR, 0x00, data)
except:
pass
def check_schedule(h, m, start_h, end_h):
now = h * 60 + m
start = start_h * 60
end = end_h * 60
if start <= end:
return start <= now < end
return now >= start or now < end
def get_webpage(h, m, dans_plage, relais_state):
color = "#2ecc71" if dans_plage else "#e74c3c"
plage_txt = "DANS LA PLAGE HORAIRE" if dans_plage else "HORS PLAGE HORAIRE"
led_class = "led-on" if relais_state == 1 else ""
led_txt = "ALLUMÉ" if relais_state == 1 else "ÉTEINT"
heure_actuelle = "{:02d}:{:02d}:{:02d}".format(h, m, 0)
return f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {{ background: #050505; color: #fff; font-family: 'Segoe UI', sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; }}
.card {{ background: rgba(17, 17, 17, 0.9); padding: 25px; border-radius: 30px; text-align: center; border: 1px solid #333; width: 90%; max-width: 350px; backdrop-filter: blur(10px); }}
.badge {{ display: inline-block; padding: 5px 15px; border-radius: 10px; border: 1px solid {color}; color: {color}; font-size: 0.8rem; margin-bottom: 15px; }}
.led {{ width: 60px; height: 60px; background: #222; border-radius: 15px; margin: 10px auto; border: 3px solid #333; transition: 0.5s; }}
.led-on {{ background: #f1c40f; box-shadow: 0 0 30px #f1c40f; border-color: #fff; }}
.time-now {{ color: {color}; font-size: 2.2rem; font-weight: bold; margin: 10px 0; }}
form {{ margin-top: 20px; padding-top: 15px; border-top: 1px solid #333; display: flex; flex-direction: column; gap: 10px; }}
input {{ background: #222; border: 1px solid #444; color: white; padding: 8px; border-radius: 8px; text-align: center; }}
button {{ background: #2ecc71; border: none; color: white; padding: 12px; border-radius: 8px; font-weight: bold; cursor: pointer; }}
.sync-btn {{ background: #3498db; margin-top: 10px; font-size: 0.8rem; }}
</style>
</head>
<body>
<div class="card">
<div style="font-size: 2rem;">🌱☀️</div>
<h1>MA SERRE</h1>
<div class="badge">{plage_txt}</div>
<div class="led {led_class}"></div>
<p>Éclairage : <strong>{led_txt}</strong></p>
<div class="time-now" id="clock">{heure_actuelle}</div>
<form action="/" method="GET">
<label>Début (Heure): <input type="number" name="start" value="{START_HOUR}" min="0" max="23"></label>
<label>Fin (Heure): <input type="number" name="end" value="{END_HOUR}" min="0" max="23"></label>
<button type="submit">Appliquer Plage</button>
</form>
<button class="sync-btn" onclick="syncTime()">Mettre à l'heure</button>
</div>
<script>
function syncTime() {{
const now = new Date();
window.location.href = `/?set_time=${{now.getHours()}}:${{now.getMinutes()}}:${{now.getSeconds()}}`;
}}
// Auto-refresh uniquement si on n'est pas en train de régler l'heure
setTimeout(() => {{
if(!window.location.search) location.href = '/';
}}, 5000);
</script>
</body>
</html>"""
# --- 4. RÉSEAU ---
ap = network.WLAN(network.AP_IF)
ap.config(essid=SSID, password=PASSWORD)
ap.active(True)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(0.1)
s.bind(('', 80))
s.listen(5)
# --- 5. BOUCLE PRINCIPALE ---
relais_virtuel = 0
dernier_changement = time.time()
while True:
try:
gc.collect()
time_data = get_rtc_time()
valeur_lum = capteur_lum.read_u16()
h, m, sec = time_data if time_data else (0, 0, 0)
dans_plage = check_schedule(h, m, START_HOUR, END_HOUR)
seuil_actuel = SEUIL_LUM + (MARGE if relais_virtuel == 1 else -MARGE)
fait_sombre = valeur_lum < seuil_actuel
nouvel_etat = 1 if (dans_plage and fait_sombre) else 0
if nouvel_etat != relais_virtuel and (time.time() - dernier_changement) > 2:
relais_virtuel = nouvel_etat
relais.value(relais_virtuel)
led_pico.value(relais_virtuel)
dernier_changement = time.time()
try:
cl, addr = s.accept()
request = cl.recv(1024).decode('utf-8')
# Action : Synchroniser l'heure
if "GET /?set_time=" in request:
time_str = request.split("set_time=")[1].split(" ")[0]
h_c, m_c, s_c = map(int, time_str.split(":"))
set_rtc_time(h_c, m_c, s_c)
cl.send('HTTP/1.1 303 See Other\r\nLocation: /\r\n\r\n')
cl.close()
continue
# Action : Changer la plage
if "GET /?start=" in request:
START_HOUR = int(request.split("start=")[1].split("&")[0])
END_HOUR = int(request.split("end=")[1].split(" ")[0])
cl.send('HTTP/1.1 303 See Other\r\nLocation: /\r\n\r\n')
cl.close()
continue
# Affichage normal
response = get_webpage(h, m, dans_plage, relais_virtuel)
cl.send('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n' + response)
cl.close()
except OSError:
pass
except Exception as e:
time.sleep(0.1)
Loading
pi-pico-w
pi-pico-w