ESP32 OTA updates (Over-the-Air) allow you to update your ESP32 wirelessly, without the need for a physical connection every time you want to upload new firmware. This is especially useful for IoT applications where devices are deployed remotely.
In this guide, you’ll learn what OTA programming is, how it works with ESP32, and how to implement it using the Arduino IDE.
What is OTA (Over-the-Air) Programming?
Over-the-air (OTA) programming is a method of updating the firmware of a microcontroller, like the ESP32, wirelessly. Instead of connecting your ESP via USB, you can send firmware updates over Wi-Fi.
Both, the Arduino IDE and the ESP32 support OTA programming.
How Does OTA Work?
At first, an OTA code snippet must be added to the firmware and uploaded to the microcontroller using a wired USB connection. This code snippet allows for connecting and uploading code to the microcontroller over Wi-Fi in the future.
Now, if the firmware has been updated and needs to be deployed, this can be done wirelessly using Wi-Fi. However, the OTA code must remain in the updated firmware. Otherwise, wireless updates won’t be possible the next time.
Additionally, OTA updates can be signed and encrypted for enhanced security.
Implementing ESP32 OTA Update in Arduino IDE
Step 1: Requirements
To begin, you’ll need your ESP32 and the Arduino IDE set up to work with the ESP32. Also, you’ll need a USB cable to upload the initial OTA programming code.
If you need help setting up the Arduino IDE to work with the ESP32, check out this detailed guide.
Luckily, there’s nothing else we need to set up! You can proceed with the next step.
Step 2: Upload the Basic OTA Sketch via USB
Before we can upload code to our microcontroller over the air, we need to upload a specific piece of code that allows us to connect to the ESP32 wirelessly and update its firmware.
If you correctly installed the ESP32 in Arduino IDE, you can find the initial OTA update code as an example sketch in the IDE under File > Examples > ArduinoOTA > BasicOTA.
In case you can’t find the example code in the Arduino IDE, here is it for you to copy:
#include <WiFi.h>
#include <ESPmDNS.h>
#include <NetworkUdp.h>
#include <ArduinoOTA.h>
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
void setup() {
Serial.begin(115200);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
// ArduinoOTA.setHostname("myesp32");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", 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");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
}
Make sure to enter your Wi-Fi credentials in the ssid and password constants.
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
Also, the ArduinoOTA library lets you set your own hostname and password for connecting to the ESP. The standard password is set to admin.
Upload the Code via USB
After entering your credentials and adapting the code to your needs, it’s time to upload the code to your ESP via USB.
If you encounter any problems during that process, check out my help article on fixing connection and COM port issues with the ESP32.
It might be useful to assign a static IP address to your ESP32 for the next time you want to update the firmware. Check out how to assign a static IP address to your ESP32 here!
Step 3: Upload a Sketch Over-the-Air!
Updated Sketch
Now, we can upload the first sketch over the air using Wi-Fi. Theoretically, you don’t need a USB cable for that process anymore. However, I like to keep it plugged in order to power my ESP.
Of course, we want to make the changes to our OTA firmware update visible. Therefore, we will modify the code so that the built-in LED of the ESP32 starts to flash:
#include <WiFi.h>
#include <ESPmDNS.h>
#include <NetworkUdp.h>
#include <ArduinoOTA.h>
const char *ssid = "YOUR_SSID";
const char *password = "YOUR_PASSWORD";
const int ledPin = 2; // Built-in LED pin for most ESP32 boards
unsigned long prevMillis = 0; // a helper variable for the timing
const long interval = 250; // interval at which to blink the led in milliseconds
int ledState = LOW; // state of the LED
void setup() {
Serial.begin(115200);
// initialize LED pin
pinMode(ledPin, OUTPUT);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
// ArduinoOTA.setHostname("myesp32");
// No authentication by default
// ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", 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");
}
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
ArduinoOTA.handle();
unsigned long currentMillis = millis();
if (currentMillis - prevMillis >= interval) {
// save the last time the LED was blinked
prevMillis = currentMillis;
// if the LED is off turn it on and vice-versa
ledState = !ledState;
// update LED state
digitalWrite(ledPin, ledState);
}
}
Notice that we changed the code in three places in order to make the LED blink:
const int ledPin = 2; // Built-in LED pin for most ESP32 boards
unsigned long prevMillis = 0; // a helper variable for the timing
const long interval = 250; // interval at which to blink the led in milliseconds
int ledState = LOW; // state of the LED
This little piece of code stores important values, like the LED pin we want to address, the interval, and the current LED state.
// initialize LED pin
pinMode(ledPin, OUTPUT);
In the setup function, we initialize the pin of the built-in LED to be an output.
unsigned long currentMillis = millis();
if (currentMillis - prevMillis >= interval) {
// save the last time the LED was blinked
prevMillis = currentMillis;
// if the LED is off turn it on and vice-versa
ledState = !ledState;
// update LED state
digitalWrite(ledPin, ledState);
}
Last but not least, we have the part of the code that actually switches the state of the LED which makes it blink.
Notice how we don’t use the usual delay() function. Instead, we count the milliseconds that have passed since we last switched the LED on or off
We do that because the delay() function pauses the program. That’s not good, because if we start uploading code over Wi-Fi, the ESP32 is very likely in a paused state and won’t receive the request.
Important: Always include the OTA code snippet!
Upload New Sketch
Next, we need to upload the code to the microcontroller. Instead of selecting a COM port, we select the network port the ESP32 has opened.
Don’t worry if your ESP32 takes a while to show up in the Arduino IDE.
After selecting the right development board and network port, it’s time to upload the code via Wi-Fi.
Simply hit the normal upload button in the top right. When prompted for a password, enter the OTA password you specified in the OTA code. The standard password is admin.
If everything works as intended, you should see the code being transmitted to your ESP:
That’s it! You are now able to upload code to your ESP32 over the air using Wi-Fi.
Where Are OTA Updates Used?
OTA updates are used in various industries and DIY projects where physical access to the microcontroller isn’t possible or at least not easy. Here’s a list of use cases for OTA updates:
- IoT Devices: Smart home devices, industrial automation, and remote sensors
- Automotive: Wireless updates for car infotainment systems and embedded controllers
- Consumer Electronics: Smartwatches, fitness trackers, and home automation hubs
- Robotics: Drones and autonomous systems that require frequent software updates
ESP32 OTA Updates: Wrapping Up
ESP32 OTA updates are a powerful feature that allows you to upload code to your ESP32 without a physical USB connection. This is particularly useful for IoT, automotive, and consumer electronics applications.
With just a few lines of code in the Arduino IDE, you can enable wireless programming and streamline your development workflow.
Share your experiences with over-the-air programming in the comments below!
Thanks for reading, Happy Coding!
Links marked with an asterisk (*) are affiliate links which means we may receive a commission for purchases made through these links at no extra cost to you. Read more on our Affiliate Disclosure Page.