Atualização OTA no ESP32: carregue código sem fio com ArduinoOTA
Com o OTA do ESP32 você carrega código pelo Wi-Fi, sem cabo USB: porta de rede do ArduinoOTA, página web do ElegantOTA, senha, partition scheme e carregamentos interrompidos.
ESP32 OTA (Over-The-Air, atualização “pelo ar”) significa carregar um novo código na sua placa pelo Wi-Fi, em vez de conectar um cabo USB. Imagine um sensor instalado no teto, um controlador de irrigação no jardim ou uma placa de relés guardada dentro de um quadro elétrico: em vez de pegar a escada, desmontar a placa e ligá-la ao computador a cada pequena correção, você envia a nova versão pelo Arduino IDE ou por um navegador em poucos segundos. A placa grava o novo programa na memória em segundo plano, verifica e se reinicia sozinha.
Neste guia você vai aprender, passo a passo, como o OTA funciona dentro do ESP32, três métodos diferentes (ArduinoOTA para o Arduino IDE, ElegantOTA para o navegador e HTTPUpdate para baixar de um servidor), como escolher o partition scheme (tabela de partições) certo, como proteger os carregamentos com senha, o que acontece se um carregamento for interrompido e como não perder o OTA no seu próximo sketch. Todo o código foi compilado e testado com o core ESP32 do Arduino.

