1. Partition table with two app slots
OTA writes the new firmware into the other app slot, so the flash layout needs:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, , 0x5000,
otadata, data, ota, , 0x2000,
app0, app, ota_0, , 0x1E0000,
app1, app, ota_1, , 0x1E0000,
(Sizes are an example for a 4 MB flash; your firmware must fit into one slot.)
- Arduino IDE: Tools → Partition Scheme (pick one with OTA), or put a
partitions.csvin the sketch folder. - PlatformIO:
board_build.partitions = partitions.csv. - ESP-IDF:
menuconfig→ Partition Table.
2. Validate the new image before trusting it
With app rollback enabled (CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE), the new image first boots in the state ESP_OTA_IMG_PENDING_VERIFY:
#include "esp_ota_ops.h"
void confirm_or_rollback(void) {
const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t state;
if (esp_ota_get_state_partition(running, &state) == ESP_OK &&
state == ESP_OTA_IMG_PENDING_VERIFY) {
if (self_test_ok()) { // Wi-Fi up, server reachable, sensors respond
esp_ota_mark_app_valid_cancel_rollback();
} else {
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
If the new image crashes or resets before it is marked valid, the bootloader marks it aborted and boots the previous firmware.
Rollback is a bootloader/build option. With the prebuilt Arduino core you can't change menuconfig options directly; using Arduino as an ESP-IDF component (or an ESP-IDF build) gives you access to them. Check whether the bootloader you ship actually has rollback enabled.
3. Pitfalls
- Confirming at the top of
setup()defeats the purpose. Confirm after the self-test. - No watchdog: a hung image never resets and never rolls back. Keep the task watchdog active.
- Unauthenticated update endpoints: the Arduino OTAWebUpdater example uses the hard-coded login
admin/admin. Change it, and prefer pulling signed firmware over HTTPS from your server to accepting uploads on the device. - Firmware too big: after enabling OTA the app slot is half the size it was. Check the build size against the slot.