21 static const char *
const TAG =
"esphome.ota";
22 static constexpr u_int16_t OTA_BLOCK_SIZE = 8192;
25 #ifdef USE_OTA_STATE_CALLBACK 31 ESP_LOGW(TAG,
"Could not create socket");
36 int err =
server_->setsockopt(SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(
int));
38 ESP_LOGW(TAG,
"Socket unable to set reuseaddr: errno %d", err);
41 err =
server_->setblocking(
false);
43 ESP_LOGW(TAG,
"Socket unable to set nonblocking mode: errno %d", err);
52 ESP_LOGW(TAG,
"Socket unable to set sockaddr: errno %d", errno);
59 ESP_LOGW(TAG,
"Socket unable to bind: errno %d", errno);
66 ESP_LOGW(TAG,
"Socket unable to listen: errno %d", errno);
73 ESP_LOGCONFIG(TAG,
"Over-The-Air updates:");
75 ESP_LOGCONFIG(TAG,
" Version: %d", USE_OTA_VERSION);
76 #ifdef USE_OTA_PASSWORD 78 ESP_LOGCONFIG(TAG,
" Password configured");
85 static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
89 bool update_started =
false;
91 uint32_t last_progress = 0;
93 char *sbuf =
reinterpret_cast<char *
>(buf);
96 std::unique_ptr<ota::OTABackend> backend;
98 #if USE_OTA_VERSION == 2 99 size_t size_acknowledged = 0;
104 socklen_t addr_len =
sizeof(source_addr);
111 int err =
client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
113 ESP_LOGW(TAG,
"Socket could not enable TCP nodelay, errno %d", errno);
117 ESP_LOGD(TAG,
"Starting update from %s...", this->
client_->getpeername().c_str());
119 #ifdef USE_OTA_STATE_CALLBACK 124 ESP_LOGW(TAG,
"Reading magic bytes failed");
128 if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
129 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],
137 buf[1] = USE_OTA_VERSION;
144 ESP_LOGW(TAG,
"Reading features failed");
147 ota_features = buf[0];
148 ESP_LOGV(TAG,
"Features: 0x%02X", ota_features);
152 if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
158 #ifdef USE_OTA_PASSWORD 168 ESP_LOGV(TAG,
"Auth: Nonce is %s", sbuf);
171 if (!this->
writeall_(reinterpret_cast<uint8_t *>(sbuf), 32)) {
172 ESP_LOGW(TAG,
"Auth: Writing nonce failed");
184 ESP_LOGW(TAG,
"Auth: Reading cnonce failed");
188 ESP_LOGV(TAG,
"Auth: CNonce is %s", sbuf);
195 ESP_LOGV(TAG,
"Auth: Result is %s", sbuf);
198 if (!this->
readall_(buf + 64, 32)) {
199 ESP_LOGW(TAG,
"Auth: Reading response failed");
202 sbuf[64 + 32] =
'\0';
203 ESP_LOGV(TAG,
"Auth: Response is %s", sbuf + 64);
206 for (uint8_t i = 0; i < 32; i++)
207 matches = matches && buf[i] == buf[64 + i];
210 ESP_LOGW(TAG,
"Auth failed! Passwords do not match");
215 #endif // USE_OTA_PASSWORD 223 ESP_LOGW(TAG,
"Reading size failed");
227 for (uint8_t i = 0; i < 4; i++) {
231 ESP_LOGV(TAG,
"Size is %u bytes", ota_size);
233 error_code = backend->begin(ota_size);
236 update_started =
true;
244 ESP_LOGW(TAG,
"Reading binary MD5 checksum failed");
248 ESP_LOGV(TAG,
"Update: Binary MD5 is %s", sbuf);
249 backend->set_update_md5(sbuf);
255 while (total < ota_size) {
257 size_t requested = std::min(
sizeof(buf), ota_size - total);
258 ssize_t read = this->
client_->read(buf, requested);
260 if (errno == EAGAIN || errno == EWOULDBLOCK) {
265 ESP_LOGW(TAG,
"Error receiving data for update, errno %d", errno);
267 }
else if (read == 0) {
271 ESP_LOGW(TAG,
"Remote end closed connection");
275 error_code = backend->write(buf, read);
277 ESP_LOGW(TAG,
"Error writing binary data to flash!, error_code: %d", error_code);
281 #if USE_OTA_VERSION == 2 282 while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
285 size_acknowledged += OTA_BLOCK_SIZE;
290 if (now - last_progress > 1000) {
292 float percentage = (total * 100.0f) / ota_size;
293 ESP_LOGD(TAG,
"Progress: %0.1f%%", percentage);
294 #ifdef USE_OTA_STATE_CALLBACK 307 error_code = backend->end();
309 ESP_LOGW(TAG,
"Error ending update! error_code: %d", error_code);
319 ESP_LOGW(TAG,
"Reading back acknowledgement failed");
326 ESP_LOGI(TAG,
"Update complete");
328 #ifdef USE_OTA_STATE_CALLBACK 335 buf[0] =
static_cast<uint8_t
>(error_code);
340 if (backend !=
nullptr && update_started) {
345 #ifdef USE_OTA_STATE_CALLBACK 351 uint32_t start =
millis();
353 while (len - at > 0) {
355 if (now - start > 1000) {
356 ESP_LOGW(TAG,
"Timed out reading %d bytes of data", len);
360 ssize_t read = this->
client_->read(buf + at, len - at);
362 if (errno == EAGAIN || errno == EWOULDBLOCK) {
367 ESP_LOGW(TAG,
"Failed to read %d bytes of data, errno %d", len, errno);
369 }
else if (read == 0) {
370 ESP_LOGW(TAG,
"Remote closed connection");
382 uint32_t start =
millis();
384 while (len - at > 0) {
386 if (now - start > 1000) {
387 ESP_LOGW(TAG,
"Timed out writing %d bytes of data", len);
391 ssize_t written = this->
client_->write(buf + at, len - at);
393 if (errno == EAGAIN || errno == EWOULDBLOCK) {
398 ESP_LOGW(TAG,
"Failed to write %d bytes of data, errno %d", len, errno);
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...
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")
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
std::unique_ptr< socket::Socket > client_
void register_ota_platform(OTAComponent *ota_caller)
void dump_config() override
uint32_t IRAM_ATTR HOT millis()
void status_momentary_error(const std::string &name, uint32_t length=5000)
CallbackManager< void(ota::OTAState, float, uint8_t)> state_callback_
void status_clear_warning()
Application App
Global storage of Application pointer - only one Application can exist.
std::unique_ptr< ota::OTABackend > make_ota_backend()
uint16_t get_port() const
bool writeall_(const uint8_t *buf, size_t len)
void IRAM_ATTR HOT yield()
float get_setup_priority() const override
std::unique_ptr< socket::Socket > server_
virtual void mark_failed()
Mark this component as failed.
Implementation of SPI Controller mode.
void set_port(uint16_t port)
Manually set the port OTA should listen on.
bool readall_(uint8_t *buf, size_t len)
void IRAM_ATTR HOT delay(uint32_t ms)