Guide · 14 min di lettura

ESP32 OTA: caricare il codice via Wi-Fi senza cavo (ArduinoOTA)

ESP32 OTA: carica il codice via Wi-Fi senza cavo USB. Porta di rete ArduinoOTA, pagina web ElegantOTA, password, schema delle partizioni e upload interrotti.

L'OTA dell'ESP32 (Over-The-Air, aggiornamento "via etere") significa caricare nuovo codice sulla scheda tramite Wi-Fi, senza collegare un cavo USB. Pensa a un sensore montato sul soffitto, a una centralina di irrigazione in giardino o a una scheda relè dentro un quadro elettrico: invece di prendere la scala, smontare la scheda e collegarla al computer per ogni piccola correzione, invii la nuova versione dall'Arduino IDE o dal browser in pochi secondi. La scheda scrive il nuovo programma in memoria in background, lo verifica e si riavvia da sola.

In questa guida imparerai passo dopo passo come funziona l'OTA dentro l'ESP32, tre metodi diversi (ArduinoOTA per l'Arduino IDE, ElegantOTA per il browser e HTTPUpdate per scaricare da un server), come scegliere lo schema di partizioni giusto, come proteggere il caricamento con una password, cosa succede se l'upload si interrompe e come non perdere l'OTA nel prossimo sketch. Tutto il codice è stato compilato e provato con il core Arduino per ESP32.

Scheda di sviluppo ESP32 con caricamento del codice OTA senza fili
Scheda di sviluppo ESP32: dopo aver caricato una volta via USB il primo sketch con OTA, puoi inviare tutti gli aggiornamenti successivi via Wi-Fi.

Cos'è l'OTA dell'ESP32 e come funziona?

La memoria flash dell'ESP32 non è un blocco unico; è divisa in parti da una mappa chiamata tabella delle partizioni. Una tabella compatibile con l'OTA ha due aree uguali per il programma: app0 (ota_0) e app1 (ota_1). Mentre la scheda gira da una delle due, il nuovo programma viene scritto nell'altra. Una piccola partizione otadata ricorda quale area verrà eseguita al prossimo avvio. Così il programma in esecuzione non viene mai toccato durante il caricamento, e la scheda non abbandona il vecchio programma finché il nuovo codice non è stato scritto e verificato per intero.

  1. Il nuovo programma (il file .bin compilato) arriva alla scheda via Wi-Fi, un pezzo alla volta.
  2. L'ESP32 scrive ogni pezzo nella partizione di programma non in uso; nel frattempo il codice attuale continua a lavorare.
  3. Quando il file è arrivato tutto, vengono controllati l'intestazione dell'immagine e il checksum; un file corrotto o incompleto viene rifiutato.
  4. Se la verifica va a buon fine, otadata viene aggiornata: al prossimo avvio partirà la nuova partizione.
  5. La scheda si riavvia e parte con il nuovo programma. L'aggiornamento successivo andrà nell'altra partizione; le due aree si usano a turno.
MetodoDa dove invii il codice?Ideale perLibreria extra
ArduinoOTADalla porta di rete dell'Arduino IDESviluppare alla scrivania, sulla stessa reteNessuna (inclusa nel core)
ElegantOTAScegliendo un .bin nella pagina /update del browserFar aggiornare chi non ha l'IDE, caricare dal telefonoElegantOTA
HTTPUpdateLa scheda scarica da sola un .bin da un serverMolti dispositivi, dispositivi remoti, aggiornamenti automaticiNessuna (inclusa nel core)

Schema delle partizioni (partition scheme) e dimensione della flash

È il requisito dell'OTA che si dimentica più spesso: serve una seconda area libera in cui scrivere il nuovo programma. Per questo il programma più grande che puoi caricare via OTA è più piccolo persino della metà della flash. La tabella delle partizioni si sceglie nell'Arduino IDE da Strumenti > Partition Scheme. Sulle comuni schede ESP32 DevKit con 4 MB di flash (ESP32 Dev Module) le opzioni sono:

Partition SchemeArea programmaOTAFile system (SPIFFS/LittleFS)
Default 4MB with spiffs2 × 1,25 MB (1.310.720 byte)Sì1,375 MB
Minimal SPIFFS (1.9MB APP with OTA)2 × 1,875 MB (1.966.080 byte)Sì128 KB
No OTA (2MB APP/2MB SPIFFS)1 × 2 MBNo1,875 MB
Huge APP (3MB No OTA/1MB SPIFFS)1 × 3 MBNo896 KB
Minimal (1.3MB APP/700KB SPIFFS)1 × 1,25 MB (per schede con 2 MB di flash)No640 KB
Quando un programma grande che usa insieme Bluetooth e Wi-Fi dà l'errore "Sketch too big", quasi tutti scelgono Huge APP. Questo schema non ha una seconda area programma: via USB il codice si carica senza problemi, ma l'OTA non parte e fallisce con "Not Enough Space" o "Begin Failed". Se vuoi l'OTA, scegli Minimal SPIFFS (1.9MB APP with OTA).

Quanto spazio occupa il tuo programma lo vedi nell'output di compilazione: il nostro primo esempio con Wi-Fi e ArduinoOTA stampa "Sketch uses 758685 bytes (57%) ... Maximum is 1310720 bytes". Quel massimo è la dimensione di una sola area programma dello schema scelto. Se l'occupazione supera il 90 %, presto dovrai passare a Minimal SPIFFS. Un'altra regola importante: la tabella delle partizioni non si può cambiare via OTA. Se hai cambiato schema, quel caricamento va fatto via USB; gli aggiornamenti OTA successivi useranno la nuova tabella. Sulle schede con 8 MB o 16 MB di flash (come molti modelli ESP32-S3), scegliere la dimensione giusta nel menu Flash Size ti dà aree OTA molto più grandi.

Se vuoi vedere da quale partizione sta girando davvero la tua scheda e quanto spazio resta per l'OTA, carica il piccolo sketch qui sotto. Non richiede librerie e usa direttamente le funzioni OTA di ESP-IDF:

C++ (Arduino IDE)
1#include <esp_ota_ops.h>
2
3void setup() {
4  Serial.begin(115200);
5  delay(1000);
6  const esp_partition_t* running = esp_ota_get_running_partition();
7  const esp_partition_t* next = esp_ota_get_next_update_partition(NULL);
8
9  Serial.printf("Flash boyutu / Flash size: %u KB\n", ESP.getFlashChipSize() / 1024);
10  Serial.printf("Program boyutu / Sketch size: %u KB\n", ESP.getSketchSize() / 1024);
11  Serial.printf("OTA icin bos alan / Free space for OTA: %u KB\n", ESP.getFreeSketchSpace() / 1024);
12  Serial.printf("Calisan bolum / Running partition: %s (0x%06x)\n", running->label, running->address);
13  if (next != NULL) {
14    Serial.printf("Siradaki OTA bolumu / Next OTA partition: %s (0x%06x)\n", next->label, next->address);
15  } else {
16    Serial.println("OTA bolumu yok: bolum tablosunu degistir / No OTA partition: change the partition scheme");
17  }
18}
19
20void loop() {
21}

Con lo schema predefinito, dopo il primo caricamento via USB l'output mostra "Running partition: app0 (0x010000)" e "Next OTA partition: app1 (0x150000)". Se esegui di nuovo il codice dopo un aggiornamento OTA, vedrai che ora gira da app1. Il valore di ESP.getFreeSketchSpace() è la dimensione del programma più grande che puoi caricare via OTA; se il nuovo .bin è più grande, l'aggiornamento non parte.

Metodo 1: caricamento wireless dall'Arduino IDE con ArduinoOTA

La libreria ArduinoOTA è inclusa nel core ESP32, quindi non devi installare nulla. Quando la scheda entra in rete si annuncia tramite mDNS; l'Arduino IDE la rileva e aggiunge una porta di rete al menu Porta. Quando premi Carica, l'IDE invia il programma attraverso questa porta di rete invece che via USB. Sull'ESP32 il servizio OTA ascolta per impostazione predefinita sulla porta 3232. Lo sketch seguente si collega al Wi-Fi, avvia l'OTA con una password e fa lampeggiare il LED integrato come prova:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <ArduinoOTA.h>
3
4const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın / your Wi-Fi name
5const char* WIFI_PASS = "AgSifresi";      // Wi-Fi şifren / your Wi-Fi password
6const int LED_PIN = 2;                    // çoğu DevKit'te dahili LED / onboard LED on most DevKits
7
8unsigned long lastBlink = 0;
9
10void setup() {
11  Serial.begin(115200);
12  pinMode(LED_PIN, OUTPUT);
13
14  WiFi.mode(WIFI_STA);
15  WiFi.begin(WIFI_SSID, WIFI_PASS);
16  while (WiFi.status() != WL_CONNECTED) {   // bağlanana kadar bekle / wait until connected
17    delay(500);
18    Serial.print(".");
19  }
20  Serial.println();
21  Serial.print("IP: ");
22  Serial.println(WiFi.localIP());
23
24  ArduinoOTA.setHostname("bluegrays-esp32");  // IDE'de görünen ad / name shown in the IDE
25  ArduinoOTA.setPassword("ota1234");          // yükleme parolası / upload password
26
27  ArduinoOTA.onStart([]() {
28    // Güncelleme başlıyor: motorları, röleleri güvenli konuma al / update starting: put motors and relays in a safe state
29    String type = (ArduinoOTA.getCommand() == U_FLASH) ? "program" : "dosya sistemi / filesystem";
30    Serial.println("OTA basladi / started: " + type);
31  });
32  ArduinoOTA.onEnd([]() {
33    Serial.println("\nOTA bitti, yeniden baslatiliyor / done, rebooting");
34  });
35  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
36    Serial.printf("Ilerleme / Progress: %u%%\r", progress * 100 / total);
37  });
38  ArduinoOTA.onError([](ota_error_t error) {
39    Serial.printf("Hata / Error[%u]: ", error);
40    if (error == OTA_AUTH_ERROR) Serial.println("parola / auth failed");
41    else if (error == OTA_BEGIN_ERROR) Serial.println("baslatilamadi, yer yok / begin failed, no space");
42    else if (error == OTA_CONNECT_ERROR) Serial.println("baglanti / connect failed");
43    else if (error == OTA_RECEIVE_ERROR) Serial.println("veri alinamadi / receive failed");
44    else if (error == OTA_END_ERROR) Serial.println("bitirilemedi / end failed");
45  });
46
47  ArduinoOTA.begin();                         // OTA hizmetini başlat / start the OTA service
48}
49
50void loop() {
51  ArduinoOTA.handle();                        // her turda çağır, unutma / call on every pass, never forget
52
53  // delay() yerine millis(): OTA isteklerini kaçırmamak için / millis() instead of delay() so OTA requests aren't missed
54  if (millis() - lastBlink >= 500) {
55    lastBlink = millis();
56    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
57  }
58}
RigaA cosa serve?
ArduinoOTA.setHostname("bluegrays-esp32")Il nome mostrato nell'elenco delle porte dell'IDE e in rete. Se hai più schede, dai a ognuna un nome diverso.
ArduinoOTA.setPassword("ota1234")Senza password chiunque nella tua rete può caricare codice sulla scheda. L'IDE chiede questa password prima del caricamento.
onStart / onEndSi eseguono all'inizio e alla fine dell'aggiornamento. Il posto ideale per fermare i motori, spegnere i relè o mostrare "Aggiornamento" su un display.
onProgressFornisce la percentuale; puoi disegnare una barra di avanzamento su un LCD o un OLED.
onErrorIndica il tipo di errore: password, spazio insufficiente, connessione, ricezione o chiusura.
ArduinoOTA.handle()Controlla le richieste OTA in arrivo. Se non viene chiamata spesso dentro loop(), la scheda non può rispondere all'IDE.