O que é OTA no ESP32 e como funciona?
A memória flash do ESP32 não é um bloco único; ela é dividida em partes por um mapa chamado tabela de partições. Uma tabela de partições com suporte a OTA tem duas áreas idênticas para o programa: app0 (ota_0) e app1 (ota_1). Enquanto a placa roda a partir de uma delas, o novo programa é gravado na outra. Uma pequena partição otadata guarda qual área será executada na próxima inicialização. Assim, o programa em execução nunca é tocado durante o carregamento, e a placa só abandona o programa antigo depois que o novo código foi totalmente gravado e verificado.
- O novo programa (o arquivo .bin compilado) chega à placa pelo Wi-Fi, pedaço por pedaço.
- O ESP32 grava cada pedaço na partição de programa que não está em uso no momento; enquanto isso, o código em execução continua fazendo seu trabalho.
- Quando o arquivo inteiro chega, o cabeçalho da imagem e o checksum são verificados; um arquivo corrompido ou incompleto é rejeitado.
- Se a verificação der certo, o otadata é atualizado: a nova partição será executada na próxima inicialização.
- A placa reinicia e volta com o novo programa. A próxima atualização vai para a outra partição; as duas áreas são usadas alternadamente.
| Método | De onde você envia o código? | Mais indicado para | Biblioteca extra |
|---|---|---|---|
| ArduinoOTA | Pela porta de rede no Arduino IDE | Desenvolvimento na bancada, na mesma rede | Nenhuma (vem com o core) |
| ElegantOTA | Escolhendo um .bin na página /update do navegador | Deixar alguém sem o IDE atualizar, carregar pelo celular | ElegantOTA |
| HTTPUpdate | A própria placa baixa um arquivo .bin de um servidor | Muitos dispositivos, dispositivos remotos, atualizações automáticas | Nenhuma (vem com o core) |
Partition scheme e tamanho da flash
Este é o requisito mais esquecido do OTA: precisa existir uma segunda área livre para gravar o novo programa. Por isso, o maior programa que você pode carregar por OTA é menor até que a metade da flash. Você escolhe a tabela de partições no Arduino IDE em Ferramentas > Partition Scheme. Nas placas ESP32 DevKit comuns com 4 MB de flash (ESP32 Dev Module), as opções são:
| Partition Scheme | Área de programa | OTA | Sistema de arquivos (SPIFFS/LittleFS) |
|---|---|---|---|
| Default 4MB with spiffs | 2 × 1,25 MB (1.310.720 bytes) | Sim | 1,375 MB |
| Minimal SPIFFS (1.9MB APP with OTA) | 2 × 1,875 MB (1.966.080 bytes) | Sim | 128 KB |
| No OTA (2MB APP/2MB SPIFFS) | 1 × 2 MB | Não | 1,875 MB |
| Huge APP (3MB No OTA/1MB SPIFFS) | 1 × 3 MB | Não | 896 KB |
| Minimal (1.3MB APP/700KB SPIFFS) | 1 × 1,25 MB (para placas com 2 MB de flash) | Não | 640 KB |
Você vê quanto espaço seu programa ocupa na saída da compilação: nosso primeiro exemplo com Wi-Fi e ArduinoOTA mostra “O sketch usa 758685 bytes (57%) ... O máximo são 1310720 bytes”. Esse máximo é o tamanho de uma única área de programa no esquema que você escolheu. Se o uso passar de 90%, conte com a mudança para Minimal SPIFFS em breve. Mais uma regra importante: a tabela de partições não pode ser alterada por OTA. Se você mudou o esquema, esse carregamento precisa ser feito pelo USB; os OTAs seguintes funcionam com a nova tabela. Em placas com 8 MB ou 16 MB de flash (como muitos modelos ESP32-S3), escolher o tamanho correto no menu Flash Size dá áreas de OTA bem maiores.
Se quiser ver de qual partição sua placa está realmente rodando e quanto espaço sobra para o OTA, carregue o pequeno sketch abaixo. Ele não precisa de biblioteca e usa diretamente as funções de OTA do ESP-IDF:
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}Com o esquema padrão, depois do primeiro carregamento pelo USB a saída mostra “Running partition: app0 (0x010000)” e “Next OTA partition: app1 (0x150000)”. Rode o código de novo depois de uma atualização OTA e você verá que agora ele roda a partir do app1. O valor de ESP.getFreeSketchSpace() é o tamanho do maior programa que você pode carregar por OTA; se o seu novo arquivo .bin for maior, a atualização não começa.
Método 1: carregamento sem fio pelo Arduino IDE com ArduinoOTA
A biblioteca ArduinoOTA vem com o core do ESP32, então não há nada para instalar. Quando a placa entra na rede, ela se anuncia via mDNS; o Arduino IDE percebe isso e adiciona uma porta de rede ao menu Porta. Ao clicar em Carregar, o IDE envia o programa por essa porta de rede em vez do USB. No ESP32, o serviço OTA escuta por padrão na porta 3232. O sketch abaixo conecta ao Wi-Fi, inicia o OTA com senha e pisca o LED integrado como prova:
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}| Linha | O que faz? |
|---|---|
| ArduinoOTA.setHostname("bluegrays-esp32") (nome na rede) | O nome que aparece na lista de portas do IDE e na rede. Se você tem várias placas, dê um nome diferente a cada uma. |
| ArduinoOTA.setPassword("ota1234") (senha) | Sem senha, qualquer pessoa na sua rede pode carregar código na sua placa. O IDE pede essa senha antes de carregar. |
| onStart / onEnd (início / fim) | Rodam quando a atualização começa e termina. O lugar ideal para parar motores, desligar relés ou mostrar “Atualizando” em um display. |
| onProgress (progresso) | Fornece a porcentagem; você pode desenhar uma barra de progresso em um LCD ou OLED. |
| onError (erro) | Informa o tipo de erro: senha, falta de espaço, conexão, recepção ou finalização. |
| ArduinoOTA.handle() (verificação) | Verifica se chegaram pedidos de OTA. Se não for chamada com frequência dentro de loop(), a placa não consegue responder ao IDE. |
Passo a passo: seu primeiro carregamento OTA
- Edite os valores de WIFI_SSID e WIFI_PASS no código para a sua rede. O ESP32 só conecta a redes de 2,4 GHz.
- No menu Ferramentas, selecione sua placa (por exemplo, ESP32 Dev Module) e um Partition Scheme que inclua OTA (Default ou Minimal SPIFFS).
- Faça o primeiro carregamento com um cabo USB. Este passo é obrigatório, porque a placa ainda não tem código de OTA.
- Abra o Monitor Serial em 115200 baud e anote o endereço IP que a placa mostra.
- Desconecte o cabo USB e, se quiser, alimente a placa com outra fonte. Em 10–20 segundos aparece uma linha como “bluegrays-esp32 at 192.168.1.x” em portas de rede, no menu Ferramentas > Porta; selecione-a.
- Mude o atraso do LED no código de 500 para 100 e clique em Carregar. Quando o IDE pedir a senha, digite “ota1234”.
- Na janela de saída você verá a porcentagem de progresso e, no fim, uma linha como “Done” ou “Result: OK”. A placa reinicia e o LED agora pisca rápido.
Há uma limitação que você precisa conhecer: a porta de rede serve apenas para carregar, e o Monitor Serial não funciona sem fio. Para ver as mensagens da placa, conecte o USB de novo ou mostre o status em uma página web, em um display ou por mensagens MQTT. Enquanto desenvolve na bancada, você também pode deixar a placa no USB e ainda assim carregar pela rede; assim você tem carregamentos rápidos e o Monitor Serial ao mesmo tempo.
Proteção por senha e segurança
Uma placa com o serviço OTA aberto é uma porta pela qual qualquer pessoa na sua rede pode carregar código. No ArduinoOTA, setPassword() guarda a senha como texto puro dentro do código; se você vai compartilhar o código, pode passar o hash MD5 da senha com setPasswordHash(), assim a senha em si não aparece no código-fonte. O ElegantOTA protege a página /update com usuário e senha (HTTP Basic Auth).
- Dê a cada dispositivo uma senha diferente e difícil de adivinhar: valores como “1234” ou “admin” são os primeiros que alguém tenta.
- Não exponha a placa à internet: abrir o OTA ou a página /update para fora com redirecionamento de portas no roteador é um risco sério; esses métodos funcionam sobre HTTP sem criptografia.
- Use HTTPUpdate para dispositivos remotos: como a própria placa pede a atualização, basta uma conexão de saída; se você baixa pela internet, prefira HTTPS com WiFiClientSecure.
- Entre em um estado seguro durante a atualização: pare motores e desligue os relés de aquecedores e bombas dentro de onStart. A reinicialização leva alguns segundos e os pinos podem ficar indefinidos nesse tempo.
Método 2: carregar um .bin pelo navegador com ElegantOTA
O ElegantOTA adiciona uma página /update caprichada ao servidor web que roda no ESP32. Você abre essa página no celular ou em qualquer computador sem o Arduino IDE, escolhe o arquivo .bin compilado e envia; a barra de progresso aparece no navegador. É o método mais prático quando você entrega o dispositivo para outra pessoa ou atualiza em campo.
- No Arduino IDE, abra o Gerenciador de Bibliotecas, busque ElegantOTA (Ayush Sharma) e instale.
- Edite o código abaixo e carregue pelo USB na primeira vez.
- Abra no navegador o endereço mostrado no Monitor Serial (por exemplo, http://192.168.1.42/update) e entre com o usuário “admin” e a senha “ota1234”.
- Deixe Firmware selecionado como modo e arraste e solte o arquivo .bin; quando o envio termina, a placa reinicia sozinha.
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}Por padrão, o ElegantOTA trabalha com a classe síncrona WebServer que vem com o core, por isso as chamadas server.handleClient() e ElegantOTA.loop() dentro de loop() são obrigatórias. Se o seu projeto já usa ESPAsyncWebServer, você pode definir a opção ELEGANTOTA_USE_ASYNC_WEBSERVER da biblioteca como 1 e usá-la com o servidor assíncrono; explicamos como montar o servidor assíncrono no post ESP32 Async Web Server e WebSocket. Já o modo Filesystem da página atualiza a imagem do LittleFS ou SPIFFS (arquivos da página web, arquivos de configuração) em vez do programa.
Obtendo o arquivo .bin: exportando o binário compilado
Para o ElegantOTA e o HTTPUpdate você precisa do arquivo do programa compilado. No Arduino IDE, execute Sketch > Exportar binário compilado. O IDE compila o programa e deixa vários arquivos em uma pasta build dentro da pasta do sketch. Só um deles serve para OTA:
| Arquivo | Conteúdo | Usado no OTA? |
|---|---|---|
| meuprojeto.ino.bin | Só a aplicação (o seu programa) | Sim, este é o arquivo a enviar |
| meuprojeto.ino.bootloader.bin | Bootloader | Não |
| meuprojeto.ino.partitions.bin | Tabela de partições | Não |
| meuprojeto.ino.merged.bin (core 3.x) | Bootloader, tabela e programa combinados | Não, ele só é gravado pelo USB no endereço 0x0 |
Método 3: atualizações automáticas a partir de um servidor com HTTPUpdate
Imagine que você tem cinco placas de sensores espalhadas pela casa. Em vez de carregar em cada uma pelo IDE, você coloca o novo arquivo .bin em um servidor e as placas baixam sozinhas. A biblioteca HTTPUpdate, que vem com o core do ESP32, faz isso em uma única linha. No exemplo abaixo, a atualização começa quando você aperta o botão BOOT (GPIO 0) da placa:
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}Para testar, coloque o arquivo .bin em uma pasta do computador com o nome firmware.bin e rode python3 -m http.server 8000 nessa pasta; troque o endereço IP no código pelo IP local do seu computador. No uso real, você troca o botão por um temporizador: por exemplo, uma vez por hora a placa lê um pequeno arquivo “version.txt” e, se o número de versão no servidor for maior que o dela, inicia a atualização. Assim ela também nunca fica presa baixando o mesmo arquivo e reiniciando sem parar.
O que acontece se a conexão cair durante o OTA?
Resposta curta: sua placa não vai virar tijolo. Como o novo programa é gravado na partição sem uso e a partição de boot só é trocada depois que o arquivo inteiro foi verificado, um carregamento interrompido deixa a placa rodando o programa antigo. Você verá “Error Uploading” no IDE, OTA_RECEIVE_ERROR no ArduinoOTA ou um resultado de falha no ElegantOTA; resolva o problema e repita o carregamento. Se a energia cair no meio do carregamento, é a mesma coisa: a placa inicia com o programa antigo. O único risco real é o próprio programa novo ter defeito: se você carregar um programa que não conecta ao Wi-Fi ou não contém o código de OTA, vai precisar do cabo de novo para a próxima atualização.
- Sinal de Wi-Fi fraco: se o carregamento trava por volta de 30–60%, aproxime a placa do roteador ou use um módulo com antena externa. Se WiFi.RSSI() no Monitor Serial estiver pior que -75 dBm, espere quedas; veja ESP32 não conecta ao Wi-Fi para mais detalhes.
- Alimentação insuficiente: gravar na flash e transmitir pelo Wi-Fi puxam corrente ao mesmo tempo. Uma porta USB fraca ou um cabo fino pode resetar a placa durante o carregamento; isso aparece como um erro de brownout. Use uma fonte de 5 V firme, que forneça pelo menos 500 mA.
- Esperas longas dentro de loop(): esperas como delay(5000) atrasam a chamada de handle() e o IDE mostra “No response from the ESP”. Faça a temporização com millis().
- Firewall: no ArduinoOTA, quando o carregamento começa, o ESP32 se conecta de volta ao seu computador. Se o Firewall do Windows ou um antivírus bloquear essa conexão de entrada, o carregamento falha logo no início; permita redes privadas na janela de permissão que aparece na primeira tentativa.
Mantendo o OTA em todo sketch novo
A decepção mais comum com OTA é assim: você carrega por OTA um projeto completamente diferente, esse projeto não tem o código ArduinoOTA e a placa não aparece mais como porta de rede. O programa recém-carregado substitui totalmente o antigo; o OTA não é algo que “fica na placa”, cada programa precisa trazê-lo consigo. Para não subir a escada até o dispositivo do teto de novo, transforme estas regras em hábito:
- Use um modelo: coloque a conexão Wi-Fi e as configurações do ArduinoOTA em uma função separada (por exemplo, setupOTA()) e comece todo projeto novo a partir desse arquivo.
- Coloque a chamada de handle() bem no início de loop() e nunca deixe dentro de loop() um laço que bloqueie por muito tempo.
- Reconecte se o Wi-Fi cair: use WiFi.setAutoReconnect(true) ou verifique a conexão regularmente; uma placa sem conexão não recebe atualizações.
- Adicione uma janela de manutenção a projetos com deep sleep: uma placa dormindo não ouve o pedido de OTA. Escreva um modo que espere 60 segundos pelo OTA antes de dormir se um botão estiver pressionado na inicialização ou se uma flag MQTT tiver chegado. Para os modos de sono, veja o post ESP32 Deep Sleep.
- Teste primeiro em uma segunda placa na bancada: antes de enviar ao dispositivo em campo, rode o mesmo código em uma placa ao seu lado; se ela conecta ao Wi-Fi e aparece como porta de rede, é seguro enviar.
- Mostre um número de versão: mantenha uma constante FW_VERSION no topo do código e exiba-a na página web ou no display; assim você sempre sabe qual versão está rodando em qual placa.
OTA no ESP8266 e no Raspberry Pi Pico W
O código de ArduinoOTA e ElegantOTA deste guia também roda em placas ESP8266 (NodeMCU, Wemos D1 Mini) com pequenas mudanças: usa-se ESP8266WiFi.h em vez de WiFi.h, ESP8266WebServer em vez de WebServer, e a porta do OTA é 8266. Em placas ESP8266 com 4 MB de flash, escolha uma opção de Flash Size que deixe espaço de programa suficiente para o OTA. No Raspberry Pi Pico W, o core arduino-pico oferece suporte a ArduinoOTA; nele, o novo programa é primeiro baixado para o sistema de arquivos LittleFS e copiado para o lugar na inicialização. Por isso, no Pico W você precisa reservar no menu Flash Size uma área de sistema de arquivos maior que o seu programa. O MicroPython não tem uma ferramenta de OTA pronta; dá para escrever pequenos scripts que baixam e substituem arquivos .py pela rede, mas isso não é uma atualização verificada com duas partições como no ESP32.
Ideias de projetos com OTA
- Sensor de teto ou de parede: mude os limites de uma placa que mede temperatura, umidade e movimento sem encostar em nenhum cabo.
- Relé de casa inteligente: atualize por OTA as regras de horário da placa de relé na caixa elétrica; coloque os relés em estado seguro dentro de onStart.
- Dispositivos do Home Assistant: adicione novos recursos pela rede a sensores conectados ao Home Assistant via MQTT.
- Controlador de irrigação do jardim: mude os horários de rega e o limite de umidade do solo sem abrir a caixa à prova d'água.
- Barra de progresso em um LCD: mostre o valor de onProgress como porcentagem e barra em um LCD 16x2; o projeto ESP32 OTA do BlueGrays faz exatamente isso.
- Atualização de frota: faça várias placas verificarem toda noite, com HTTPUpdate, se há uma nova versão no mesmo servidor.
Erros comuns e como resolver
| Sintoma | Causa provável | Solução |
|---|---|---|
| Nenhuma porta de rede no menu Porta | Placa em outra rede, mDNS bloqueado, o código não chama ArduinoOTA.begin() | Use a mesma rede de 2,4 GHz, reinicie o IDE, confira se o IP aparece no Monitor Serial |
| “No response from the ESP” (sem resposta do ESP) | delay() longo em loop(), placa ocupada ou firewall | Use millis() em vez de delay(), libere o IDE no firewall |
| “Authentication Failed” (falha de autenticação) | Senha de OTA errada | Digite o valor de setPassword do código; se esqueceu, carregue uma vez pelo USB |
| “Not Enough Space” / Begin Failed (espaço insuficiente / falha ao iniciar) | Esquema Huge APP ou No OTA, o programa não cabe na segunda área | Escolha Minimal SPIFFS e carregue uma vez pelo USB; reduza o programa |
| O carregamento para no meio | Sinal fraco, queda de alimentação, conexão perdida | Aproxime a placa do roteador, use uma fonte de 5 V firme, tente de novo; o programa antigo continua rodando |
| A placa não entra na rede depois do carregamento | O código novo não tem Wi-Fi ou OTA, SSID errado | Corrija pelo USB; daqui em diante, comece todo projeto pelo modelo com OTA |
| “Wrong Magic Byte” ou erro de ativação no ElegantOTA | Foi escolhido o merged.bin, o bootloader.bin ou um arquivo compilado para outro chip | Envie apenas o arquivo meuprojeto.ino.bin |
O OTA é a chave para tirar os projetos com ESP32 da bancada e instalá-los em um lugar de verdade: depois de bem configurado, correções, novos recursos e mudanças de limites chegam sem fio em segundos. No app BlueGrays você encontra o projeto ESP32 OTA Update (com IP e progresso mostrados em um LCD), junto com os projetos de conexão Wi-Fi, Async Web Server, mDNS e NTP, cada um com esquema do circuito e código, passo a passo.
Perguntas frequentes
O que é OTA no ESP32?
OTA (Over-The-Air) significa carregar um novo programa no ESP32 pelo Wi-Fi em vez de um cabo USB. A placa grava o novo código em uma partição de programa sem uso, verifica e reinicia com a nova versão. Você precisa carregar o primeiro sketch com OTA uma vez pelo USB.
Por que a porta de rede do ESP32 não aparece no Arduino IDE?
Os motivos mais comuns são o computador e a placa estarem em redes diferentes, uma rede de convidados isolando os dispositivos e a chamada ArduinoOTA.begin() do código nunca ser executada. Confira no Monitor Serial se a placa recebeu um IP, reinicie o IDE e espere alguns segundos.
Qual partition scheme devo escolher para OTA no ESP32?
Em placas com 4 MB de flash, escolha Default (área de programa de 2 × 1,25 MB) ou, se o seu programa for grande, Minimal SPIFFS (2 × 1,875 MB). Huge APP e No OTA não têm segunda área de programa, então o OTA não funciona com eles. O primeiro carregamento depois de mudar o esquema precisa ser feito pelo USB.
Um carregamento OTA interrompido pode estragar o ESP32?
Não. O novo programa é gravado em uma partição vazia e a partição de boot só é trocada depois que o arquivo inteiro foi verificado. Se a conexão ou a energia cair, a placa inicia com o programa antigo e você pode simplesmente tentar o carregamento de novo.
Dá para usar o Monitor Serial ao carregar por OTA?
A porta de rede serve apenas para carregar código; o Monitor Serial não funciona sem fio. Para ver as mensagens, você pode deixar a placa conectada ao USB ou mostrar as informações em uma página web, em um display ou via MQTT.
Como definir uma senha de OTA no ESP32?
No ArduinoOTA, você chama ArduinoOTA.setPassword("senha") antes de begin(); o IDE pede essa senha antes de carregar. Se não quiser a senha visível no código, passe o hash MD5 dela com setPasswordHash(). No ElegantOTA, você protege a página com begin(&server, "usuario", "senha").
Projetos para montar depois desta leitura
Ver todos os projetos
Atualização OTA no ESP32 — firmware sem fio (com display LCD)
Neste projeto, você aprende a carregar um novo firmware no ESP32 por Wi-Fi, sem cabo USB. Com a biblioteca ArduinoOTA, o ESP32 fica visível na rede e aparece automaticamente como bluegrays-ota na aba "Porta de rede" do Arduino IDE. A primeira carga é feita por USB, e todas as atualizações seguintes são sem fio — um recurso essencial para dispositivos em campo. O LCD I2C mostra o estado do Wi-Fi, o IP, o nome do host, a porcentagem de envio por OTA e as mensagens de erro em turco e inglês.

