ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
ota_backend_esp_idf.cpp
Go to the documentation of this file.
1#ifdef USE_ESP32
3
7#include "esphome/core/log.h"
8
9#include <esp_ota_ops.h>
10#include <esp_task_wdt.h>
11#include <spi_flash_mmap.h>
12
13namespace esphome::ota {
14
15static const char *const TAG = "ota.idf";
16
17std::unique_ptr<IDFOTABackend> make_ota_backend() { return make_unique<IDFOTABackend>(); }
18
20#ifdef USE_OTA_PARTITIONS
21 this->ota_type_ = ota_type;
22 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_PARTITION_TABLE) {
23 // Reject any size other than ESP_PARTITION_TABLE_MAX_LEN
24 if (image_size != ESP_PARTITION_TABLE_MAX_LEN) {
25 ESP_LOGE(TAG, "Wrong partition table size: expected %u bytes, got %zu", ESP_PARTITION_TABLE_MAX_LEN, image_size);
27 }
28 memset(this->buf_, 0xFF, sizeof this->buf_);
29 this->buf_written_ = 0;
30 this->image_size_ = image_size;
31 this->md5_.init();
32 return OTA_RESPONSE_OK;
33 }
34 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_BOOTLOADER) {
35 OTAResponseTypes result = this->prepare_bootloader_update_(image_size);
36 if (result != OTA_RESPONSE_OK) {
37 return result;
38 }
39 }
40 if (!this->is_app_or_bootloader_update_()) {
42 }
43#else
44 if (ota_type != ota::OTA_TYPE_UPDATE_APP) {
46 }
47#endif
48#ifdef USE_OTA_ROLLBACK
49 // If we're starting an OTA, the current boot is good enough - mark it valid
50 // to prevent rollback and allow the OTA to proceed even if the safe mode
51 // timer hasn't expired yet.
52 esp_ota_mark_app_valid_cancel_rollback();
53#endif
54
55 this->partition_ = esp_ota_get_next_update_partition(nullptr);
56 if (this->partition_ == nullptr) {
58 }
59
60 watchdog::WatchdogManager watchdog(15000);
61 esp_err_t err = esp_ota_begin(this->partition_, image_size, &this->update_handle_);
62
63 if (err != ESP_OK) {
64 ESP_LOGE(TAG, "esp_ota_begin failed (err=0x%X)", err);
65 esp_ota_abort(this->update_handle_);
66 this->update_handle_ = 0;
67 if (err == ESP_ERR_INVALID_SIZE) {
69 } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
71 } else if (err == ESP_ERR_OTA_PARTITION_CONFLICT) {
72 // This error appears with 1 factory and 1 ota partition
74 }
76 }
77#ifdef USE_OTA_PARTITIONS
78 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_BOOTLOADER) {
80 if (result != OTA_RESPONSE_OK) {
81 return result;
82 }
83 }
84#endif
85 this->md5_.init();
86 return OTA_RESPONSE_OK;
87}
88
89void IDFOTABackend::set_update_md5(const char *expected_md5) {
90 memcpy(this->expected_bin_md5_, expected_md5, 32);
91 this->md5_set_ = true;
92}
93
95#ifdef USE_OTA_PARTITIONS
96 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_PARTITION_TABLE) {
97 if (len > PARTITION_TABLE_BUFFER_SIZE - this->buf_written_) {
98 ESP_LOGE(TAG, "Wrong partition table size");
100 }
101 memcpy(this->buf_ + this->buf_written_, data, len);
102 this->buf_written_ += len;
103 this->md5_.add(data, len);
104 return OTA_RESPONSE_OK;
105 }
106 if (!this->is_app_or_bootloader_update_()) {
108 }
109#endif
110 esp_err_t err = esp_ota_write(this->update_handle_, data, len);
111 this->md5_.add(data, len);
112 if (err != ESP_OK) {
113 ESP_LOGE(TAG, "esp_ota_write failed (err=0x%X)", err);
114 if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
116 } else if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
118 }
120 }
121 return OTA_RESPONSE_OK;
122}
123
125 if (this->md5_set_) {
126 this->md5_.calculate();
127 if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
128 this->abort();
130 }
131 }
132#ifdef USE_OTA_PARTITIONS
133 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_PARTITION_TABLE) {
134 return this->update_partition_table();
135 }
136 if (!this->is_app_or_bootloader_update_()) {
138 }
139#endif
140 esp_err_t err = esp_ota_end(this->update_handle_);
141 this->update_handle_ = 0;
142 if (err != ESP_OK) {
143 ESP_LOGE(TAG, "esp_ota_end failed (err=0x%X)", err);
144 }
145#ifdef USE_OTA_PARTITIONS
146 if (this->ota_type_ == ota::OTA_TYPE_UPDATE_BOOTLOADER) {
147 return this->finalize_bootloader_update_(err);
148 }
149#endif
150 if (err == ESP_OK) {
151 err = esp_ota_set_boot_partition(this->partition_);
152 if (err == ESP_OK) {
153 return OTA_RESPONSE_OK;
154 }
155 }
156 if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
157#ifdef USE_OTA_SIGNED_VERIFICATION
158 ESP_LOGE(TAG, "OTA validation failed (err=0x%X) - possible signature verification failure", err);
160#else
162#endif
163 }
164 if (err == ESP_ERR_FLASH_OP_TIMEOUT || err == ESP_ERR_FLASH_OP_FAIL) {
166 }
168}
169
171#ifdef USE_OTA_PARTITIONS
172 if (this->partition_table_part_ != nullptr) {
173 esp_partition_deregister_external(this->partition_table_part_);
174 this->partition_table_part_ = nullptr;
175 }
176 if (this->bootloader_part_ != nullptr) {
177 esp_partition_deregister_external(this->bootloader_part_);
178 this->bootloader_part_ = nullptr;
179 }
180#endif
181 // esp_ota_abort with handle 0 returns ESP_ERR_INVALID_ARG harmlessly, so this is safe whether
182 // or not an update is in flight.
183 esp_ota_abort(this->update_handle_);
184 this->update_handle_ = 0;
185}
186
187} // namespace esphome::ota
188#endif // USE_ESP32
bool equals_hex(const char *expected)
Compare the hash against a provided hex-encoded hash.
Definition hash_base.h:35
void calculate() override
Compute the digest, based on the provided data.
Definition md5.cpp:16
void add(const uint8_t *data, size_t len) override
Add bytes of data for the digest.
Definition md5.cpp:14
void init() override
Initialize a new MD5 digest computation.
Definition md5.cpp:9
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)
OTAResponseTypes write(uint8_t *data, size_t len)
@ OTA_TYPE_UPDATE_BOOTLOADER
Definition ota_backend.h:63
@ OTA_TYPE_UPDATE_PARTITION_TABLE
Definition ota_backend.h:62
@ OTA_RESPONSE_ERROR_MD5_MISMATCH
Definition ota_backend.h:41
@ OTA_RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE
Definition ota_backend.h:39
@ OTA_RESPONSE_ERROR_WRITING_FLASH
Definition ota_backend.h:33
@ OTA_RESPONSE_ERROR_UNSUPPORTED_OTA_TYPE
Definition ota_backend.h:44
@ OTA_RESPONSE_ERROR_UPDATE_END
Definition ota_backend.h:34
@ OTA_RESPONSE_ERROR_SIGNATURE_INVALID
Definition ota_backend.h:43
@ OTA_RESPONSE_ERROR_UNKNOWN
Definition ota_backend.h:49
@ OTA_RESPONSE_ERROR_NO_UPDATE_PARTITION
Definition ota_backend.h:40
@ OTA_RESPONSE_ERROR_MAGIC
Definition ota_backend.h:30
@ OTA_RESPONSE_ERROR_PARTITION_TABLE_VERIFY
Definition ota_backend.h:45
std::unique_ptr< ArduinoLibreTinyOTABackend > make_ota_backend()
std::string size_t len