3 #ifdef USE_NEXTION_TFT_UPLOAD 12 #include <esp_heap_caps.h> 13 #include <esp_http_client.h> 17 static const char *
const TAG =
"nextion.upload.idf";
23 uint32_t range_size = this->
tft_size_ - range_start;
24 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
26 ESP_LOGD(TAG,
"Range start: %" PRIu32, range_start);
27 if (range_size <= 0 or range_end <= range_start) {
28 ESP_LOGD(TAG,
"Range end: %" PRIu32, range_end);
29 ESP_LOGD(TAG,
"Range size: %" PRIu32, range_size);
30 ESP_LOGE(TAG,
"Invalid range");
34 char range_header[32];
35 sprintf(range_header,
"bytes=%" PRIu32
"-%" PRIu32, range_start, range_end);
36 ESP_LOGV(TAG,
"Requesting range: %s", range_header);
37 esp_http_client_set_header(http_client,
"Range", range_header);
38 ESP_LOGV(TAG,
"Opening HTTP connetion");
40 if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) {
41 ESP_LOGE(TAG,
"Failed to open HTTP connection: %s", esp_err_to_name(err));
45 ESP_LOGV(TAG,
"Fetch content length");
46 const int chunk_size = esp_http_client_fetch_headers(http_client);
47 ESP_LOGV(TAG,
"content_length = %d", chunk_size);
48 if (chunk_size <= 0) {
49 ESP_LOGE(TAG,
"Failed to get chunk's content length: %d", chunk_size);
55 uint8_t *buffer = allocator.
allocate(4096);
57 ESP_LOGE(TAG,
"Failed to allocate upload buffer");
61 std::string recv_string;
64 const uint16_t buffer_size =
66 ESP_LOGV(TAG,
"Fetching %" PRIu16
" bytes from HTTP", buffer_size);
67 uint16_t read_len = 0;
68 int partial_read_len = 0;
71 while (retries < 5 && read_len < buffer_size) {
73 esp_http_client_read(http_client, reinterpret_cast<char *>(buffer) + read_len, buffer_size - read_len);
74 if (partial_read_len > 0) {
75 read_len += partial_read_len;
81 vTaskDelay(pdMS_TO_TICKS(2));
85 if (read_len != buffer_size) {
87 ESP_LOGE(TAG,
"Failed to read full package, received only %" PRIu16
" of %" PRIu16
" bytes", read_len,
94 ESP_LOGV(TAG,
"%d bytes fetched, writing it to UART", read_len);
105 "Uploaded %0.2f%%, remaining %" PRIu32
" bytes, free heap: %" PRIu32
" (DRAM) + %" PRIu32
" (PSRAM) bytes",
106 upload_percentage, this->
content_length_, static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_INTERNAL)),
107 static_cast<uint32_t>(heap_caps_get_free_size(MALLOC_CAP_SPIRAM)));
109 ESP_LOGD(TAG,
"Uploaded %0.2f%%, remaining %" PRIu32
" bytes, free heap: %" PRIu32
" bytes", upload_percentage,
110 this->
content_length_, static_cast<uint32_t>(esp_get_free_heap_size()));
113 if (recv_string[0] == 0x08 && recv_string.size() == 5) {
114 ESP_LOGD(TAG,
"recv_string [%s]",
115 format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
117 for (
int j = 0; j < 4; ++j) {
118 result +=
static_cast<uint8_t
>(recv_string[j + 1]) << (8 * j);
121 ESP_LOGI(TAG,
"Nextion reported new range %" PRIu32, result);
123 range_start = result;
125 range_start = range_end + 1;
130 return range_end + 1;
131 }
else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) {
132 ESP_LOGE(TAG,
"Invalid response from Nextion: [%s]",
133 format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
141 }
else if (read_len == 0) {
142 ESP_LOGV(TAG,
"End of HTTP response reached");
145 ESP_LOGE(TAG,
"Failed to read from HTTP client, error code: %" PRIu16, read_len);
149 range_start = range_end + 1;
153 return range_end + 1;
157 ESP_LOGD(TAG,
"Nextion TFT upload requested");
158 ESP_LOGD(TAG,
"Exit reparse: %s", YESNO(exit_reparse));
159 ESP_LOGD(TAG,
"URL: %s", this->
tft_url_.c_str());
162 ESP_LOGW(TAG,
"Currently uploading");
167 ESP_LOGE(TAG,
"Network is not connected");
174 ESP_LOGD(TAG,
"Exiting Nextion reparse mode");
176 ESP_LOGW(TAG,
"Failed to request Nextion to exit reparse mode");
183 static const std::vector<uint32_t> SUPPORTED_BAUD_RATES = {2400, 4800, 9600, 19200, 31250, 38400, 57600,
184 115200, 230400, 250000, 256000, 512000, 921600};
185 if (std::find(SUPPORTED_BAUD_RATES.begin(), SUPPORTED_BAUD_RATES.end(), baud_rate) == SUPPORTED_BAUD_RATES.end()) {
188 ESP_LOGD(TAG,
"Baud rate: %" PRIu32, baud_rate);
191 ESP_LOGV(TAG,
"Initializing HTTP client");
192 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
193 esp_http_client_config_t config = {
196 .method = HTTP_METHOD_HEAD,
198 .disable_auto_redirect =
false,
199 .max_redirection_count = 10,
202 esp_http_client_handle_t http_client = esp_http_client_init(&config);
204 ESP_LOGE(TAG,
"Failed to initialize HTTP client.");
208 esp_err_t err = esp_http_client_set_header(http_client,
"Connection",
"keep-alive");
210 ESP_LOGE(TAG,
"HTTP set header failed: %s", esp_err_to_name(err));
211 esp_http_client_cleanup(http_client);
216 ESP_LOGV(TAG,
"Check if the client could connect");
217 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
218 err = esp_http_client_perform(http_client);
220 ESP_LOGE(TAG,
"HTTP request failed: %s", esp_err_to_name(err));
221 esp_http_client_cleanup(http_client);
226 ESP_LOGV(TAG,
"Check the HTTP Status Code");
227 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
228 int status_code = esp_http_client_get_status_code(http_client);
229 if (status_code != 200 && status_code != 206) {
233 this->
tft_size_ = esp_http_client_get_content_length(http_client);
235 ESP_LOGD(TAG,
"TFT file size: %zu bytes", this->
tft_size_);
236 if (this->tft_size_ < 4096 || this->
tft_size_ > 134217728) {
237 ESP_LOGE(TAG,
"File size check failed.");
238 ESP_LOGD(TAG,
"Close HTTP connection");
239 esp_http_client_close(http_client);
240 esp_http_client_cleanup(http_client);
241 ESP_LOGV(TAG,
"Connection closed");
244 ESP_LOGV(TAG,
"File size check passed. Proceeding...");
248 ESP_LOGD(TAG,
"Uploading Nextion");
251 ESP_LOGV(TAG,
"Wake-up Nextion");
255 vTaskDelay(pdMS_TO_TICKS(250));
256 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
263 sprintf(command,
"whmi-wris %" PRIu32
",%" PRIu32
",1", this->
content_length_, baud_rate);
266 ESP_LOGV(TAG,
"Clear serial receive buffer");
268 vTaskDelay(pdMS_TO_TICKS(250));
269 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
271 ESP_LOGV(TAG,
"Send upload instruction: %s", command);
275 ESP_LOGD(TAG,
"Changing baud rate from %" PRIu32
" to %" PRIu32
" bps", this->
original_baud_rate_, baud_rate);
280 std::string response;
281 ESP_LOGV(TAG,
"Waiting for upgrade response");
285 ESP_LOGD(TAG,
"Upgrade response is [%s] - %zu byte(s)",
286 format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
288 ESP_LOGV(TAG,
"Free heap: %" PRIu32, esp_get_free_heap_size());
290 if (response.find(0x05) != std::string::npos) {
291 ESP_LOGV(TAG,
"Preparation for TFT upload done");
293 ESP_LOGE(TAG,
"Preparation for TFT upload failed %d \"%s\"", response[0], response.c_str());
294 ESP_LOGD(TAG,
"Close HTTP connection");
295 esp_http_client_close(http_client);
296 esp_http_client_cleanup(http_client);
297 ESP_LOGV(TAG,
"Connection closed");
301 ESP_LOGV(TAG,
"Change the method to GET before starting the download");
302 esp_err_t set_method_result = esp_http_client_set_method(http_client, HTTP_METHOD_GET);
303 if (set_method_result != ESP_OK) {
304 ESP_LOGE(TAG,
"Failed to set HTTP method to GET: %s", esp_err_to_name(set_method_result));
308 ESP_LOGD(TAG,
"Uploading TFT to Nextion:");
309 ESP_LOGD(TAG,
" URL: %s", this->
tft_url_.c_str());
311 ESP_LOGD(TAG,
" Free heap: %" PRIu32, esp_get_free_heap_size());
315 ESP_LOGV(TAG,
"Starting transfer by chunks loop");
320 if (upload_result < 0) {
321 ESP_LOGE(TAG,
"Error uploading TFT to Nextion!");
322 ESP_LOGD(TAG,
"Close HTTP connection");
323 esp_http_client_close(http_client);
324 esp_http_client_cleanup(http_client);
325 ESP_LOGV(TAG,
"Connection closed");
329 ESP_LOGV(TAG,
"Free heap: %" PRIu32
", Bytes left: %" PRIu32, esp_get_free_heap_size(), this->
content_length_);
332 ESP_LOGD(TAG,
"Successfully uploaded TFT to Nextion!");
334 ESP_LOGD(TAG,
"Close HTTP connection");
335 esp_http_client_close(http_client);
336 esp_http_client_cleanup(http_client);
337 ESP_LOGV(TAG,
"Connection closed");
342 ESP_LOGD(TAG,
"Nextion TFT upload finished: %s", YESNO(successful));
348 ESP_LOGD(TAG,
"Changing baud rate back from %" PRIu32
" to %" PRIu32
" bps", baud_rate, this->
original_baud_rate_);
354 ESP_LOGD(TAG,
"Restarting ESPHome");
358 ESP_LOGE(TAG,
"Nextion TFT upload failed");
366 #endif // USE_ESP_IDF 367 #endif // USE_NEXTION_TFT_UPLOAD bool ignore_is_setup_
Sends commands ignoring of the Nextion has been setup.
uint32_t get_baud_rate() const
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
void write_array(const uint8_t *data, size_t len)
bool upload_tft(uint32_t baud_rate=0, bool exit_reparse=true)
Uploads the TFT file to the Nextion display.
bool send_command_(const std::string &command)
Manually send a raw command to the display and don't wait for an acknowledgement packet.
bool upload_end_(bool successful)
Ends the upload process, restart Nextion and, if successful, restarts ESP.
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
virtual void load_settings(bool dump_config)
Load the UART settings.
int upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start)
will request chunk_size chunks from the web server and send each to the nextion
bool set_protocol_reparse_mode(bool active_mode)
Sets the Nextion display's protocol reparse mode.
uint32_t original_baud_rate_
Application App
Global storage of Application pointer - only one Application can exist.
void set_baud_rate(uint32_t baud_rate)
void deallocate(T *p, size_t n)
bool upload_first_chunk_sent_
Implementation of SPI Controller mode.
void reset_(bool reset_nextion=true)
An STL allocator that uses SPI or internal RAM.
uint16_t recv_ret_string_(std::string &response, uint32_t timeout, bool recv_flag)
void IRAM_ATTR HOT delay(uint32_t ms)