Conexão Wi-Fi STA com ESP32 e display LCD
Neste projeto, conectamos o ESP32 à rede Wi-Fi de casa no modo estação (STA), de forma segura e tolerante a falhas. Guardamos o SSID e a senha em um arquivo secrets.h separado para evitar que sejam expostos no Git, configuramos um mecanismo de reconexão automática e exibimos o nível de sinal RSSI e o endereço IP em um display LCD I2C. O LED integrado funciona como indicador de status. É um gerenciador de conexão pronto para uso em produção.

Servidor web assíncrono com ESP32 (IP no LCD)
Neste projeto, transformamos o ESP32 em um servidor web assíncrono que você pode controlar pelo celular ou computador na mesma rede Wi-Fi. Com a biblioteca ESPAsyncWebServer, o servidor processa várias requisições ao mesmo tempo (ao contrário do WebServer.h tradicional, que bloqueia a execução ao processar uma requisição). Você poderá abrir o endereço IP do ESP32 no navegador e clicar nos botões ON/OFF (as rotas /on e /off) para ligar e desligar o LED conectado ao GPIO 5.

ESP32 mDNS: acesso via bluegrays-esp.local (com display LCD)
Neste projeto, adicionamos o serviço mDNS (Multicast DNS) ao ESP32 para acessar o dispositivo por um nome de host fácil de ler, como bluegrays-esp.local, em vez de um endereço IP. Mesmo que o IP atribuído pelo DHCP mude, você pode acessar o dispositivo pelo mesmo nome. Também executamos um pequeno servidor web no dispositivo para enviar comandos de controle do LED pelo navegador no endereço http://bluegrays-esp.local/.

