ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ota_backend_esp_idf.h
Go to the documentation of this file.
1#pragma once
2#ifdef USE_ESP32
3#include "ota_backend.h"
4
7
8#include <esp_idf_version.h>
9#include <esp_ota_ops.h>
10
11// esp_ota_resume() (IDF 5.4.2+, backported to 5.3.3) provides a no-erase OTA
12// handle, letting write() block-erase 64 KiB ahead of the write cursor
13// (~4x faster than the per-sector lazy erase of OTA_WITH_SEQUENTIAL_WRITES,
14// used as fallback on older IDF).
15#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2) || \
16 (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 3) && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 0))
17#define USE_OTA_BLOCK_ERASE_AHEAD
18#endif
19
20namespace esphome::ota {
21
22#ifdef USE_OTA_PARTITIONS
23// Staging buffer holds the entire partition table for verification before any flash op.
24static constexpr size_t PARTITION_TABLE_BUFFER_SIZE = ESP_PARTITION_TABLE_MAX_LEN; // 0xC00
25
26void get_running_app_position(uint32_t &offset, size_t &size);
27#endif
28
29class IDFOTABackend final {
30 public:
31 OTAResponseTypes begin(size_t image_size, ota::OTAType ota_type = ota::OTA_TYPE_UPDATE_APP);
32 void set_update_md5(const char *md5);
33 OTAResponseTypes write(uint8_t *data, size_t len);
35 void abort();
36 static constexpr bool supports_compression() { return false; }
37
38 protected:
41 if (result == OTA_RESPONSE_OK)
42 this->lock_.hold_until_reboot();
43 return result;
44 }
45#ifdef USE_OTA_PARTITIONS
46 // copy_dest_part non-null means the running app must be copied INTO this slot of the current
47 // table before the new partition table is committed. The destination is in the current table
48 // because that's where esp_partition_copy can write; once the new table replaces it, the same
49 // flash region becomes target_app_index in the new table.
52 const esp_partition_t *copy_dest_part{nullptr};
53 };
54
55 OTAResponseTypes validate_new_partition_table_(uint32_t running_app_offset, size_t running_app_size,
56 PartitionTablePlan &plan);
59 // Defined in ota_bootloader_esp_idf.cpp:
63 OTAResponseTypes finalize_bootloader_update_(esp_err_t ota_end_err);
64
65 // The OTA types that flow through esp_ota_begin/write/end. Partition-table updates take a
66 // separate code path that buffers the table in RAM and never touches the OTA handle.
68 return this->ota_type_ == ota::OTA_TYPE_UPDATE_APP || this->ota_type_ == ota::OTA_TYPE_UPDATE_BOOTLOADER;
69 }
70#endif
71
72 private:
73#ifdef USE_OTA_BLOCK_ERASE_AHEAD
74 OTAResponseTypes erase_ahead_(size_t len);
75#endif
76#ifdef USE_OTA_SIGNED_VERIFICATION_MULTI_KEY
77 // Accept an image signed by any key the running app trusts (up to 3 blocks),
78 // so rotation and backup keys work. Fails closed. Covers app and bootloader.
79 bool verify_signed_image_(const esp_partition_t *incoming);
80#endif
81 // Keep md5_ first since its digest_ is alignas(32) on DMA-SHA variants; md5_set_ stays last so buf_ packs tightly.
82 md5::MD5Digest md5_{};
83 esp_ota_handle_t update_handle_{0};
84 const esp_partition_t *partition_{nullptr};
85 size_t written_{0}; // Bytes handed to esp_ota_write()
86#ifdef USE_OTA_BLOCK_ERASE_AHEAD
87 size_t erased_end_{0}; // Erased up to this partition offset; must stay >= written_
88#endif
89 char expected_bin_md5_[32];
90 bool md5_set_{false};
91#ifdef USE_OTA_PARTITIONS
92 // Buffer first so it packs tightly after the preceding `bool md5_set_` with no alignment
93 // padding. Only resident during an active OTA: the backend is constructed per connection and
94 // destroyed on cleanup_connection_().
95 uint8_t buf_[PARTITION_TABLE_BUFFER_SIZE];
96 size_t buf_written_{0};
97 size_t image_size_{0};
98 const esp_partition_t *partition_table_part_{nullptr};
99 const esp_partition_t *bootloader_part_{nullptr};
101#endif
102};
103
104std::unique_ptr<IDFOTABackend> make_ota_backend();
105
106} // namespace esphome::ota
107#endif // USE_ESP32
void set_update_md5(const char *md5)
OTAResponseTypes finalize_bootloader_update_(esp_err_t ota_end_err)
OTAResponseTypes begin(size_t image_size, ota::OTAType ota_type=ota::OTA_TYPE_UPDATE_APP)
OTAResponseTypes prepare_bootloader_update_(size_t image_size)
static constexpr bool supports_compression()
OTAResponseTypes register_and_validate_bootloader_part_()
OTAResponseTypes write(uint8_t *data, size_t len)
OTAResponseTypes validate_new_partition_table_(uint32_t running_app_offset, size_t running_app_size, PartitionTablePlan &plan)
OTAResponseTypes hold_lock_if_ok_(OTAResponseTypes result)
OTAResponseTypes register_and_validate_partition_table_part_()
Serializes flash updates.
void hold_until_reboot()
Keep the lock set until reboot; is_held() becomes false.
@ OTA_TYPE_UPDATE_BOOTLOADER
Definition ota_backend.h:96
void get_running_app_position(uint32_t &offset, size_t &size)
std::unique_ptr< ArduinoLibreTinyOTABackend > make_ota_backend()
const void size_t len
Definition hal.h:68
uint16_t size
Definition helpers.cpp:34
static void uint32_t