Passo dopo passo: il tuo primo caricamento OTA

  1. Modifica i valori WIFI_SSID e WIFI_PASS nel codice per la tua rete. L'ESP32 si collega solo a reti a 2,4 GHz.
  2. Nel menu Strumenti scegli la tua scheda (es. ESP32 Dev Module) e un Partition Scheme con OTA (Default o Minimal SPIFFS).
  3. Fai il primo caricamento con il cavo USB. È obbligatorio, perché la scheda non ha ancora il codice OTA.
  4. Apri il Monitor seriale a 115200 baud e annota l'indirizzo IP stampato dalla scheda.
  5. Scollega il cavo USB e, se vuoi, alimenta la scheda con un'altra sorgente. Entro 10–20 secondi in Strumenti > Porta, sotto porte di rete, compare una riga come "bluegrays-esp32 at 192.168.1.x"; selezionala.
  6. Cambia nel codice la velocità del LED da 500 a 100 e premi Carica. Quando l'IDE chiede la password, scrivi "ota1234".
  7. Nella finestra di output vedrai la percentuale di avanzamento e alla fine una riga come "Done" o "Result: OK". La scheda si riavvia e ora il LED lampeggia veloce.
Se la porta di rete non compare, controlla prima che il computer e l'ESP32 siano sulla stessa rete; le reti ospiti e alcuni sistemi mesh impediscono ai dispositivi di vedersi. Riavviare l'IDE, riavviare la scheda o semplicemente aspettare qualche secondo di solito basta. Su Mac e Linux l'IDE usa lo script espota.py per il caricamento, quindi sul computer deve essere installato Python 3.