Contador WebSocket com ESP32 (2 botões + LCD + web em tempo real)
Neste projeto, dois botões conectados ao ESP32 (GPIO 5 aumenta, GPIO 4 diminui) alteram um contador. O valor é atualizado instantaneamente no LCD I2C 16x2 e, com o suporte a WebSocket do ESPAsyncWebServer, em todos os navegadores conectados, sem recarregar a página. Em vez de consultas periódicas por HTTP, usamos uma única conexão persistente, e o ESP32 envia o novo valor a todos com ws.textAll().

Hora exata pela internet com ESP32 e NTP
O ESP32 se conecta ao Wi-Fi e obtém a hora exata com precisão de milissegundos de servidores NTP (Network Time Protocol). Com a função configTzTime(), o fuso horário configurado (TRT, UTC+3 neste exemplo) é aplicado automaticamente, e as mudanças nos países que adotam horário de verão são gerenciadas automaticamente por uma string POSIX TZ. A hora é exibida tanto no Monitor Serial quanto em um LCD I2C opcional.

ESP32 HTTPClient + API de clima (com display LCD)
Neste projeto, usamos o ESP32 para fazer uma chamada REST à API de clima wttr.in pela internet com HTTPClient.h. Interpretamos a resposta JSON com ArduinoJson v7 e mostramos cidade, temperatura, umidade, condições do tempo e vento em um display LCD I2C, em turco e inglês. O wttr.in é grátis e não exige chave de API — basta informar o nome de uma cidade para consultar o clima atual. Os dados se atualizam sozinhos a cada 30 minutos, e o LED dá um retorno visual diferente para cada tela.

ESP32 em sono profundo — Economia de bateria (OLED + contador na RAM RTC)
O modo de sono profundo do ESP32 reduz o consumo de corrente para ~10 µA ao desligar a CPU e a maioria dos periféricos, sendo essencial para dispositivos IoT alimentados por bateria. Neste projeto, usamos três fontes de despertar: um temporizador (15 segundos), um pino externo (EXT0 — botão no GPIO 33) e toque (T0/GPIO 4). As variáveis marcadas com RTC_DATA_ATTR são preservadas durante o sono profundo, mantendo os contadores de inicializações e de despertares por temporizador e botão.
Mais artigos
- O que é ESP32? Características, configuração na Arduino IDE e seu primeiro projeto com Wi-Fi
- Servidor web assíncrono no ESP32 com WebSocket: painel de controle em tempo real
- ESP32 não conecta ao Wi-Fi? Códigos do WiFi.status() e soluções reais
- ESP32 “Brownout detector was triggered” e Guru Meditation: como resolver
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

