mirror of
https://github.com/esphome/esphome.git
synced 2024-11-10 01:07:45 +01:00
[nextion] Use persistent http connection for TFT upload (ESP-IDF) (#6576)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
5ddad26476
commit
a4a23d73b3
5 changed files with 225 additions and 213 deletions
|
@ -242,7 +242,7 @@ esphome/components/mpl3115a2/* @kbickar
|
||||||
esphome/components/mpu6886/* @fabaff
|
esphome/components/mpu6886/* @fabaff
|
||||||
esphome/components/ms8607/* @e28eta
|
esphome/components/ms8607/* @e28eta
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/nextion/* @senexcrenshaw
|
esphome/components/nextion/* @edwardtfn @senexcrenshaw
|
||||||
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
||||||
esphome/components/nextion/sensor/* @senexcrenshaw
|
esphome/components/nextion/sensor/* @senexcrenshaw
|
||||||
esphome/components/nextion/switch/* @senexcrenshaw
|
esphome/components/nextion/switch/* @senexcrenshaw
|
||||||
|
|
|
@ -25,7 +25,7 @@ from .base_component import (
|
||||||
CONF_EXIT_REPARSE_ON_START,
|
CONF_EXIT_REPARSE_ON_START,
|
||||||
)
|
)
|
||||||
|
|
||||||
CODEOWNERS = ["@senexcrenshaw"]
|
CODEOWNERS = ["@senexcrenshaw", "@edwardtfn"]
|
||||||
|
|
||||||
DEPENDENCIES = ["uart"]
|
DEPENDENCIES = ["uart"]
|
||||||
AUTO_LOAD = ["binary_sensor", "switch", "sensor", "text_sensor"]
|
AUTO_LOAD = ["binary_sensor", "switch", "sensor", "text_sensor"]
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
*/
|
*/
|
||||||
bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true);
|
bool upload_tft(uint32_t baud_rate = 0, bool exit_reparse = true);
|
||||||
|
|
||||||
#endif
|
#endif // USE_NEXTION_TFT_UPLOAD
|
||||||
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
|
@ -1142,6 +1142,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
* Sends commands ignoring of the Nextion has been setup.
|
* Sends commands ignoring of the Nextion has been setup.
|
||||||
*/
|
*/
|
||||||
bool ignore_is_setup_ = false;
|
bool ignore_is_setup_ = false;
|
||||||
|
|
||||||
bool nextion_reports_is_setup_ = false;
|
bool nextion_reports_is_setup_ = false;
|
||||||
uint8_t nextion_event_;
|
uint8_t nextion_event_;
|
||||||
|
|
||||||
|
@ -1182,7 +1183,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
WiFiClient *wifi_client_{nullptr};
|
WiFiClient *wifi_client_{nullptr};
|
||||||
BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr};
|
BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr};
|
||||||
WiFiClient *get_wifi_client_();
|
WiFiClient *get_wifi_client_();
|
||||||
#endif
|
#endif // USE_ESP8266
|
||||||
std::string tft_url_;
|
std::string tft_url_;
|
||||||
uint32_t content_length_ = 0;
|
uint32_t content_length_ = 0;
|
||||||
int tft_size_ = 0;
|
int tft_size_ = 0;
|
||||||
|
@ -1193,11 +1194,21 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
/**
|
/**
|
||||||
* will request chunk_size chunks from the web server
|
* will request chunk_size chunks from the web server
|
||||||
* and send each to the nextion
|
* and send each to the nextion
|
||||||
* @param HTTPClient http HTTP client handler.
|
* @param HTTPClient http_client HTTP client handler.
|
||||||
* @param int range_start Position of next byte to transfer.
|
* @param int range_start Position of next byte to transfer.
|
||||||
* @return position of last byte transferred, -1 for failure.
|
* @return position of last byte transferred, -1 for failure.
|
||||||
*/
|
*/
|
||||||
int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start);
|
int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start);
|
||||||
|
#elif defined(USE_ESP_IDF)
|
||||||
|
/**
|
||||||
|
* will request 4096 bytes chunks from the web server
|
||||||
|
* and send each to Nextion
|
||||||
|
* @param esp_http_client_handle_t http_client HTTP client handler.
|
||||||
|
* @param int range_start Position of next byte to transfer.
|
||||||
|
* @return position of last byte transferred, -1 for failure.
|
||||||
|
*/
|
||||||
|
int upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start);
|
||||||
|
#endif // ARDUINO vs USE_ESP_IDF
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends the upload process, restart Nextion and, if successful,
|
* Ends the upload process, restart Nextion and, if successful,
|
||||||
|
@ -1207,24 +1218,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
*/
|
*/
|
||||||
bool upload_end_(bool successful);
|
bool upload_end_(bool successful);
|
||||||
|
|
||||||
#elif defined(USE_ESP_IDF)
|
|
||||||
/**
|
|
||||||
* will request 4096 bytes chunks from the web server
|
|
||||||
* and send each to Nextion
|
|
||||||
* @param std::string url Full url for download.
|
|
||||||
* @param int range_start Position of next byte to transfer.
|
|
||||||
* @return position of last byte transferred, -1 for failure.
|
|
||||||
*/
|
|
||||||
int upload_range(const std::string &url, int range_start);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends the upload process, restart Nextion and, if successful,
|
|
||||||
* restarts ESP
|
|
||||||
* @param bool url successful True: Transfer completed successfuly, False: Transfer failed.
|
|
||||||
* @return bool True: Transfer completed successfuly, False: Transfer failed.
|
|
||||||
*/
|
|
||||||
bool upload_end(bool successful);
|
|
||||||
#endif // ARDUINO vs USE_ESP_IDF
|
|
||||||
/**
|
/**
|
||||||
* Returns the ESP Free Heap memory. This is framework independent.
|
* Returns the ESP Free Heap memory. This is framework independent.
|
||||||
* @return Free Heap in bytes.
|
* @return Free Heap in bytes.
|
||||||
|
@ -1260,7 +1253,7 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||||
|
|
||||||
#ifdef NEXTION_PROTOCOL_LOG
|
#ifdef NEXTION_PROTOCOL_LOG
|
||||||
void print_queue_members_();
|
void print_queue_members_();
|
||||||
#endif
|
#endif // NEXTION_PROTOCOL_LOG
|
||||||
void reset_(bool reset_nextion = true);
|
void reset_(bool reset_nextion = true);
|
||||||
|
|
||||||
std::string command_data_;
|
std::string command_data_;
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
#include "nextion.h"
|
#include "nextion.h"
|
||||||
|
|
||||||
#ifdef USE_ESP_IDF
|
|
||||||
#ifdef USE_NEXTION_TFT_UPLOAD
|
#ifdef USE_NEXTION_TFT_UPLOAD
|
||||||
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/components/network/util.h"
|
#include "esphome/components/network/util.h"
|
||||||
|
#include <cinttypes>
|
||||||
#include <esp_heap_caps.h>
|
#include <esp_heap_caps.h>
|
||||||
#include <esp_http_client.h>
|
#include <esp_http_client.h>
|
||||||
#include <cinttypes>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace nextion {
|
namespace nextion {
|
||||||
|
@ -20,153 +19,147 @@ static const char *const TAG = "nextion.upload.idf";
|
||||||
// Followed guide
|
// Followed guide
|
||||||
// https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
|
// https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
|
||||||
|
|
||||||
int Nextion::upload_range(const std::string &url, int range_start) {
|
int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &range_start) {
|
||||||
ESP_LOGVV(TAG, "url: %s", url.c_str());
|
uint32_t range_size = this->tft_size_ - range_start;
|
||||||
uint range_size = this->tft_size_ - range_start;
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
ESP_LOGVV(TAG, "tft_size_: %i", this->tft_size_);
|
uint32_t range_end = ((upload_first_chunk_sent_ or this->tft_size_ < 4096) ? this->tft_size_ : 4096) - 1;
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGD(TAG, "Range start: %" PRIu32, range_start);
|
||||||
int range_end = (range_start == 0) ? std::min(this->tft_size_, 16383) : this->tft_size_;
|
|
||||||
if (range_size <= 0 or range_end <= range_start) {
|
if (range_size <= 0 or range_end <= range_start) {
|
||||||
|
ESP_LOGD(TAG, "Range end: %" PRIu32, range_end);
|
||||||
|
ESP_LOGD(TAG, "Range size: %" PRIu32, range_size);
|
||||||
ESP_LOGE(TAG, "Invalid range");
|
ESP_LOGE(TAG, "Invalid range");
|
||||||
ESP_LOGD(TAG, "Range start: %i", range_start);
|
|
||||||
ESP_LOGD(TAG, "Range end: %i", range_end);
|
|
||||||
ESP_LOGD(TAG, "Range size: %i", range_size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_http_client_config_t config = {
|
char range_header[32];
|
||||||
.url = url.c_str(),
|
sprintf(range_header, "bytes=%" PRIu32 "-%" PRIu32, range_start, range_end);
|
||||||
.cert_pem = nullptr,
|
|
||||||
.disable_auto_redirect = false,
|
|
||||||
.max_redirection_count = 10,
|
|
||||||
};
|
|
||||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
|
||||||
|
|
||||||
char range_header[64];
|
|
||||||
sprintf(range_header, "bytes=%d-%d", range_start, range_end);
|
|
||||||
ESP_LOGV(TAG, "Requesting range: %s", range_header);
|
ESP_LOGV(TAG, "Requesting range: %s", range_header);
|
||||||
esp_http_client_set_header(client, "Range", range_header);
|
esp_http_client_set_header(http_client, "Range", range_header);
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGV(TAG, "Opening HTTP connetion");
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Opening http connetion");
|
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
if ((err = esp_http_client_open(client, 0)) != ESP_OK) {
|
if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
||||||
esp_http_client_cleanup(client);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Fetch content length");
|
ESP_LOGV(TAG, "Fetch content length");
|
||||||
int content_length = esp_http_client_fetch_headers(client);
|
const int chunk_size = esp_http_client_fetch_headers(http_client);
|
||||||
ESP_LOGV(TAG, "content_length = %d", content_length);
|
ESP_LOGV(TAG, "content_length = %d", chunk_size);
|
||||||
if (content_length <= 0) {
|
if (chunk_size <= 0) {
|
||||||
ESP_LOGE(TAG, "Failed to get content length: %d", content_length);
|
ESP_LOGE(TAG, "Failed to get chunk's content length: %d", chunk_size);
|
||||||
esp_http_client_cleanup(client);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_read_len = 0, read_len;
|
// Allocate the buffer dynamically
|
||||||
|
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
uint8_t *buffer = allocator.allocate(4096);
|
||||||
ESP_LOGV(TAG, "Allocate buffer");
|
if (!buffer) {
|
||||||
uint8_t *buffer = new uint8_t[4096];
|
ESP_LOGE(TAG, "Failed to allocate upload buffer");
|
||||||
std::string recv_string;
|
return -1;
|
||||||
if (buffer == nullptr) {
|
|
||||||
ESP_LOGE(TAG, "Failed to allocate memory for buffer");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
} else {
|
|
||||||
ESP_LOGV(TAG, "Memory for buffer allocated successfully");
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
App.feed_wdt();
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
int read_len = esp_http_client_read(client, reinterpret_cast<char *>(buffer), 4096);
|
|
||||||
ESP_LOGVV(TAG, "Read %d bytes from HTTP client, writing to UART", read_len);
|
|
||||||
if (read_len > 0) {
|
|
||||||
this->write_array(buffer, read_len);
|
|
||||||
ESP_LOGVV(TAG, "Write to UART successful");
|
|
||||||
this->recv_ret_string_(recv_string, 5000, true);
|
|
||||||
this->content_length_ -= read_len;
|
|
||||||
ESP_LOGD(TAG, "Uploaded %0.2f %%, remaining %d bytes, heap is %" PRIu32 " bytes",
|
|
||||||
100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_,
|
|
||||||
esp_get_free_heap_size());
|
|
||||||
|
|
||||||
if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request
|
|
||||||
ESP_LOGD(
|
|
||||||
TAG, "recv_string [%s]",
|
|
||||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
|
||||||
uint32_t result = 0;
|
|
||||||
for (int j = 0; j < 4; ++j) {
|
|
||||||
result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
|
|
||||||
}
|
|
||||||
if (result > 0) {
|
|
||||||
ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result);
|
|
||||||
this->content_length_ = this->tft_size_ - result;
|
|
||||||
// Deallocate the buffer when done
|
|
||||||
ESP_LOGV(TAG, "Deallocate buffer");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
delete[] buffer;
|
|
||||||
ESP_LOGVV(TAG, "Memory for buffer deallocated");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
ESP_LOGV(TAG, "Close http client");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
esp_http_client_close(client);
|
|
||||||
esp_http_client_cleanup(client);
|
|
||||||
ESP_LOGVV(TAG, "Client closed");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else if (recv_string[0] != 0x05) { // 0x05 == "ok"
|
|
||||||
ESP_LOGE(
|
|
||||||
TAG, "Invalid response from Nextion: [%s]",
|
|
||||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
|
||||||
ESP_LOGV(TAG, "Deallocate buffer");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
delete[] buffer;
|
|
||||||
ESP_LOGVV(TAG, "Memory for buffer deallocated");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
ESP_LOGV(TAG, "Close http client");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
esp_http_client_close(client);
|
|
||||||
esp_http_client_cleanup(client);
|
|
||||||
ESP_LOGVV(TAG, "Client closed");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
recv_string.clear();
|
|
||||||
} else if (read_len == 0) {
|
|
||||||
ESP_LOGV(TAG, "End of HTTP response reached");
|
|
||||||
break; // Exit the loop if there is no more data to read
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %d", read_len);
|
|
||||||
break; // Exit the loop on error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deallocate the buffer when done
|
|
||||||
ESP_LOGV(TAG, "Deallocate buffer");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
delete[] buffer;
|
|
||||||
ESP_LOGVV(TAG, "Memory for buffer deallocated");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
}
|
}
|
||||||
ESP_LOGV(TAG, "Close http client");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
std::string recv_string;
|
||||||
esp_http_client_close(client);
|
while (true) {
|
||||||
esp_http_client_cleanup(client);
|
App.feed_wdt();
|
||||||
ESP_LOGVV(TAG, "Client closed");
|
const uint16_t buffer_size =
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
this->content_length_ < 4096 ? this->content_length_ : 4096; // Limits buffer to the remaining data
|
||||||
|
ESP_LOGV(TAG, "Fetching %" PRIu16 " bytes from HTTP", buffer_size);
|
||||||
|
uint16_t read_len = 0;
|
||||||
|
int partial_read_len = 0;
|
||||||
|
uint8_t retries = 0;
|
||||||
|
// Attempt to read the chunk with retries.
|
||||||
|
while (retries < 5 && read_len < buffer_size) {
|
||||||
|
partial_read_len =
|
||||||
|
esp_http_client_read(http_client, reinterpret_cast<char *>(buffer) + read_len, buffer_size - read_len);
|
||||||
|
if (partial_read_len > 0) {
|
||||||
|
read_len += partial_read_len; // Accumulate the total read length.
|
||||||
|
// Reset retries on successful read.
|
||||||
|
retries = 0;
|
||||||
|
} else {
|
||||||
|
// If no data was read, increment retries.
|
||||||
|
retries++;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2)); // NOLINT
|
||||||
|
}
|
||||||
|
App.feed_wdt(); // Feed the watchdog timer.
|
||||||
|
}
|
||||||
|
if (read_len != buffer_size) {
|
||||||
|
// Did not receive the full package within the timeout period
|
||||||
|
ESP_LOGE(TAG, "Failed to read full package, received only %" PRIu16 " of %" PRIu16 " bytes", read_len,
|
||||||
|
buffer_size);
|
||||||
|
// Deallocate buffer
|
||||||
|
allocator.deallocate(buffer, 4096);
|
||||||
|
buffer = nullptr;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "%d bytes fetched, writing it to UART", read_len);
|
||||||
|
if (read_len > 0) {
|
||||||
|
recv_string.clear();
|
||||||
|
this->write_array(buffer, buffer_size);
|
||||||
|
App.feed_wdt();
|
||||||
|
this->recv_ret_string_(recv_string, upload_first_chunk_sent_ ? 500 : 5000, true);
|
||||||
|
this->content_length_ -= read_len;
|
||||||
|
const float upload_percentage = 100.0f * (this->tft_size_ - this->content_length_) / this->tft_size_;
|
||||||
|
#ifdef USE_PSRAM
|
||||||
|
ESP_LOGD(
|
||||||
|
TAG,
|
||||||
|
"Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " (DRAM) + %" PRIu32 " (PSRAM) bytes",
|
||||||
|
upload_percentage, this->content_length_, static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)),
|
||||||
|
static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)));
|
||||||
|
#else
|
||||||
|
ESP_LOGD(TAG, "Uploaded %0.2f%%, remaining %" PRIu32 " bytes, free heap: %" PRIu32 " bytes", upload_percentage,
|
||||||
|
this->content_length_, static_cast<uint32_t>(esp_get_free_heap_size()));
|
||||||
|
#endif
|
||||||
|
upload_first_chunk_sent_ = true;
|
||||||
|
if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request
|
||||||
|
ESP_LOGD(TAG, "recv_string [%s]",
|
||||||
|
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||||
|
uint32_t result = 0;
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
|
||||||
|
}
|
||||||
|
if (result > 0) {
|
||||||
|
ESP_LOGI(TAG, "Nextion reported new range %" PRIu32, result);
|
||||||
|
this->content_length_ = this->tft_size_ - result;
|
||||||
|
range_start = result;
|
||||||
|
} else {
|
||||||
|
range_start = range_end + 1;
|
||||||
|
}
|
||||||
|
// Deallocate buffer
|
||||||
|
allocator.deallocate(buffer, 4096);
|
||||||
|
buffer = nullptr;
|
||||||
|
return range_end + 1;
|
||||||
|
} else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok"
|
||||||
|
ESP_LOGE(TAG, "Invalid response from Nextion: [%s]",
|
||||||
|
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||||
|
// Deallocate buffer
|
||||||
|
allocator.deallocate(buffer, 4096);
|
||||||
|
buffer = nullptr;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_string.clear();
|
||||||
|
} else if (read_len == 0) {
|
||||||
|
ESP_LOGV(TAG, "End of HTTP response reached");
|
||||||
|
break; // Exit the loop if there is no more data to read
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Failed to read from HTTP client, error code: %" PRIu16, read_len);
|
||||||
|
break; // Exit the loop on error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range_start = range_end + 1;
|
||||||
|
// Deallocate buffer
|
||||||
|
allocator.deallocate(buffer, 4096);
|
||||||
|
buffer = nullptr;
|
||||||
return range_end + 1;
|
return range_end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||||
ESP_LOGD(TAG, "Nextion TFT upload requested");
|
ESP_LOGD(TAG, "Nextion TFT upload requested");
|
||||||
ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse));
|
ESP_LOGD(TAG, "Exit reparse: %s", YESNO(exit_reparse));
|
||||||
ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str());
|
ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str());
|
||||||
|
|
||||||
if (this->is_updating_) {
|
if (this->is_updating_) {
|
||||||
ESP_LOGW(TAG, "Currently updating");
|
ESP_LOGW(TAG, "Currently uploading");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +188,8 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||||
ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate);
|
ESP_LOGD(TAG, "Baud rate: %" PRIu32, baud_rate);
|
||||||
|
|
||||||
// Define the configuration for the HTTP client
|
// Define the configuration for the HTTP client
|
||||||
ESP_LOGV(TAG, "Establishing connection to HTTP server");
|
ESP_LOGV(TAG, "Initializing HTTP client");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
esp_http_client_config_t config = {
|
esp_http_client_config_t config = {
|
||||||
.url = this->tft_url_.c_str(),
|
.url = this->tft_url_.c_str(),
|
||||||
.cert_pem = nullptr,
|
.cert_pem = nullptr,
|
||||||
|
@ -205,58 +198,62 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||||
.disable_auto_redirect = false,
|
.disable_auto_redirect = false,
|
||||||
.max_redirection_count = 10,
|
.max_redirection_count = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize the HTTP client with the configuration
|
// Initialize the HTTP client with the configuration
|
||||||
ESP_LOGV(TAG, "Initializing HTTP client");
|
esp_http_client_handle_t http_client = esp_http_client_init(&config);
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
if (!http_client) {
|
||||||
esp_http_client_handle_t http = esp_http_client_init(&config);
|
|
||||||
if (!http) {
|
|
||||||
ESP_LOGE(TAG, "Failed to initialize HTTP client.");
|
ESP_LOGE(TAG, "Failed to initialize HTTP client.");
|
||||||
return this->upload_end(false);
|
return this->upload_end_(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = esp_http_client_set_header(http_client, "Connection", "keep-alive");
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "HTTP set header failed: %s", esp_err_to_name(err));
|
||||||
|
esp_http_client_cleanup(http_client);
|
||||||
|
return this->upload_end_(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the HTTP request
|
// Perform the HTTP request
|
||||||
ESP_LOGV(TAG, "Check if the client could connect");
|
ESP_LOGV(TAG, "Check if the client could connect");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
esp_err_t err = esp_http_client_perform(http);
|
err = esp_http_client_perform(http_client);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err));
|
||||||
esp_http_client_cleanup(http);
|
esp_http_client_cleanup(http_client);
|
||||||
return this->upload_end(false);
|
return this->upload_end_(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the HTTP Status Code
|
// Check the HTTP Status Code
|
||||||
ESP_LOGV(TAG, "Check the HTTP Status Code");
|
ESP_LOGV(TAG, "Check the HTTP Status Code");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
int status_code = esp_http_client_get_status_code(http);
|
int status_code = esp_http_client_get_status_code(http_client);
|
||||||
ESP_LOGV(TAG, "HTTP Status Code: %d", status_code);
|
if (status_code != 200 && status_code != 206) {
|
||||||
size_t tft_file_size = esp_http_client_get_content_length(http);
|
return this->upload_end_(false);
|
||||||
ESP_LOGD(TAG, "TFT file size: %zu", tft_file_size);
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Close HTTP connection");
|
this->tft_size_ = esp_http_client_get_content_length(http_client);
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
esp_http_client_close(http);
|
|
||||||
esp_http_client_cleanup(http);
|
|
||||||
ESP_LOGVV(TAG, "Connection closed");
|
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
|
|
||||||
if (tft_file_size < 4096) {
|
ESP_LOGD(TAG, "TFT file size: %zu bytes", this->tft_size_);
|
||||||
ESP_LOGE(TAG, "File size check failed. Size: %zu", tft_file_size);
|
if (this->tft_size_ < 4096 || this->tft_size_ > 134217728) {
|
||||||
return this->upload_end(false);
|
ESP_LOGE(TAG, "File size check failed.");
|
||||||
|
ESP_LOGD(TAG, "Close HTTP connection");
|
||||||
|
esp_http_client_close(http_client);
|
||||||
|
esp_http_client_cleanup(http_client);
|
||||||
|
ESP_LOGV(TAG, "Connection closed");
|
||||||
|
return this->upload_end_(false);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(TAG, "File size check passed. Proceeding...");
|
ESP_LOGV(TAG, "File size check passed. Proceeding...");
|
||||||
}
|
}
|
||||||
this->content_length_ = tft_file_size;
|
this->content_length_ = this->tft_size_;
|
||||||
this->tft_size_ = tft_file_size;
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Updating Nextion");
|
ESP_LOGD(TAG, "Uploading Nextion");
|
||||||
|
|
||||||
// The Nextion will ignore the update command if it is sleeping
|
// The Nextion will ignore the upload command if it is sleeping
|
||||||
ESP_LOGV(TAG, "Wake-up Nextion");
|
ESP_LOGV(TAG, "Wake-up Nextion");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
this->ignore_is_setup_ = true;
|
||||||
this->send_command_("sleep=0");
|
this->send_command_("sleep=0");
|
||||||
this->set_backlight_brightness(1.0);
|
this->send_command_("dim=100");
|
||||||
vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT
|
vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT
|
||||||
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
|
|
||||||
App.feed_wdt();
|
App.feed_wdt();
|
||||||
char command[128];
|
char command[128];
|
||||||
|
@ -267,14 +264,11 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||||
|
|
||||||
// Clear serial receive buffer
|
// Clear serial receive buffer
|
||||||
ESP_LOGV(TAG, "Clear serial receive buffer");
|
ESP_LOGV(TAG, "Clear serial receive buffer");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
this->reset_(false);
|
||||||
uint8_t d;
|
vTaskDelay(pdMS_TO_TICKS(250)); // NOLINT
|
||||||
while (this->available()) {
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
this->read_byte(&d);
|
|
||||||
};
|
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Send update instruction: %s", command);
|
ESP_LOGV(TAG, "Send upload instruction: %s", command);
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
this->send_command_(command);
|
this->send_command_(command);
|
||||||
|
|
||||||
if (baud_rate != this->original_baud_rate_) {
|
if (baud_rate != this->original_baud_rate_) {
|
||||||
|
@ -288,41 +282,66 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||||
this->recv_ret_string_(response, 5000, true); // This can take some time to return
|
this->recv_ret_string_(response, 5000, true); // This can take some time to return
|
||||||
|
|
||||||
// The Nextion display will, if it's ready to accept data, send a 0x05 byte.
|
// The Nextion display will, if it's ready to accept data, send a 0x05 byte.
|
||||||
ESP_LOGD(TAG, "Upgrade response is [%s] - %zu bytes",
|
ESP_LOGD(TAG, "Upgrade response is [%s] - %zu byte(s)",
|
||||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
|
format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
|
||||||
response.length());
|
response.length());
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
ESP_LOGV(TAG, "Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
|
|
||||||
if (response.find(0x05) != std::string::npos) {
|
if (response.find(0x05) != std::string::npos) {
|
||||||
ESP_LOGV(TAG, "Preparation for tft update done");
|
ESP_LOGV(TAG, "Preparation for TFT upload done");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str());
|
ESP_LOGE(TAG, "Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str());
|
||||||
return this->upload_end(false);
|
ESP_LOGD(TAG, "Close HTTP connection");
|
||||||
|
esp_http_client_close(http_client);
|
||||||
|
esp_http_client_cleanup(http_client);
|
||||||
|
ESP_LOGV(TAG, "Connection closed");
|
||||||
|
return this->upload_end_(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Updating tft from \"%s\" with a file size of %d, Heap Size %" PRIu32, this->tft_url_.c_str(),
|
ESP_LOGV(TAG, "Change the method to GET before starting the download");
|
||||||
content_length_, esp_get_free_heap_size());
|
esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET);
|
||||||
|
if (set_method_result != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to set HTTP method to GET: %s", esp_err_to_name(set_method_result));
|
||||||
|
return this->upload_end_(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Uploading TFT to Nextion:");
|
||||||
|
ESP_LOGD(TAG, " URL: %s", this->tft_url_.c_str());
|
||||||
|
ESP_LOGD(TAG, " File size: %" PRIu32 " bytes", this->content_length_);
|
||||||
|
ESP_LOGD(TAG, " Free heap: %" PRIu32, esp_get_free_heap_size());
|
||||||
|
|
||||||
|
// Proceed with the content download as before
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Starting transfer by chunks loop");
|
ESP_LOGV(TAG, "Starting transfer by chunks loop");
|
||||||
ESP_LOGVV(TAG, "Available heap: %" PRIu32, esp_get_free_heap_size());
|
|
||||||
int result = 0;
|
uint32_t position = 0;
|
||||||
while (content_length_ > 0) {
|
while (this->content_length_ > 0) {
|
||||||
result = upload_range(this->tft_url_.c_str(), result);
|
int upload_result = upload_by_chunks_(http_client, position);
|
||||||
if (result < 0) {
|
if (upload_result < 0) {
|
||||||
ESP_LOGE(TAG, "Error updating Nextion!");
|
ESP_LOGE(TAG, "Error uploading TFT to Nextion!");
|
||||||
return this->upload_end(false);
|
ESP_LOGD(TAG, "Close HTTP connection");
|
||||||
|
esp_http_client_close(http_client);
|
||||||
|
esp_http_client_cleanup(http_client);
|
||||||
|
ESP_LOGV(TAG, "Connection closed");
|
||||||
|
return this->upload_end_(false);
|
||||||
}
|
}
|
||||||
App.feed_wdt();
|
App.feed_wdt();
|
||||||
ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_);
|
ESP_LOGV(TAG, "Free heap: %" PRIu32 ", Bytes left: %" PRIu32, esp_get_free_heap_size(), this->content_length_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Successfully updated Nextion!");
|
ESP_LOGD(TAG, "Successfully uploaded TFT to Nextion!");
|
||||||
|
|
||||||
return upload_end(true);
|
ESP_LOGD(TAG, "Close HTTP connection");
|
||||||
|
esp_http_client_close(http_client);
|
||||||
|
esp_http_client_cleanup(http_client);
|
||||||
|
ESP_LOGV(TAG, "Connection closed");
|
||||||
|
return this->upload_end_(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Nextion::upload_end(bool successful) {
|
bool Nextion::upload_end_(bool successful) {
|
||||||
|
ESP_LOGD(TAG, "Nextion TFT upload finished: %s", YESNO(successful));
|
||||||
this->is_updating_ = false;
|
this->is_updating_ = false;
|
||||||
|
this->ignore_is_setup_ = false;
|
||||||
|
|
||||||
uint32_t baud_rate = this->parent_->get_baud_rate();
|
uint32_t baud_rate = this->parent_->get_baud_rate();
|
||||||
if (baud_rate != this->original_baud_rate_) {
|
if (baud_rate != this->original_baud_rate_) {
|
||||||
|
@ -331,12 +350,12 @@ bool Nextion::upload_end(bool successful) {
|
||||||
this->parent_->load_settings();
|
this->parent_->load_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Restarting Nextion");
|
|
||||||
this->soft_reset();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1500)); // NOLINT
|
|
||||||
if (successful) {
|
if (successful) {
|
||||||
ESP_LOGD(TAG, "Restarting ESPHome");
|
ESP_LOGD(TAG, "Restarting ESPHome");
|
||||||
esp_restart(); // NOLINT(readability-static-accessed-through-instance)
|
delay(1500); // NOLINT
|
||||||
|
arch_restart();
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Nextion TFT upload failed");
|
||||||
}
|
}
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
@ -344,5 +363,5 @@ bool Nextion::upload_end(bool successful) {
|
||||||
} // namespace nextion
|
} // namespace nextion
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_NEXTION_TFT_UPLOAD
|
|
||||||
#endif // USE_ESP_IDF
|
#endif // USE_ESP_IDF
|
||||||
|
#endif // USE_NEXTION_TFT_UPLOAD
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#define USE_MDNS
|
#define USE_MDNS
|
||||||
#define USE_MEDIA_PLAYER
|
#define USE_MEDIA_PLAYER
|
||||||
#define USE_MQTT
|
#define USE_MQTT
|
||||||
|
#define USE_NEXTION_TFT_UPLOAD
|
||||||
#define USE_NUMBER
|
#define USE_NUMBER
|
||||||
#define USE_DATETIME
|
#define USE_DATETIME
|
||||||
#define USE_DATETIME_DATE
|
#define USE_DATETIME_DATE
|
||||||
|
@ -64,7 +65,6 @@
|
||||||
// Arduino-specific feature flags
|
// Arduino-specific feature flags
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
#define USE_CAPTIVE_PORTAL
|
#define USE_CAPTIVE_PORTAL
|
||||||
#define USE_NEXTION_TFT_UPLOAD
|
|
||||||
#define USE_PROMETHEUS
|
#define USE_PROMETHEUS
|
||||||
#define USE_WEBSERVER
|
#define USE_WEBSERVER
|
||||||
#define USE_WEBSERVER_PORT 80 // NOLINT
|
#define USE_WEBSERVER_PORT 80 // NOLINT
|
||||||
|
|
Loading…
Reference in a new issue