C'è un limite da conoscere: la porta di rete serve solo per caricare e il Monitor seriale non funziona senza fili. Per vedere i messaggi della scheda ricollega l'USB oppure mostra lo stato su una pagina web, su un display o con messaggi MQTT. Mentre sviluppi alla scrivania puoi anche lasciare la scheda collegata via USB e caricare comunque dalla rete; così hai caricamenti veloci e il Monitor seriale insieme.

Protezione con password e sicurezza

Una scheda con il servizio OTA aperto è una porta da cui chiunque nella tua rete può caricare codice. In ArduinoOTA, setPassword() tiene la password in chiaro nel codice; se condividi il codice, puoi passare l'hash MD5 della password con setPasswordHash(), così la password non compare nel sorgente. ElegantOTA protegge la pagina /update con nome utente e password (HTTP Basic Auth).

  • Dai a ogni dispositivo una password diversa e difficile da indovinare: valori come "1234" o "admin" sono i primi che vengono provati.
  • Non esporre la scheda su internet: aprire l'OTA o la pagina /update verso l'esterno con il port forwarding del router è un rischio serio; questi metodi viaggiano su HTTP non cifrato.
  • Usa HTTPUpdate per i dispositivi remoti: poiché è la scheda a chiedere l'aggiornamento, basta una connessione in uscita; se scarichi da internet, preferisci HTTPS con WiFiClientSecure.
  • Passa a uno stato sicuro durante l'aggiornamento: in onStart ferma i motori e spegni i relè di riscaldatori e pompe. Il riavvio dura qualche secondo e in quel tempo i pin possono restare indefiniti.

Metodo 2: caricare un .bin dal browser con ElegantOTA

ElegantOTA aggiunge una curata pagina /update al server web che gira sull'ESP32. Apri questa pagina dal telefono o da qualsiasi computer senza Arduino IDE, scegli il file .bin compilato e lo carichi; la barra di avanzamento compare nel browser. È il metodo più pratico quando consegni il dispositivo a qualcun altro o lo aggiorni sul posto.

  1. Nell'Arduino IDE apri il Gestore librerie, cerca ElegantOTA (Ayush Sharma) e installala.
  2. Modifica il codice qui sotto e caricalo la prima volta via USB.
  3. Apri nel browser l'indirizzo stampato nel Monitor seriale (es. http://192.168.1.42/update) e accedi con nome utente "admin" e password "ota1234".
  4. Lascia selezionata la modalità Firmware e trascina il file .bin; finito il caricamento, la scheda si riavvia da sola.
C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WebServer.h>
3#include <ElegantOTA.h>
4
5const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın / your Wi-Fi name
6const char* WIFI_PASS = "AgSifresi";      // Wi-Fi şifren / your Wi-Fi password
7
8WebServer server(80);
9unsigned long otaProgressMillis = 0;
10
11void onOTAStart() {
12  Serial.println("OTA basladi / OTA started");     // röleleri kapat / switch relays off
13}
14
15void onOTAProgress(size_t current, size_t final) {
16  if (millis() - otaProgressMillis > 1000) {        // saniyede bir yaz / print once per second
17    otaProgressMillis = millis();
18    Serial.printf("%u / %u bayt / bytes\n", current, final);
19  }
20}
21
22void onOTAEnd(bool success) {
23  Serial.println(success ? "OTA basarili / OTA successful" : "OTA hatasi / OTA failed");
24}
25
26void setup() {
27  Serial.begin(115200);
28  WiFi.mode(WIFI_STA);
29  WiFi.begin(WIFI_SSID, WIFI_PASS);
30  while (WiFi.status() != WL_CONNECTED) {
31    delay(500);
32    Serial.print(".");
33  }
34  Serial.println();
35  Serial.print("Adres / Address: http://");
36  Serial.print(WiFi.localIP());
37  Serial.println("/update");
38
39  server.on("/", []() {
40    server.send(200, "text/plain", "BlueGrays ESP32 - surum / version 1.0");
41  });
42
43  ElegantOTA.begin(&server, "admin", "ota1234");   // /update sayfası + kullanıcı/parola / /update page + user/password
44  ElegantOTA.onStart(onOTAStart);
45  ElegantOTA.onProgress(onOTAProgress);
46  ElegantOTA.onEnd(onOTAEnd);
47
48  server.begin();
49}
50
51void loop() {
52  server.handleClient();     // web isteklerini işle / handle web requests
53  ElegantOTA.loop();         // başarılı yüklemeden sonra yeniden başlatır / reboots after a successful upload
54}

Per impostazione predefinita ElegantOTA lavora con la classe sincrona WebServer inclusa nel core, quindi le chiamate server.handleClient() ed ElegantOTA.loop() dentro loop() sono obbligatorie. Se il tuo progetto usa già ESPAsyncWebServer, puoi impostare a 1 l'opzione ELEGANTOTA_USE_ASYNC_WEBSERVER della libreria e usarla con il server asincrono; spieghiamo come configurare il server asincrono nell'articolo Web server asincrono e WebSocket con ESP32. La modalità Filesystem della pagina aggiorna l'immagine LittleFS o SPIFFS (file della pagina web, file di impostazioni) invece del programma.

Ottenere il file .bin: esportare il binario compilato

Per ElegantOTA e HTTPUpdate ti serve il file del programma compilato. Nell'Arduino IDE esegui Sketch > Esporta binario compilato (Export Compiled Binary). L'IDE compila il programma e lascia diversi file in una cartella build dentro la cartella dello sketch. Solo uno di questi va bene per l'OTA:

