22 static const char *
const TAG =
"ota";
23 static constexpr u_int16_t OTA_BLOCK_SIZE = 8192;
30 return make_unique<ArduinoESP8266OTABackend>();
33 return make_unique<ArduinoESP32OTABackend>();
37 return make_unique<IDFOTABackend>();
40 return make_unique<ArduinoRP2040OTABackend>();
43 return make_unique<ArduinoLibreTinyOTABackend>();
52 ESP_LOGW(TAG,
"Could not create socket.");
57 int err =
server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
59 ESP_LOGW(TAG,
"Socket unable to set reuseaddr: errno %d", err);
62 err =
server_->setblocking(
false);
64 ESP_LOGW(TAG,
"Socket unable to set nonblocking mode: errno %d", err);
73 ESP_LOGW(TAG,
"Socket unable to set sockaddr: errno %d", errno);
80 ESP_LOGW(TAG,
"Socket unable to bind: errno %d", errno);
87 ESP_LOGW(TAG,
"Socket unable to listen: errno %d", errno);
96 ESP_LOGCONFIG(TAG,
"Over-The-Air Updates:");
98 #ifdef USE_OTA_PASSWORD 100 ESP_LOGCONFIG(TAG,
" Using Password.");
103 ESP_LOGCONFIG(TAG,
" OTA version: %d.", USE_OTA_VERSION);
106 ESP_LOGW(TAG,
"Last Boot was an unhandled reset, will proceed to safe mode in %" PRIu32
" restarts",
117 ESP_LOGI(TAG,
"Boot seems successful, resetting boot loop counter.");
122 static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
126 bool update_started =
false;
128 uint32_t last_progress = 0;
130 char *sbuf =
reinterpret_cast<char *
>(buf);
132 uint8_t ota_features;
133 std::unique_ptr<OTABackend> backend;
135 #if USE_OTA_VERSION == 2 136 size_t size_acknowledged = 0;
141 socklen_t addr_len =
sizeof(source_addr);
148 int err =
client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
150 ESP_LOGW(TAG,
"Socket could not enable tcp nodelay, errno: %d", errno);
154 ESP_LOGD(TAG,
"Starting OTA Update from %s...", this->
client_->getpeername().c_str());
156 #ifdef USE_OTA_STATE_CALLBACK 161 ESP_LOGW(TAG,
"Reading magic bytes failed!");
165 if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
166 ESP_LOGW(TAG,
"Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3],
174 buf[1] = USE_OTA_VERSION;
181 ESP_LOGW(TAG,
"Reading features failed!");
184 ota_features = buf[0];
185 ESP_LOGV(TAG,
"OTA features is 0x%02X", ota_features);
189 if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
195 #ifdef USE_OTA_PASSWORD 205 ESP_LOGV(TAG,
"Auth: Nonce is %s", sbuf);
208 if (!this->
writeall_(reinterpret_cast<uint8_t *>(sbuf), 32)) {
209 ESP_LOGW(TAG,
"Auth: Writing nonce failed!");
221 ESP_LOGW(TAG,
"Auth: Reading cnonce failed!");
225 ESP_LOGV(TAG,
"Auth: CNonce is %s", sbuf);
232 ESP_LOGV(TAG,
"Auth: Result is %s", sbuf);
235 if (!this->
readall_(buf + 64, 32)) {
236 ESP_LOGW(TAG,
"Auth: Reading response failed!");
239 sbuf[64 + 32] =
'\0';
240 ESP_LOGV(TAG,
"Auth: Response is %s", sbuf + 64);
243 for (uint8_t i = 0; i < 32; i++)
244 matches = matches && buf[i] == buf[64 + i];
247 ESP_LOGW(TAG,
"Auth failed! Passwords do not match!");
252 #endif // USE_OTA_PASSWORD 260 ESP_LOGW(TAG,
"Reading size failed!");
264 for (uint8_t i = 0; i < 4; i++) {
268 ESP_LOGV(TAG,
"OTA size is %u bytes", ota_size);
270 error_code = backend->begin(ota_size);
273 update_started =
true;
281 ESP_LOGW(TAG,
"Reading binary MD5 checksum failed!");
285 ESP_LOGV(TAG,
"Update: Binary MD5 is %s", sbuf);
286 backend->set_update_md5(sbuf);
292 while (total < ota_size) {
294 size_t requested = std::min(
sizeof(buf), ota_size - total);
295 ssize_t read = this->
client_->read(buf, requested);
297 if (errno == EAGAIN || errno == EWOULDBLOCK) {
302 ESP_LOGW(TAG,
"Error receiving data for update, errno: %d", errno);
304 }
else if (read == 0) {
308 ESP_LOGW(TAG,
"Remote end closed connection");
312 error_code = backend->write(buf, read);
314 ESP_LOGW(TAG,
"Error writing binary data to flash!, error_code: %d", error_code);
318 #if USE_OTA_VERSION == 2 319 while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
322 size_acknowledged += OTA_BLOCK_SIZE;
327 if (now - last_progress > 1000) {
329 float percentage = (total * 100.0f) / ota_size;
330 ESP_LOGD(TAG,
"OTA in progress: %0.1f%%", percentage);
331 #ifdef USE_OTA_STATE_CALLBACK 344 error_code = backend->end();
346 ESP_LOGW(TAG,
"Error ending OTA!, error_code: %d", error_code);
356 ESP_LOGW(TAG,
"Reading back acknowledgement failed!");
363 ESP_LOGI(TAG,
"OTA update finished!");
365 #ifdef USE_OTA_STATE_CALLBACK 372 buf[0] =
static_cast<uint8_t
>(error_code);
377 if (backend !=
nullptr && update_started) {
382 #ifdef USE_OTA_STATE_CALLBACK 388 uint32_t start =
millis();
390 while (len - at > 0) {
392 if (now - start > 1000) {
393 ESP_LOGW(TAG,
"Timed out reading %d bytes of data", len);
397 ssize_t read = this->
client_->read(buf + at, len - at);
399 if (errno == EAGAIN || errno == EWOULDBLOCK) {
404 ESP_LOGW(TAG,
"Failed to read %d bytes of data, errno: %d", len, errno);
406 }
else if (read == 0) {
407 ESP_LOGW(TAG,
"Remote closed connection");
419 uint32_t start =
millis();
421 while (len - at > 0) {
423 if (now - start > 1000) {
424 ESP_LOGW(TAG,
"Timed out writing %d bytes of data", len);
428 ssize_t written = this->
client_->write(buf + at, len - at);
430 if (errno == EAGAIN || errno == EWOULDBLOCK) {
435 ESP_LOGW(TAG,
"Failed to write %d bytes of data, errno: %d", len, errno);
454 uint32_t current_rtc = this->
read_rtc_();
457 ESP_LOGI(TAG,
"Device will enter safe mode on next boot.");
462 ESP_LOGI(TAG,
"Safe mode pending has been cleared");
480 if (is_manual_safe_mode) {
481 ESP_LOGI(TAG,
"Safe mode has been entered manually");
483 ESP_LOGCONFIG(TAG,
"There have been %" PRIu32
" suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_);
486 if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) {
489 if (!is_manual_safe_mode) {
490 ESP_LOGE(TAG,
"Boot loop detected. Proceeding to safe mode.");
495 ESP_LOGE(TAG,
"No OTA attempt made, restarting.");
503 ESP_LOGI(TAG,
"Waiting for OTA attempt.");
508 this->
write_rtc_(this->safe_mode_rtc_value_ + 1);
528 #ifdef USE_OTA_STATE_CALLBACK void dump_config() override
void init()
Initialize a new MD5 digest computation.
std::unique_ptr< Socket > socket_ip(int type, int protocol)
Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol...
uint16_t get_port() const
uint32_t safe_mode_enable_time_
The time safe mode should be on for.
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port)
Set a sockaddr to the any address and specified port for the IP version used by socket_ip().
std::string get_use_address()
Get the active network hostname.
void status_set_warning(const char *message="unspecified")
bool get_safe_mode_pending()
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void add_on_state_callback(std::function< void(OTAState, float, uint8_t)> &&callback)
void setup()
Set up all the registered components. Call this at the end of your setup() function.
uint32_t safe_mode_start_time_
stores when safe mode was enabled.
uint32_t IRAM_ATTR HOT millis()
void status_momentary_error(const std::string &name, uint32_t length=5000)
bool readall_(uint8_t *buf, size_t len)
static const uint32_t ENTER_SAFE_MODE_MAGIC
a magic number to indicate that safe mode should be entered on next boot
void status_set_error(const char *message="unspecified")
void set_port(uint16_t port)
Manually set the port OTA should listen on.
ESPPreferences * global_preferences
void status_clear_warning()
std::unique_ptr< socket::Socket > client_
float get_setup_priority() const override
bool has_safe_mode_
stores whether safe mode can be enabled.
std::unique_ptr< OTABackend > make_ota_backend()
void write_rtc_(uint32_t val)
Application App
Global storage of Application pointer - only one Application can exist.
void on_safe_shutdown() override
OTAComponent * global_ota_component
bool should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time)
uint8_t safe_mode_num_attempts_
void IRAM_ATTR HOT yield()
virtual ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)=0
virtual void mark_failed()
Mark this component as failed.
uint32_t safe_mode_rtc_value_
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
virtual bool sync()=0
Commit pending writes to flash.
void set_safe_mode_pending(const bool &pending)
Set to true if the next startup will enter safe mode.
bool writeall_(const uint8_t *buf, size_t len)
std::unique_ptr< socket::Socket > server_
CallbackManager< void(OTAState, float, uint8_t)> state_callback_
OTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA...
void IRAM_ATTR HOT delay(uint32_t ms)