OTA reliability comes frompartition mechanism + state machine + rollback confirmationthree things meshing together. This Skill provides baseline (high-confidence) facts and order; device facts such as partitions and offsets must always "read target first"; fabrication is forbidden.
Determine Task Type
- Add OTA capability to a product: partition layout rework + upgrade code + upgrade server → Workflow A (main path).
- After upgrade the device runs the old version: suspected rollback → Workflow B (troubleshooting, first check for unconfirmed PENDING_VERIFY).
- Upgrade channel robustness/decision: when to allow upgrades, what to do on failure → upgrade decision checklist + rollback-checklist。
- Upgrade without network / offline flashing: out of scope → refusal route
esp32-idf(see Hand-off).
Prerequisites / Preflight
idf.py --version # IDF 版本(基线见下)
idf.py partition-table # 读 target 实际分区表——任何分区回答的起点
idf.py confserver 2>/dev/null | head -5 || true # 存在性自检可忽略
- Read target first:
idf.py partition-tableoutput is the only valid source of partition facts; before there is target board output,refuse to fabricate partition offsets/sizes。 - Confirm the actual flash capacity (determines how large the OTA slot can be).
- Upgrade server: HTTPS reachable, CA certificate in hand (see Contracts item 4).
Offline Baseline
- ESP-IDF baseline = v6.1(as of walkthrough 2026-09-02, not auto-updated); partition mechanism, OTA state machine,
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE, and esp_https_ota are all cited from baseline §4/§5 (official partition-tables and ota docs, high confidence). - Behavior changes after this version are subject to the official OTA docs; do not assert from memory.
Contracts (Device Contracts)
- Partition prerequisites (high confidence): OTA requires at least two OTA app slots ota_0/ota_1 + otadata partition; the bootloader selects the slot according to otadata's ota_seq; if otadata is empty, it boots factory.
- Image validity status is stored in otadata (not inside the image): VALID/UNDEFINED can boot; INVALID/ABORTED do not boot.
- Only OTA slots can roll back, factory cannot—placing production firmware in a combination of factory + OTA slots is a common practice and supported by the mechanism, but rollback only occurs between OTA slots.
- HTTPS certificate: esp_https_ota uses HTTPS, and the firmware must hold the server CA certificate (the embedding method and verification options are subject to the official esp_https_ota docs, verified at runtime).Security stance: server certificate verification must not be disabled—disabling verification is equivalent to opening the upgrade channel to man-in-the-middle poisoning.
- Flashing/erasing partitions is a destructive operation: before changing the partition table, restate the current layout (Preflight output) and obtain confirmation.
Partition prerequisites and minimal CSV template
Mechanism hand-off esp32-idf(CSV fields, full Type/SubType set), this Skill only provides the OTA minimal complete template. Leave all Offset columns empty = let the build arrange them automatically (high confidence: empty Offset = automatic arrangement; app 64KB alignment and data partition 4KB alignment are guaranteed by the build)—do not hand-fill offset values from memory:
# Name, Type, SubType, Offset, Size, Flags
# 说明:Offset 留空自动排布;各 Size 按实际 flash 容量与 app 体积调整,
# 最终布局以 idf.py partition-table 输出为准(读 target 先行)。
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
factory, app, factory, , 1M,
ota_0, app, ota_0, , 1M,
ota_1, app, ota_1, , 1M,
menuconfig preset can be a starting point:"Factory app, two OTA definitions"(corresponds to the table above); "Single factory app, no OTA" means no OTA. The build will verify that the image must fit into some app partition—if it does not fit, it will error out directly; do not try to squeeze it in by shrinking nvs.
OTA state machine (core anti-pitfall)
写入非活动槽(esp_ota_begin/write/end)
-> esp_ota_set_boot_partition,镜像记为 NEW
-> 重启,bootloader 置 PENDING_VERIFY 后启动新镜像
├── 应用自检通过 -> esp_ota_mark_app_valid_cancel_rollback() -> VALID(转正)
├── 应用自检失败 -> esp_ota_mark_app_invalid_rollback_and_reboot() -> ABORTED 回滚旧版
└── 新镜像崩溃/看门狗反复重启,从未调用确认 -> 重启即回滚旧版(INVALID)
Trap #1 for this skill: after enabling CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE ,the new image must explicitly call esp_ota_mark_app_valid_cancel_rollback()on the application side—the consequence of not calling it is not "success by default", but ratherrolling back to the old version on the first reboot. The number one cause of "after a successful upgrade the device runs the old version again" is an omitted self-check confirmation (for troubleshooting see Workflow B).
API order (high confidence):esp_ota_begin(if the size is unknown, pass OTA_SIZE_UNKNOWN)→ esp_ota_write(block loop) → esp_ota_end(image verification) → esp_ota_set_boot_partition; for slot selection use esp_ota_get_next_update_partition() rotation. For high-level encapsulation use esp_https_ota(esp_https_ota_config_t, with buffer_size/bulk_flash_erase and other tuning options). Anti-rollback (optional)CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK: secure_version burns eFuse and can only increase—enabling it involves an irreversible eFuse operation, route esp32-secureboot。
Capability Boundaries + Hand-off
| User Intent | Skill |
|---|---|
| Project skeleton/partition table mechanism fundamentals/USB serial flashing | esp32-idf |
| Offline device upgrade (no network) | refusal: OTA inherently requires a network; for offline use USB serial flashing → esp32-idf |
| Signing/anti-rollback eFuse/encrypted image | esp32-secureboot |
| Real-device upgrade + power-loss rollback acceptance | fw-hil-testing |
| Upgrade package naming/checksum/release process | fw-release-gate |
| Locating a crash in the new image after upgrade | esp32-debug(coredump) |
| Pre-upgrade network (credentials invalid, cannot connect) | esp32-wifi-provision |
Workflow A — Add OTA dual-partition rollback support (main path)
- Read target:
idf.py partition-tableto record the current layout; confirm that ota_0/ota_1/otadata exist; if not, modify according to the CSV template above (leave Offset blank),refuse to fabricate offsets。 - menuconfig: In Partition Table preselect "Factory app, two OTA definitions"; enable
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE。 - Implement the upgrade flow:
esp_ota_get_next_update_partition()select slot →esp_ota_begin/write/end→esp_ota_set_boot_partition→ reboot; for download use esp_https_ota (for certificates follow Article 4 of Contracts). - Implement self-check confirmation: after the new image starts, complete a business-level self-check (peripherals present, network present, critical tasks running), and immediately after passing
esp_ota_mark_app_valid_cancel_rollback(); if the self-check fails, callesp_ota_mark_app_invalid_rollback_and_reboot()。do not leave "we'll do it next time" for confirmation。 - Real-device acceptance: see Validation Gates; among them, power-loss rollback acceptance →
fw-hil-testing。 - When there is no real device, mark all conclusions as
Build Verification Only。
Workflow B — After upgrade, the device reboots into the old version (troubleshooting)
- First check for state machine gaps: whether in the new image there exists andis necessarily executedthe
esp_ota_mark_app_valid_cancel_rollback()? (A hung self-check/blocked task will cause confirmation to never execute.) - Confirm menuconfig:
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLEwhether it is enabled (once enabled, the semantics are "rollback if unconfirmed", which is mechanism behavior, not a fault). - Read the evidence: serial boot log +
esp32-debug(coredump/reset reason) to locate whether the new image crashes before confirmation. - Refer to rollback-checklist acceptance checklist and replay the upgrade process once.
Upgrade decision checklist (conditions allowing the upgrade to start)
- Version comparison: the target version is newer than the current version; anti-rollback requirement (eFuse secure_version) →
esp32-secureboot。 - Window and battery: for battery devices, battery level is above the threshold; business idle window; no power loss during upgrade (notify the user).
- Image budget: new image ≤ OTA slot size (known only after reading target).
- Rollback plan: The confirmation logic has been implemented and rehearsed; on failure it can return to the old version (only between OTA slots).
- Channel security: HTTPS + certificate verification enabled, images are not pulled over plaintext HTTP.
- On-device acceptance items →
fw-hil-testing; release artifact verification →fw-release-gate。
Validation Gates
- Normal upgrade: the new version number is reported, otadata points to the new slot, and the application is in VALID.
- Rollback acceptance: Flash a test image that is guaranteed to fail its self-check → the device automatically returns to the old version and can be upgraded again (execute on a real device; no real device = Pending HIL).
- Unconfirmed semantics acceptance: with the confirmation call commented out, after a reboot it returns to the old version—used to prove the anti-trap has been understood.
- Power-loss interrupted upgrade: after the upgrade is interrupted, the device can still boot (the old slot was not damaged).
- Channel security: packet capture confirms HTTPS; testing against a server with an expired/wrong certificate is rejected.
Pitfalls
- Do notenable ROLLBACK and then forget to write the confirmation call—the culprit behind "upgrade succeeds but it returns to the old version".
- Do notfabricate partition offsets/sizes—leave Offset blank for automatic layout, and the placement is based on
idf.py partition-table. - Do notdisable esp_https_ota's server certificate verification—I do not provide that path.
- Do notpresent a layout of "factory only, no OTA slots" as supporting rollback—rollback only occurs between OTA slots.
- Do notpromise that "offline devices can also do OTA"—OTA inherently requires a network; for offline, use USB serial flashing (route
esp32-idf)。 - Do notretry downloads infinitely in the upgrade loop—failures must have backoff and a limit, to avoid the device getting stuck in an "upgrade storm".
Official Sources
Privacy
Upgrade metadata (device version, serial number, upgrade server URL) and diagnostic logs may contain device identifiers: do not collect, do not send externally; upgrade server credentials/certificate private keys are governed according to fw-release-gate , and must not enter the repository or logs.