🛠 Heure exacte via NTP : l'horloge temps réel des projets connectés
Objectifs
Le RP2040 n'a pas d'horloge temps réel : sans source de temps, time.time repart de zéro (ou de 2000) à chaque reset — rédhibitoire pour horodater des mesures ou faire du HTTPS. Le SDK officiel fournit un exemple NTP complet dans pico_w/wifi/ (dossier ntp) ; en MicroPython, quelques lignes de socket UDP suffisent. Tu vas comprendre le paquet NTP v3 de 48 octets, le décalage d'époque 1900→1970, et pourquoi le mode SNTP du SDK est plus propre en C.
Matériel
- 1 × Raspberry Pi Pico W + firmware MicroPython
_picow - Accès Internet (sortie UDP port 123 autorisée — certaines box d'entreprise la bloquent)
- Console série 115200 bauds
Code complet
# ntp.py — synchronisation NTP en MicroPython (UDP brut, paquet 48 octets)
import machine, network, socket, time
wlan = network.WLAN; wlan.active(True)
if not wlan.isconnected:
wlan.connect('my_ssid', 'my_password')
while not wlan.isconnected:
machine.idle
NTP_EPOCH_OFFSET = 2208988800 # secondes entre 1900 et 1970
def sync_time(server='pool.ntp.org'):
addr = socket.getaddrinfo(server, 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(5)
pkt = bytearray(48)
pkt[0] = 0x1B # LI=0, VN=3, mode=3 (client)
s.sendto(pkt, addr)
data = s.recv(48)[0]
secs = int.from_bytes(data[40:44], 'big') - NTP_EPOCH_OFFSET
machine.RTC.datetime((1970, 1, 1, 0, 0, 0, 0, 0)[:3] +
time.gmtime(secs)[3:6] + (0,))
return secs
t = sync_time
print('UTC :', time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(t)))
# En C SDK : exemple officiel pico_w/wifi/ntp (lwIP) ; lwIP expose aussi
# une API SNTP — >
# de lwIP embarquée dans le Pico SDK (sntp_setserver vs sntp_set_server).
Vérification attendue
La console affiche la date/heure UTC courante, cohérente avec ton PC. Après synchronisation, time.time renvoie de vraies secondes POSIX : tes journaux de capteurs sont horodatés, et le HTTPS avec validation de certificat devient possible. Relance un script sans sync : l'heure repart de zéro — la preuve que le RP2040 ne retient rien sans NTP (pas de RTC, pas de batterie).
Erreurs fréquentes
- Oublier le décalage d'époque : sans les 2 208 988 800 secondes, tu te retrouves en 2039 — NTP compte depuis 1900, Unix depuis 1970.
- UDP 123 bloqué par le routeur/la box : le
recvexpire ; teste avec un autre réseau ou un serveur NTP sur un autre port (certaines implémentations utilisent 123 en sortie, généralement accepté). - Croire l'heure persistante : chaque reset efface l'horloge — resynchronise au boot dans
main.py, ou ajoute une RTC externe (I²C DS3231 sur les GPIO libres GP0–GP22/GP26–GP28). - Paquet trop court :
recv(48)doit lire les 48 octets complets ; un serveur qui répond en IPv6 surgetaddrinfopeut surprendre — forceAF_INET. - En C SDK, mélanger les variantes d'arch : avec
pico_cyw43_arch_lwip_threadbackground, les appels lwIP doivent être entourés du verrou d'arch (cyw43_arch_lwip_begin/end) — voir le tuto SDK avancé.
Autres tutoriels pour cette carte
- Faire clignoter la LED embarquée (elle est derrière la puce Wi-Fi !)
- Se connecter à un réseau Wi-Fi (station, WPA2/WPA3)
- Bouton et potentiomètre sans marcher sur le sans-fil (GPIO libres & ADC)
- Servir une page web depuis la Pico W (socket TCP + HTTP)
- Client HTTP : consommer une API depuis la Pico W
- Client MQTT : télémétrie IoT légère sur la Pico W
Exemples de code pour cette carte
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython