21static const char *
const TAG =
"esphome.ota";
22static constexpr uint16_t OTA_BLOCK_SIZE = 8192;
23static constexpr uint32_t OTA_SOCKET_TIMEOUT_HANDSHAKE = 10000;
24static constexpr uint32_t OTA_SOCKET_TIMEOUT_DATA = 90000;
27#ifdef USE_OTA_STATE_CALLBACK
38 int err = this->
server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
43 err = this->
server_->setblocking(
false);
76 "Over-The-Air updates:\n"
80#ifdef USE_OTA_PASSWORD
82 ESP_LOGCONFIG(TAG,
" Password configured");
97static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
106 if (this->
client_ ==
nullptr) {
109 socklen_t addr_len =
sizeof(source_addr);
115 int err = this->
client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
121 err = this->
client_->setblocking(
false);
135 ESP_LOGW(TAG,
"Handshake timeout");
146 if (read == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
155 ESP_LOGW(TAG,
"Remote closed during handshake");
167 static const uint8_t MAGIC_BYTES[5] = {0x6C, 0x26, 0xF7, 0x5C, 0x45};
168 if (memcmp(this->
magic_buf_, MAGIC_BYTES, 5) != 0) {
169 ESP_LOGW(TAG,
"Magic bytes mismatch! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", this->
magic_buf_[0],
173 this->
client_->write(&error, 1);
190 bool update_started =
false;
192 uint32_t last_progress = 0;
194 char *sbuf =
reinterpret_cast<char *
>(buf);
196 uint8_t ota_features;
197 std::unique_ptr<ota::OTABackend> backend;
199#if USE_OTA_VERSION == 2
200 size_t size_acknowledged = 0;
205 buf[1] = USE_OTA_VERSION;
215 ota_features = buf[0];
216 ESP_LOGV(TAG,
"Features: 0x%02X", ota_features);
220 if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
226#ifdef USE_OTA_PASSWORD
236 ESP_LOGV(TAG,
"Auth: Nonce is %s", sbuf);
239 if (!this->
writeall_(
reinterpret_cast<uint8_t *
>(sbuf), 32)) {
240 ESP_LOGW(TAG,
"Auth: Writing nonce failed");
246 md5.add(this->
password_.c_str(), this->password_.length());
252 ESP_LOGW(TAG,
"Auth: Reading cnonce failed");
256 ESP_LOGV(TAG,
"Auth: CNonce is %s", sbuf);
263 ESP_LOGV(TAG,
"Auth: Result is %s", sbuf);
266 if (!this->
readall_(buf + 64, 32)) {
267 ESP_LOGW(TAG,
"Auth: Reading response failed");
270 sbuf[64 + 32] =
'\0';
271 ESP_LOGV(TAG,
"Auth: Response is %s", sbuf + 64);
274 for (uint8_t i = 0; i < 32; i++)
275 matches = matches && buf[i] == buf[64 + i];
278 ESP_LOGW(TAG,
"Auth failed! Passwords do not match");
295 for (uint8_t i = 0; i < 4; i++) {
299 ESP_LOGV(TAG,
"Size is %u bytes", ota_size);
307#ifdef USE_OTA_STATE_CALLBACK
312 error_code = backend->begin(ota_size);
315 update_started =
true;
327 ESP_LOGV(TAG,
"Update: Binary MD5 is %s", sbuf);
328 backend->set_update_md5(sbuf);
334 while (total < ota_size) {
336 size_t requested = std::min(
sizeof(buf), ota_size - total);
339 if (errno == EAGAIN || errno == EWOULDBLOCK) {
343 ESP_LOGW(TAG,
"Read error, errno %d", errno);
345 }
else if (read == 0) {
349 ESP_LOGW(TAG,
"Remote closed connection");
353 error_code = backend->write(buf, read);
355 ESP_LOGW(TAG,
"Flash write error, code: %d", error_code);
359#if USE_OTA_VERSION == 2
360 while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
363 size_acknowledged += OTA_BLOCK_SIZE;
368 if (now - last_progress > 1000) {
370 float percentage = (total * 100.0f) / ota_size;
371 ESP_LOGD(TAG,
"Progress: %0.1f%%", percentage);
372#ifdef USE_OTA_STATE_CALLBACK
384 error_code = backend->end();
386 ESP_LOGW(TAG,
"Error ending update! code: %d", error_code);
402 ESP_LOGI(TAG,
"Update complete");
404#ifdef USE_OTA_STATE_CALLBACK
411 buf[0] =
static_cast<uint8_t
>(error_code);
415 if (backend !=
nullptr && update_started) {
420#ifdef USE_OTA_STATE_CALLBACK
426 uint32_t start =
millis();
428 while (
len - at > 0) {
430 if (now - start > OTA_SOCKET_TIMEOUT_DATA) {
431 ESP_LOGW(TAG,
"Timeout reading %d bytes",
len);
437 if (errno != EAGAIN && errno != EWOULDBLOCK) {
438 ESP_LOGW(TAG,
"Error reading %d bytes, errno %d",
len, errno);
441 }
else if (read == 0) {
442 ESP_LOGW(TAG,
"Remote closed connection");
453 uint32_t start =
millis();
455 while (
len - at > 0) {
457 if (now - start > OTA_SOCKET_TIMEOUT_DATA) {
458 ESP_LOGW(TAG,
"Timeout writing %d bytes",
len);
464 if (errno != EAGAIN && errno != EWOULDBLOCK) {
465 ESP_LOGW(TAG,
"Error writing %d bytes, errno %d",
len, errno);
485 ESP_LOGD(TAG,
"Starting %s from %s", phase, this->
client_->getpeername().c_str());
void feed_wdt(uint32_t time=0)
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
virtual void mark_failed()
Mark this component as failed.
void status_set_warning(const char *message=nullptr)
void status_momentary_error(const std::string &name, uint32_t length=5000)
void status_clear_warning()
uint16_t get_port() const
void yield_and_feed_watchdog_()
bool writeall_(const uint8_t *buf, size_t len)
void log_start_(const char *phase)
void dump_config() override
void log_socket_error_(const char *msg)
uint32_t client_connect_time_
float get_setup_priority() const override
bool readall_(uint8_t *buf, size_t len)
void set_port(uint16_t port)
Manually set the port OTA should listen on.
std::unique_ptr< socket::Socket > server_
void cleanup_connection_()
void log_read_error_(const char *what)
std::unique_ptr< socket::Socket > client_
void init()
Initialize a new MD5 digest computation.
StateCallbackManager state_callback_
std::string get_use_address()
Get the active network hostname.
void register_ota_platform(OTAComponent *ota_caller)
std::unique_ptr< ota::OTABackend > make_ota_backend()
@ OTA_RESPONSE_UPDATE_PREPARE_OK
@ OTA_RESPONSE_SUPPORTS_COMPRESSION
@ OTA_RESPONSE_BIN_MD5_OK
@ OTA_RESPONSE_UPDATE_END_OK
@ OTA_RESPONSE_RECEIVE_OK
@ OTA_RESPONSE_ERROR_AUTH_INVALID
@ OTA_RESPONSE_ERROR_UNKNOWN
@ OTA_RESPONSE_ERROR_MAGIC
@ OTA_RESPONSE_REQUEST_AUTH
const float AFTER_WIFI
For components that should be initialized after WiFi is connected.
std::unique_ptr< Socket > socket_ip_loop_monitored(int type, int protocol)
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().
Providing packet encoding functions for exchanging data with a remote host.
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.