FileContenutoSi usa per l'OTA?
mioprogetto.ino.binSolo l'applicazione (il tuo programma)Sì, è il file da caricare
mioprogetto.ino.bootloader.binBootloaderNo
mioprogetto.ino.partitions.binTabella delle partizioniNo
mioprogetto.ino.merged.bin (core 3.x)Bootloader, tabella e programma unitiNo, si scrive solo via USB all'indirizzo 0x0
Assicurati di aver compilato il programma per il chip della tua scheda. Se provi a caricare un .bin compilato per ESP32 su un ESP32-S3 o un ESP32-C3, viene rifiutato nella verifica finale e la scheda continua con il vecchio programma. Se scegli per errore merged.bin o bootloader.bin, l'aggiornamento si ferma con "Wrong Magic Byte", con un errore di spazio insufficiente o di attivazione.

Metodo 3: aggiornamenti automatici da un server con HTTPUpdate

Immagina di avere cinque schede sensore sparse per casa. Invece di caricarle una per una dall'IDE, metti il nuovo .bin su un server e le schede lo scaricano da sole. La libreria HTTPUpdate inclusa nel core ESP32 lo fa con una sola riga. Nell'esempio qui sotto l'aggiornamento parte quando premi il pulsante BOOT (GPIO 0) sulla scheda:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <HTTPUpdate.h>
3
4const char* WIFI_SSID = "AgAdi";
5const char* WIFI_PASS = "AgSifresi";
6// Bilgisayarındaki ya da sunucundaki .bin dosyası / the .bin file on your computer or server
7const char* FIRMWARE_URL = "http://192.168.1.50:8000/firmware.bin";
8const int BUTTON_PIN = 0;               // karttaki BOOT butonu / the BOOT button on the board
9
10void setup() {
11  Serial.begin(115200);
12  pinMode(BUTTON_PIN, INPUT_PULLUP);
13  WiFi.begin(WIFI_SSID, WIFI_PASS);
14  while (WiFi.status() != WL_CONNECTED) delay(500);
15  Serial.println("Hazir: guncellemek icin BOOT'a bas / Ready: press BOOT to update");
16}
17
18void loop() {
19  if (digitalRead(BUTTON_PIN) == LOW) {      // butona basıldı / button pressed
20    WiFiClient client;
21    httpUpdate.rebootOnUpdate(true);          // başarılıysa yeniden başlat / reboot on success
22    t_httpUpdate_return ret = httpUpdate.update(client, FIRMWARE_URL);
23
24    switch (ret) {
25      case HTTP_UPDATE_FAILED:
26        Serial.printf("Hata / Error (%d): %s\n", httpUpdate.getLastError(),
27                      httpUpdate.getLastErrorString().c_str());
28        break;
29      case HTTP_UPDATE_NO_UPDATES:
30        Serial.println("Guncelleme yok / No update");
31        break;
32      case HTTP_UPDATE_OK:
33        Serial.println("Tamam / OK");        // buraya genelde gelinmez, kart yeniden başlar / usually not reached, the board reboots
34        break;
35    }
36    delay(1000);
37  }
38}

Per provarlo, metti il .bin in una cartella del computer con il nome firmware.bin ed esegui python3 -m http.server 8000 in quella cartella; sostituisci l'indirizzo IP nel codice con l'IP locale del tuo computer. Nell'uso reale sostituisci il pulsante con un timer: per esempio, una volta all'ora la scheda legge un piccolo file "version.txt" e, se il numero di versione sul server è maggiore del suo, avvia l'aggiornamento. Così non finisce nemmeno in un ciclo in cui scarica lo stesso file e si riavvia all'infinito.

Cosa succede se la connessione cade durante l'OTA?

Risposta breve: la scheda non si brickera. Poiché il nuovo programma viene scritto nella partizione non usata e la partizione di avvio cambia solo dopo la verifica del file completo, se il caricamento si interrompe la scheda continua a funzionare con il vecchio programma. Vedrai "Error Uploading" nell'IDE, OTA_RECEIVE_ERROR in ArduinoOTA o un esito negativo in ElegantOTA; risolvi il problema e ripeti il caricamento. Se manca la corrente a metà caricamento vale lo stesso: la scheda si avvia con il vecchio programma. L'unico vero rischio è che il nuovo programma sia difettoso: se carichi un programma che non si collega al Wi-Fi o che non contiene il codice OTA, per il prossimo aggiornamento ti servirà di nuovo il cavo.

  • Segnale Wi-Fi debole: se il caricamento si blocca intorno al 30–60 %, avvicina la scheda al router o usa un modulo con antenna esterna. Se WiFi.RSSI() nel Monitor seriale è peggio di -75 dBm, aspettati interruzioni; trovi i dettagli in L'ESP32 non si connette al Wi-Fi.
  • Alimentazione insufficiente: la scrittura in flash e la trasmissione Wi-Fi assorbono corrente nello stesso momento. Una porta USB debole o un cavo sottile possono resettare la scheda durante il caricamento; si presenta come un errore di brownout. Usa un alimentatore a 5 V robusto che fornisca almeno 500 mA.
  • Attese lunghe in loop(): pause come delay(5000) ritardano la chiamata a handle() e l'IDE segnala "No response from the ESP". Gestisci i tempi con millis().
  • Firewall: con ArduinoOTA, all'inizio del caricamento l'ESP32 si ricollega al tuo computer. Se il Firewall di Windows o un antivirus blocca questa connessione in entrata, il caricamento fallisce subito; nella finestra di autorizzazione che compare al primo tentativo consenti le reti private.

Mantenere l'OTA in ogni nuovo sketch

La delusione più comune con l'OTA è questa: carichi via OTA un progetto completamente diverso, quel progetto non contiene codice ArduinoOTA e la scheda non compare più come porta di rete. Il nuovo programma sostituisce del tutto il vecchio; l'OTA non è qualcosa che "resta sulla scheda", ogni programma deve portarlo con sé. Per non risalire sulla scala fino al dispositivo sul soffitto, fai di queste regole un'abitudine:

  • Usa un modello: metti la connessione Wi-Fi e le impostazioni di ArduinoOTA in una funzione separata (es. setupOTA()) e inizia ogni nuovo progetto da quel file.
  • Metti la chiamata a handle() all'inizio di loop() e non lasciare mai dentro loop() un ciclo che blocca a lungo.
  • Riconnettiti se cade il Wi-Fi: usa WiFi.setAutoReconnect(true) o controlla la connessione regolarmente; una scheda senza connessione non può ricevere aggiornamenti.
  • Aggiungi una finestra di manutenzione ai progetti con deep sleep: una scheda addormentata non sente la richiesta OTA. Scrivi una modalità che attende l'OTA per 60 secondi prima di dormire se all'avvio è premuto un pulsante o è arrivato un flag MQTT. Per le modalità di sospensione vedi l'articolo ESP32 Deep Sleep.
  • Prova prima su una seconda scheda alla scrivania: prima di inviare al dispositivo installato, esegui lo stesso codice su una scheda accanto a te; se si collega al Wi-Fi e compare come porta di rete, è sicuro inviarlo.
  • Mostra un numero di versione: tieni una costante FW_VERSION all'inizio del codice e mostrala sulla pagina web o sul display; saprai sempre quale versione gira su quale scheda.

OTA su ESP8266 e Raspberry Pi Pico W

Il codice ArduinoOTA ed ElegantOTA di questa guida funziona con piccole modifiche anche sulle schede ESP8266 (NodeMCU, Wemos D1 Mini): si usa ESP8266WiFi.h al posto di WiFi.h, ESP8266WebServer al posto di WebServer, e la porta OTA è la 8266. Sulle schede ESP8266 con 4 MB di flash devi scegliere nel menu Flash Size un'opzione che lasci abbastanza spazio programma per l'OTA. Sul Raspberry Pi Pico W il core arduino-pico offre il supporto ad ArduinoOTA; qui il nuovo programma viene prima scaricato nel file system LittleFS e copiato al suo posto all'avvio. Per questo sul Pico W devi riservare nel menu Flash Size un file system più grande del programma. MicroPython non ha uno strumento OTA pronto; si possono scrivere piccoli script che scaricano e sostituiscono file .py dalla rete, ma non è un aggiornamento verificato a due partizioni come sull'ESP32.

Idee di progetti con l'OTA

  • Sensore a soffitto o a parete: cambia le soglie di una scheda che misura temperatura, umidità e movimento senza toccare un cavo.
  • Relè domotico: aggiorna via OTA le regole orarie della scheda relè nel quadro elettrico; metti i relè in uno stato sicuro dentro onStart.
  • Dispositivi per Home Assistant: aggiungi nuove funzioni dalla rete ai sensori collegati a Home Assistant via MQTT.
  • Centralina di irrigazione del giardino: cambia gli orari di irrigazione e la soglia di umidità del terreno senza aprire la scatola stagna.
  • Barra di avanzamento su LCD: mostra il valore di onProgress come percentuale e barra su un LCD 16x2; il progetto ESP32 OTA di BlueGrays fa esattamente questo.
  • Aggiornamento di una flotta: fai controllare ogni notte a più schede, con HTTPUpdate, se sullo stesso server c'è una nuova versione.

Errori comuni e soluzioni

SintomoCausa probabileSoluzione
Nessuna porta di rete nel menu PortaScheda su un'altra rete, mDNS bloccato, il codice non chiama ArduinoOTA.begin()Usa la stessa rete a 2,4 GHz, riavvia l'IDE, controlla che l'IP compaia nel Monitor seriale
"No response from the ESP"delay() lungo in loop(), scheda occupata o firewallUsa millis() invece di delay(), consenti l'IDE nel firewall
"Authentication Failed"Password OTA sbagliataInserisci il valore di setPassword del codice; se l'hai dimenticata, carica una volta via USB
"Not Enough Space" / Begin FailedSchema Huge APP o No OTA, il programma non entra nella seconda areaScegli Minimal SPIFFS e carica una volta via USB; riduci il programma
Il caricamento si interrompe a metàSegnale debole, calo di tensione, connessione persaAvvicina la scheda al router, usa un alimentatore a 5 V robusto, riprova; il vecchio programma continua a funzionare
Dopo il caricamento la scheda non entra in reteIl nuovo codice non ha Wi-Fi né OTA, SSID sbagliatoCorreggi via USB; d'ora in poi inizia ogni progetto dal modello OTA
"Wrong Magic Byte" o errore di attivazione in ElegantOTAÈ stato scelto merged.bin, bootloader.bin o un file compilato per un altro chipCarica solo il file mioprogetto.ino.bin
Quando configuri l'OTA per la prima volta, lascia la scheda collegata via USB con il Monitor seriale aperto; l'output di onError ti dice in una riga se il problema è la password, lo spazio o la connessione. Quando tutto funziona puoi scollegare il cavo.

L'OTA è la chiave per portare i progetti con ESP32 dalla scrivania a un'installazione vera: una volta configurato bene, correzioni, nuove funzioni e cambi di soglia arrivano senza fili in pochi secondi. Nell'app BlueGrays trovi il progetto ESP32 OTA Update (con IP e avanzamento mostrati su un LCD) insieme ai progetti su connessione Wi-Fi, Async Web Server, mDNS e NTP, tutti con schema del circuito e codice passo dopo passo.

Domande frequenti

Cos'è l'OTA dell'ESP32?

L'OTA (Over-The-Air) consiste nel caricare un nuovo programma sull'ESP32 via Wi-Fi invece che con un cavo USB. La scheda scrive il nuovo codice in una partizione di programma libera, lo verifica e si riavvia con la nuova versione. Il primo sketch con OTA va caricato una volta via USB.

Perché la porta di rete dell'ESP32 non compare nell'Arduino IDE?

Le cause più comuni sono il computer e la scheda su reti diverse, una rete ospiti che isola i dispositivi e la chiamata ArduinoOTA.begin() nel codice che non viene mai eseguita. Controlla nel Monitor seriale che la scheda abbia ottenuto un IP, riavvia l'IDE e aspetta qualche secondo.

Quale partition scheme scegliere per l'OTA dell'ESP32?

Sulle schede con 4 MB di flash scegli Default (area programma di 2 × 1,25 MB) oppure, se il programma è grande, Minimal SPIFFS (2 × 1,875 MB). Huge APP e No OTA non hanno una seconda area programma, quindi con questi l'OTA non funziona. Il primo caricamento dopo il cambio di schema va fatto via USB.

Un aggiornamento OTA interrotto può brickare l'ESP32?

No. Il nuovo programma viene scritto in una partizione vuota e la partizione di avvio cambia solo dopo la verifica dell'intero file. Se cade la connessione o la corrente, la scheda si avvia con il vecchio programma e puoi semplicemente ripetere il caricamento.

Si può usare il Monitor seriale durante il caricamento OTA?

La porta di rete serve solo a caricare codice; il Monitor seriale non funziona senza fili. Per vedere i messaggi puoi lasciare la scheda collegata via USB o mostrare le informazioni su una pagina web, un display o via MQTT.

Come si imposta una password OTA sull'ESP32?

In ArduinoOTA chiami ArduinoOTA.setPassword("password") prima di begin(); l'IDE chiede questa password prima del caricamento. Se non vuoi che la password compaia nel codice, passa il suo hash MD5 con setPasswordHash(). In ElegantOTA proteggi la pagina con begin(&server, "utente", "password").

Vedi tutti i progetti
Aggiornamento OTA dell'ESP32 — Installazione wireless del firmware (con display LCD)
#132Avanzato
Premium

Aggiornamento OTA dell'ESP32 — Installazione wireless del firmware (con display LCD)

In questo progetto imparerai a installare il nuovo firmware sull'ESP32 tramite Wi-Fi, senza bisogno di un cavo USB. Grazie alla libreria ArduinoOTA, l'ESP32 diventa visibile sulla rete e viene automaticamente elencato come bluegrays-ota nella scheda "Network port" dell'IDE di Arduino. Il primo caricamento avviene tramite USB, mentre tutti gli aggiornamenti successivi saranno wireless — una caratteristica fondamentale per i dispositivi sul campo. Sul display LCD I2C vengono visualizzati, sia

4.6(14)
22
Connessione Wi-Fi STA con ESP32 (con display LCD)
#127Avanzato

Connessione Wi-Fi STA con ESP32 (con display LCD)

In questo progetto colleghiamo l'ESP32 alla rete Wi-Fi domestica in modalità Station (STA) in modo sicuro e tollerante agli errori. Separiamo SSID e password in un file secrets.h per impedire fughe su Git, impostiamo un meccanismo di riconnessione automatica e visualizziamo il livello del segnale RSSI e l'indirizzo IP su un display LCD I2C. Il LED interno funge da indicatore di stato.

4.4(21)
34
Server web asincrono ESP32 (con indicazione dell'IP sul display LCD)
#129Avanzato

Server web asincrono ESP32 (con indicazione dell'IP sul display LCD)

In questo progetto trasformiamo l'ESP32 in un server web asincrono che potrete controllare dal vostro telefono o computer collegato alla stessa rete Wi-Fi. Grazie alla libreria ESPAsyncWebServer, il server è in grado di elaborare più richieste contemporaneamente (a differenza del classico WebServer.h, che si blocca su una singola richiesta).

4.8(16)
26
ESP32 mDNS: accesso al dispositivo tramite bluegrays-esp.local (con schermo LCD)
#131Avanzato
Premium

ESP32 mDNS: accesso al dispositivo tramite bluegrays-esp.local (con schermo LCD)

In questo progetto, aggiungendo il servizio mDNS (Multicast DNS) all'ESP32, consentiamo l'accesso tramite un nome host leggibile, come bluegrays-esp.local, anziché tramite l'indirizzo IP. Anche se l'IP assegnato dal DHCP dovesse cambiare, potrete sempre raggiungere il dispositivo con lo stesso nome. Eseguendo anche un piccolo server web, inviamo comandi di controllo dei LED dal browser all’indirizzo http://bluegrays-esp.local/. Sul display LCD I2C vengono visualizzati il nome host, l’IP e lo

4.8(14)
23
Contatore WebSocket ESP32 (2 pulsanti + LCD + Web in tempo reale)
#130Avanzato
Premium

Contatore WebSocket ESP32 (2 pulsanti + LCD + Web in tempo reale)

In questo progetto due pulsanti collegati all'ESP32 (GPIO 5 incrementa, GPIO 4 decrementa) modificano un contatore. Il valore si aggiorna all'istante su un display LCD I2C 16x2 e, grazie al supporto WebSocket di ESPAsyncWebServer, in tutti i browser collegati senza ricaricare la pagina. Al posto del polling HTTP si usa un'unica connessione persistente e l'ESP32 invia il nuovo valore a tutti con ws.textAll().

4.5(14)
23
ESP32: ora reale da Internet tramite NTP
#128Avanzato
Premium

ESP32: ora reale da Internet tramite NTP

L'ESP32 si connette al Wi-Fi e recupera l'ora reale con precisione al millisecondo dai server NTP (Network Time Protocol). Grazie a configTzTime(), il fuso orario della Turchia (TRT, UTC+3) viene applicato automaticamente e il passaggio all'ora legale è gestito tramite la stringa POSIX TZ. L'ora viene mostrata sul Serial Monitor e su un display LCD I2C opzionale. configTzTime() avvia il servizio SNTP; vengono eseguite risincronizzazioni periodiche finché è disponibile l'accesso alla rete, e

4.5(13)
21
ESP32 HTTPClient + API meteo (con schermo LCD)
#133Avanzato
Premium

ESP32 HTTPClient + API meteo (con schermo LCD)

In questo progetto, utilizzando l'ESP32, effettuiamo una chiamata REST all'API meteo (wttr.in) tramite Internet utilizzando HTTPClient.h. Analizziamo la risposta JSON restituita tramite ArduinoJson v7 e visualizziamo le informazioni relative a città, temperatura, umidità, condizioni meteorologiche e vento sul display LCD I2C sia in turco che in inglese. wttr.in è gratuito e non richiede una chiave API: basta digitare il nome di una città qualsiasi per ottenere le condizioni meteorologiche in t

4.7(13)
20
ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RTC RAM)
#135Avanzato
Premium

ESP32 Deep Sleep — Risparmio della batteria (OLED + contatore in RTC RAM)

La modalità Deep Sleep dell'ESP32 riduce il consumo di corrente a circa 10 µA spegnendo la CPU e la maggior parte dei dispositivi periferici ed è di fondamentale importanza per i dispositivi IoT alimentati a batteria. In questo progetto utilizziamo tre diverse fonti di risveglio: il timer (15 secondi), un pin esterno (EXT0 — pulsante GPIO 33) e il sensore tattile (T0/GPIO 4). Le variabili contrassegnate con RTC_DATA_ATTR vengono preservate durante la modalità Deep Sleep: il contatore di avvio,

4.3(10)
16