How to Set Up ESP32 Over-the-Air Updates
In this tutorial, you'll learn about How to Set Up ESP32 Over. We cover key concepts, practical examples, and best practices.
The Problem
You try to upload a new sketch to your ESP32 over Wi-Fi, but the Arduino IDE shows Error: No data received on the OTA port, the update freezes at 50%, or the ESP32 bricks after an update and will not boot. Over-the-Air (OTA) updates are convenient but fragile when misconfigured.
Quick Fix
Fix 1: Basic OTA Setup (Arduino IDE)
WRONG — writing the sketch without OTA code:
void setup() {
Serial.begin(115200);
// (Wi-Fi is connected but no OTA handler is registered)
}
RIGHT — include the ArduinoOTA library:
#include <WiFi.h>
#include <ArduinoOTA.h>
const char* ssid = "MyNetwork";
const char* password = "password123";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
ArduinoOTA.begin(); // important: starts OTA service
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle(); // important: must be called in loop
}
// Output:
// IP address: 192.168.1.42
// (now visible as "esp32-XXXXXXXXXXXX" in Arduino IDE Port menu)
Fix 2: OTA Update Fails Mid-Way
WRONG — losing Wi-Fi during the update:
// Update fails at 50% with:
// Error: ERROR: esp_ota_begin error 0x18
// (partition table issue or insufficient space)
RIGHT — check partition scheme and flash size:
# In Arduino IDE: Tools → Partition Scheme → "Huge APP (3MB No OTA/1MB SPIFFS)"
# For OTA: Tools → Partition Scheme → "Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)"
The ESP32 needs two application partitions for OTA (running app and update app). Select a partition scheme with OTA support.
Fix 3: Authentication Error
WRONG — no password protection:
ArduinoOTA.begin();
// (anyone on the network can upload code)
RIGHT — set a password:
ArduinoOTA.setPassword("mysecret");
// (or using hash for security)
ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA.begin();
Fix 4: Upload via Web Browser (Web OTA)
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
AsyncWebServer server(80);
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "OTA ready. Go to /update");
});
AsyncElegantOTA.begin(&server);
server.begin();
Serial.println("Web OTA at http://");
Serial.println(WiFi.localIP());
}
// Open browser at http://192.168.1.42/update and upload .bin file
Fix 5: Rollback After Failed Update
WRONG — ESP32 does not boot after update:
# (the new firmware is corrupt or incompatible)
RIGHT — enable rollback in the partition scheme:
ArduinoOTA.onError([](ota_error_t error) {
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
If the ESP32 does not boot after OTA, hold the BOOT button for 3 seconds to force factory mode or reflash via USB serial.
Fix 6: OTA from Another ESP32 (Peer OTA)
// Download firmware from another ESP32 HTTP server
HTTPClient http;
http.begin("http://192.168.1.50/firmware.bin");
int httpCode = http.GET();
if (httpCode == 200) {
Update.begin(http.getSize());
Update.writeStream(http.getStream());
if (Update.end()) {
Serial.println("OTA successful, rebooting...");
ESP.restart();
}
}
Use DodaTech's Fleet Manager to push OTA updates to multiple ESP32 devices simultaneously, with version tracking and automatic rollback.
Prevention
- Select a partition scheme with OTA support.
- Keep the ESP32 within Wi-Fi range during updates.
- Always include error handling in the OTA callback.
- Set a password for production OTA updates.
- Test OTA with a USB-serial fallback connection first.
Common Mistakes with over the air
- Misunderstanding that
Stringis[Char]with poor performance for large text operations - Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging
These mistakes appear frequently in real-world ESP32 code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro