ESP32 Ethernet — initialisation, premier flash et OTA
Cette page décrit la cible actuellement prise en charge par leukOS : la WT32-ETH01 v1.4, basée sur un ESP32 et un PHY Ethernet LAN8720. Le firmware est un runtime générique : il ne contient ni le nom de la pièce, ni les identifiants des modules, ni leur câblage. Ces données arrivent ensuite sous forme de JSON, sans reflasher la carte.
Ce qui est flashé, et ce qui ne l'est pas
| Élément | Transport | Fréquence |
|---|---|---|
| Runtime générique ESP32 | UART au premier flash, OTA ensuite | Seulement quand le code du runtime change |
| Configuration de pièce | JSON sur TCP 3233 | À chaque modification d'une pièce ou d'un module |
| Commandes et états | Lignes texte sur TCP 23 | Pendant l'exploitation |
Le bouton Envoyer JSON de la page Domotique compile le runtime pour vérifier
qu'il reste valide, mais il ne transmet pas le binaire lorsque le contrôleur est
configuré avec une URL tcp://.... Il conserve le JSON dans SQLite puis envoie
ce même document à l'ESP32.
Prérequis
- une carte WT32-ETH01 v1.4 ;
- un adaptateur USB–UART utilisant une logique 3,3 V ;
- un câble Ethernet relié au même LAN que le node leukOS ;
arduino-cliet le cœur Arduino ESP32 installés ;- une alimentation stable adaptée à la carte ou à sa carte porteuse ;
- les ports TCP
23,3232et3233accessibles sur le réseau local.
:::danger Électricité et niveaux logiques Les GPIO de l'ESP32 ne tolèrent pas une logique UART à 5 V. Relier les masses, croiser TX et RX, et vérifier l'entrée d'alimentation de la carte porteuse avant la mise sous tension. Les relais secteur doivent être isolés et installés par une personne qualifiée. :::
Câblage du premier flash
Le premier chargement ne peut pas utiliser OTA, puisque le service OTA n'existe pas encore dans la carte. Il passe donc par l'UART :
| Adaptateur USB–UART | WT32-ETH01 |
|---|---|
| TX 3,3 V | RXD0 |
| RX 3,3 V | TXD0 |
| GND | GND |
Pour entrer dans le bootloader série :
- couper l'alimentation ;
- relier
IO0àGND; - remettre sous tension ou actionner
EN/RESET; - lancer le téléversement ;
- après succès, retirer le pont
IO0–GNDpuis redémarrer normalement.
Le port apparaît généralement comme /dev/ttyUSB0. Le vérifier avant toute
commande :
arduino-cli board list
ls -l /dev/ttyUSB*
Si l'accès est refusé, le compte qui lance leukOS ou arduino-cli doit avoir
accès au périphérique série, généralement via le groupe dialout.
1. Initialiser le runtime générique
La source de référence est générée par FirmwareGenerator dans
nodes/ui/src/domotics/firmware_generator.cpp. Pour l'obtenir depuis l'IHM :
- ouvrir Domotique et créer ou sélectionner la pièce ;
- choisir la carte
esp32-eth01-v1.4; - sélectionner le port série pour le tout premier chargement ;
- ouvrir la page Programme ;
- utiliser Valider runtime, puis téléverser sur le port série.
Le code commence par fixer le brochage LAN8720 et les trois services réseau :
#include <ArduinoOTA.h>
#include <ETH.h>
#include <Preferences.h>
#include <WiFi.h>
#include <cJSON.h>
#define ETH_PHY_ADDR 1
#define ETH_PHY_POWER 16
#define ETH_PHY_MDC 23
#define ETH_PHY_MDIO 18
#define ETH_PHY_TYPE ETH_PHY_LAN8720
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
static const IPAddress LEUKOS_STATIC_IP(192, 168, 0, 240);
static const IPAddress LEUKOS_GATEWAY(192, 168, 0, 1);
static const IPAddress LEUKOS_SUBNET(255, 255, 255, 0);
static const uint16_t LEUKOS_COMMAND_PORT = 23;
static const uint16_t LEUKOS_OTA_PORT = 3232;
static const uint16_t LEUKOS_CONFIG_PORT = 3233;
Ce bloc est matériel et réseau. Il est le seul endroit où l'adresse IP par défaut est fixée. Chaque ESP32 du même LAN doit avoir une adresse unique.
Compilation manuelle
Si le sketch généré a été exporté dans un dossier, il peut être compilé sans le téléverser :
arduino-cli compile \
--fqbn esp32:esp32:esp32 \
--output-dir /tmp/leukos-esp32-output \
--build-path /tmp/leukos-esp32-cache \
/chemin/vers/le/sketch
Le fichier d'application destiné à OTA porte normalement le suffixe
.ino.bin. Sur un Raspberry Pi utilisant une carte SD, le premier build peut
prendre plusieurs minutes : le cache de compilation doit rester dans /tmp,
et seul le .ino.bin utile est conservé durablement.
Premier téléversement manuel par UART
Après la compilation et avec la carte en mode bootloader :
arduino-cli upload \
--fqbn esp32:esp32:esp32 \
--port /dev/ttyUSB0 \
--input-dir /tmp/leukos-esp32-output \
/chemin/vers/le/sketch
Un effacement complet n'est pas nécessaire à chaque chargement. Il efface aussi la configuration JSON conservée en NVS ; il doit donc rester une opération de diagnostic ou de remise à zéro.
2. Démarrer Ethernet et OTA
Le runtime attend l'événement ETH_GOT_IP avant d'ouvrir ses serveurs. OTA
n'est donc annoncé que lorsque le lien Ethernet est réellement opérationnel :
WiFi.onEvent([](WiFiEvent_t event) {
if (event == ARDUINO_EVENT_ETH_START)
ETH.setHostname("leukos-domotics");
if (event == ARDUINO_EVENT_ETH_DISCONNECTED)
networkReady = false;
if (event == ARDUINO_EVENT_ETH_GOT_IP && !networkReady) {
commandServer.begin();
configServer.begin();
ArduinoOTA.setHostname("leukos-domotics");
ArduinoOTA.setPort(LEUKOS_OTA_PORT);
ArduinoOTA.begin();
networkReady = true;
}
});
ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO,
ETH_PHY_POWER, ETH_CLK_MODE);
ETH.config(LEUKOS_STATIC_IP, LEUKOS_GATEWAY, LEUKOS_SUBNET);
ArduinoOTA.begin() initialise le service sur le port 3232. Cela ne suffit
pas : la boucle principale doit lui rendre la main fréquemment.
void loop() {
if (networkReady) {
ArduinoOTA.handle();
handleCommandClient();
handleConfigClient();
}
}
Éviter les attentes longues et bloquantes dans loop(). Sinon le transfert OTA
ralentit, expire ou laisse la carte indisponible pendant la mise à jour.
3. Vérifier le runtime après redémarrage
Retirer IO0 de la masse, brancher Ethernet et redémarrer. Depuis le node :
python3 - <<'PY'
import socket
with socket.create_connection(("192.168.0.240", 23), timeout=3) as sock:
for command in (b"PING\n", b"INFO\n", b"STATE\n"):
sock.sendall(command)
print(sock.recv(2048).decode().strip())
PY
Une carte saine répond notamment :
PONG
model=esp32-eth01-v1.4 processor=esp32 board=esp32-eth01-v1.4 ota=1 ota_port=3232 config=1 config_port=3233 ...
unconfigured=1
unconfigured=1 est normal juste après le premier flash. Il signifie que le
runtime fonctionne mais qu'aucun JSON de pièce n'a encore été reçu.
4. Mettre à jour le firmware par OTA
OTA sert uniquement quand le code du runtime change. Une modification de
prise, lampe, capteur, GPIO ou nom de pièce utilise le port JSON 3233 et ne
doit pas envoyer le binaire.
Après une compilation réussie, envoyer seulement l'image d'application :
python3 /opt/leukos-arduino/data/packages/esp32/hardware/esp32/3.0.7/tools/espota.py \
-d \
-i 192.168.0.240 \
-I 192.168.0.9 \
-p 3232 \
-f /tmp/leukos-esp32-output/firmware.ino.bin
-iest l'adresse de l'ESP32 ;-Iest l'adresse locale du node sur le même réseau ;-p 3232est le port annoncé parINFO;-fdésigne l'image.ino.bin, pas le bootloader ni la table de partitions.
Le chemin de espota.py dépend de la version du cœur ESP32 installée. Le
transfert est terminé uniquement si la commande affiche Result: OK puis
Success. Attendre ensuite le redémarrage et refaire PING, INFO, STATE.
Diagnostic rapide
| Symptôme | Vérification |
|---|---|
| Aucun port série | câble de données, alimentation, dmesg, droits sur /dev/ttyUSB0 |
Failed to connect au premier flash | IO0 à la masse, impulsion sur EN, TX/RX croisés |
Pas de réponse sur TCP 23 | lien RJ45, IP unique, sous-réseau, réponse au ping IP |
| OTA expire | port 3232, adresse passée avec -I, pare-feu, appels fréquents à ArduinoOTA.handle() |
| Téléversement anormalement lent | première compilation sur SD, cache vide, espace libre et alimentation du Pi |
STATE retourne unconfigured=1 | envoyer le JSON de pièce sur TCP 3233 |
La suite est décrite dans ESP32 — configuration JSON : format canonique, modules pris en charge et protocole de transfert.