esp32 intermediate 30 min

ESP32: OTA (over-the-air) firmware updates

Update ESP32 firmware over Wi-Fi without plugging in USB. The feature that turns a project from prototype into something you actually deploy.

Code available for: ESP32 Arduino
Published Aug 8, 2026

OTA (over-the-air) updates are the feature that takes an ESP32 project from “plugged into my laptop” to “deployed on the ceiling of the garage.” Once OTA is set up, you can update the firmware from your laptop without climbing a ladder.

This tutorial is the minimum version. It uses Arduino OTA, which is built in to the ESP32 Arduino core.

What you need

  • An ESP32 you can currently program over USB
  • A computer on the same Wi-Fi network

The code

#include <WiFi.h>
#include <ESPmDNS.h>
#include <ArduinoOTA.h>

const char* ssid     = "your-wifi-ssid";
const char* password = "your-wifi-password";

void setup() {
  Serial.begin(115200);
  delay(1000);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  ArduinoOTA.setHostname("esp32-ota-test");
  ArduinoOTA.begin();

  Serial.print("Ready. IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  ArduinoOTA.handle();
  // your normal code here
}

Upload it. Open Serial Monitor. Note the IP. Now go to the Arduino IDE.

Configure the Arduino IDE for OTA

  1. Select Tools >> Port. You should see a new entry under “Network ports” that says something like esp32-ota-test at 192.168.1.42. Select that.
  2. Click Upload.

The IDE sends the firmware over the network. The ESP32 reboots into the new firmware. You did not touch the USB cable.

What happens during an OTA update

  1. The ESP32 listens on port 3232 (Arduino OTA default).
  2. The IDE connects, sends the new firmware in chunks.
  3. The ESP32 writes the new firmware to a second partition.
  4. When the upload is complete, the ESP32 sets a flag and reboots.
  5. The bootloader sees the flag, swaps partitions, and boots the new firmware.

If the new firmware is broken (e.g. crashes on boot), the ESP32 rolls back to the previous one automatically. The roll-back is built in to the partition scheme.

Setting a password

Without a password, anyone on your Wi-Fi can upload to your ESP32. Add a password:

ArduinoOTA.setPassword("your-password-here");

You will be prompted for the password in the Arduino IDE when you upload.

Setting a port

If 3232 conflicts with something else on your network:

ArduinoOTA.setPort(3232);   // pick something else

Why OTA updates fail

  • The ESP32 and the IDE are on different Wi-Fi networks. Check both are on the same SSID. Some networks isolate clients from each other (guest networks, IoT VLANs).
  • The IDE is showing the wrong network port. After rebooting the ESP32, the IDE may still have the old entry. Click the port dropdown and re-select.
  • The mDNS hostname is conflicting. If you have two ESP32s with the same hostname, only one shows up in the IDE. Set unique hostnames:
ArduinoOTA.setHostname("esp32-garage-sensor");
  • Firewall on the laptop. Some firewalls block port 3232. Allow it or temporarily disable the firewall for testing.

Adding a manual OTA trigger

For deployed devices, I add a “double-tap reset” or a button press that enables OTA only for 60 seconds. That way a stray update can never brick a deployed device:

#define OTA_BUTTON_PIN 0   // GPIO 0 (the BOOT button on most boards)

unsigned long otaWindowStart = 0;
const unsigned long OTA_WINDOW_MS = 60000;

void setup() {
  // ... after ArduinoOTA.begin() ...

  pinMode(OTA_BUTTON_PIN, INPUT_PULLUP);
}

void checkOtaTrigger() {
  if (digitalRead(OTA_BUTTON_PIN) == LOW) {
    otaWindowStart = millis();
  }
}

void loop() {
  checkOtaTrigger();

  if (millis() - otaWindowStart < OTA_WINDOW_MS) {
    ArduinoOTA.handle();   // OTA only available during window
  }
  // ... your normal code ...
}

Hold the BOOT button on most ESP32 boards and OTA becomes available for 60 seconds. Let go of the button (or wait 60 seconds) and OTA is locked again.

When to use OTA vs. a custom update mechanism

  • Arduino OTA for development and hobbyist projects. Easy. Built in.
  • HTTP OTA (e.g. fetch a firmware.bin from a URL) for production deployments. Lets you push updates to a fleet of devices from a server.
  • ESP-IDF OTA if you need signed firmware, encrypted firmware, or rollback to a specific version.

The HTTP OTA version is in the book ESP32 in Production. The ESP-IDF version is in the Learn ESP-IDF book.

What you just built

The single most useful deployment feature for ESP32 projects. Combine this with deep sleep (covered in a separate tutorial) and you have a sensor network that you can update without unplugging anything.

What to build next

  • The OTA signing tutorial secures the update channel.
  • The NVS storage tutorial persists state across updates.
  • The book IoT with ESP32 bundles the foundations.