mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Nextion support to esp-idf (#5667)
				
					
				
			Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -36,7 +36,7 @@ CONFIG_SCHEMA = ( | |||||||
|     display.BASIC_DISPLAY_SCHEMA.extend( |     display.BASIC_DISPLAY_SCHEMA.extend( | ||||||
|         { |         { | ||||||
|             cv.GenerateID(): cv.declare_id(Nextion), |             cv.GenerateID(): cv.declare_id(Nextion), | ||||||
|             cv.Optional(CONF_TFT_URL): cv.All(cv.string, cv.only_with_arduino), |             cv.Optional(CONF_TFT_URL): cv.url, | ||||||
|             cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, |             cv.Optional(CONF_BRIGHTNESS, default=1.0): cv.percentage, | ||||||
|             cv.Optional(CONF_ON_SETUP): automation.validate_automation( |             cv.Optional(CONF_ON_SETUP): automation.validate_automation( | ||||||
|                 { |                 { | ||||||
| @@ -85,10 +85,10 @@ async def to_code(config): | |||||||
|     if CONF_TFT_URL in config: |     if CONF_TFT_URL in config: | ||||||
|         cg.add_define("USE_NEXTION_TFT_UPLOAD") |         cg.add_define("USE_NEXTION_TFT_UPLOAD") | ||||||
|         cg.add(var.set_tft_url(config[CONF_TFT_URL])) |         cg.add(var.set_tft_url(config[CONF_TFT_URL])) | ||||||
|         if CORE.is_esp32: |         if CORE.is_esp32 and CORE.using_arduino: | ||||||
|             cg.add_library("WiFiClientSecure", None) |             cg.add_library("WiFiClientSecure", None) | ||||||
|             cg.add_library("HTTPClient", None) |             cg.add_library("HTTPClient", None) | ||||||
|         if CORE.is_esp8266: |         elif CORE.is_esp8266 and CORE.using_arduino: | ||||||
|             cg.add_library("ESP8266HTTPClient", None) |             cg.add_library("ESP8266HTTPClient", None) | ||||||
|  |  | ||||||
|     if CONF_TOUCH_SLEEP_TIMEOUT in config: |     if CONF_TOUCH_SLEEP_TIMEOUT in config: | ||||||
|   | |||||||
| @@ -128,7 +128,7 @@ void Nextion::dump_config() { | |||||||
|   ESP_LOGCONFIG(TAG, "  Wake On Touch:    %s", this->auto_wake_on_touch_ ? "True" : "False"); |   ESP_LOGCONFIG(TAG, "  Wake On Touch:    %s", this->auto_wake_on_touch_ ? "True" : "False"); | ||||||
|  |  | ||||||
|   if (this->touch_sleep_timeout_ != 0) { |   if (this->touch_sleep_timeout_ != 0) { | ||||||
|     ESP_LOGCONFIG(TAG, "  Touch Timeout:       %d", this->touch_sleep_timeout_); |     ESP_LOGCONFIG(TAG, "  Touch Timeout:       %" PRIu32, this->touch_sleep_timeout_); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (this->wake_up_page_ != -1) { |   if (this->wake_up_page_ != -1) { | ||||||
| @@ -868,6 +868,12 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool | |||||||
|   start = millis(); |   start = millis(); | ||||||
|  |  | ||||||
|   while ((timeout == 0 && this->available()) || millis() - start <= timeout) { |   while ((timeout == 0 && this->available()) || millis() - start <= timeout) { | ||||||
|  |     if (!this->available()) { | ||||||
|  |       App.feed_wdt(); | ||||||
|  |       delay(1); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     this->read_byte(&c); |     this->read_byte(&c); | ||||||
|     if (c == 0xFF) { |     if (c == 0xFF) { | ||||||
|       nr_of_ff_bytes++; |       nr_of_ff_bytes++; | ||||||
| @@ -886,7 +892,7 @@ uint16_t Nextion::recv_ret_string_(std::string &response, uint32_t timeout, bool | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     App.feed_wdt(); |     App.feed_wdt(); | ||||||
|     delay(1); |     delay(2); | ||||||
|  |  | ||||||
|     if (exit_flag || ff_flag) { |     if (exit_flag || ff_flag) { | ||||||
|       break; |       break; | ||||||
|   | |||||||
| @@ -12,14 +12,18 @@ | |||||||
| #include "esphome/components/display/display_color_utils.h" | #include "esphome/components/display/display_color_utils.h" | ||||||
|  |  | ||||||
| #ifdef USE_NEXTION_TFT_UPLOAD | #ifdef USE_NEXTION_TFT_UPLOAD | ||||||
|  | #ifdef ARDUINO | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
| #include <HTTPClient.h> | #include <HTTPClient.h> | ||||||
| #endif | #endif  // USE_ESP32 | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
| #include <ESP8266HTTPClient.h> | #include <ESP8266HTTPClient.h> | ||||||
| #include <WiFiClientSecure.h> | #include <WiFiClientSecure.h> | ||||||
| #endif | #endif  // USE_ESP8266 | ||||||
| #endif | #elif defined(USE_ESP_IDF) | ||||||
|  | #include <esp_http_client.h> | ||||||
|  | #endif  // ARDUINO vs ESP-IDF | ||||||
|  | #endif  // USE_NEXTION_TFT_UPLOAD | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace nextion { | namespace nextion { | ||||||
| @@ -685,16 +689,18 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe | |||||||
|  |  | ||||||
| #ifdef USE_NEXTION_TFT_UPLOAD | #ifdef USE_NEXTION_TFT_UPLOAD | ||||||
|   /** |   /** | ||||||
|    * Set the tft file URL. https seems problamtic with arduino.. |    * Set the tft file URL. https seems problematic with arduino.. | ||||||
|    */ |    */ | ||||||
|   void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } |   void set_tft_url(const std::string &tft_url) { this->tft_url_ = tft_url; } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Upload the tft file and softreset the Nextion |    * Upload the tft file and soft reset Nextion | ||||||
|  |    * @return bool True: Transfer completed successfuly, False: Transfer failed. | ||||||
|    */ |    */ | ||||||
|   void upload_tft(); |   bool upload_tft(); | ||||||
|  |  | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
| @@ -817,16 +823,16 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe | |||||||
|   BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr}; |   BearSSL::WiFiClientSecure *wifi_client_secure_{nullptr}; | ||||||
|   WiFiClient *get_wifi_client_(); |   WiFiClient *get_wifi_client_(); | ||||||
| #endif | #endif | ||||||
|  |   int content_length_ = 0; | ||||||
|  |   int tft_size_ = 0; | ||||||
|  | #ifdef ARDUINO | ||||||
|   /** |   /** | ||||||
|    * 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 int contentLength Total size of the file |    * @param HTTPClient http HTTP client handler. | ||||||
|    * @param uint32_t chunk_size |    * @param int range_start Position of next byte to transfer. | ||||||
|    * @return true if success, false for failure. |    * @return position of last byte transferred, -1 for failure. | ||||||
|    */ |    */ | ||||||
|   int content_length_ = 0; |  | ||||||
|   int tft_size_ = 0; |  | ||||||
|   int upload_by_chunks_(HTTPClient *http, int range_start); |   int upload_by_chunks_(HTTPClient *http, int range_start); | ||||||
|  |  | ||||||
|   bool upload_with_range_(uint32_t range_start, uint32_t range_end); |   bool upload_with_range_(uint32_t range_start, uint32_t range_end); | ||||||
| @@ -839,7 +845,30 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe | |||||||
|    * @return true if success, false for failure. |    * @return true if success, false for failure. | ||||||
|    */ |    */ | ||||||
|   bool upload_from_buffer_(const uint8_t *file_buf, size_t buf_size); |   bool upload_from_buffer_(const uint8_t *file_buf, size_t buf_size); | ||||||
|   void upload_end_(); |   /** | ||||||
|  |    * 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); | ||||||
|  | #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 ESP-IDF | ||||||
|  |  | ||||||
| #endif  // USE_NEXTION_TFT_UPLOAD | #endif  // USE_NEXTION_TFT_UPLOAD | ||||||
|  |  | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ void Nextion::set_protocol_reparse_mode(bool active_mode) { | |||||||
|  |  | ||||||
| // Set Colors | // Set Colors | ||||||
| void Nextion::set_component_background_color(const char *component, uint32_t color) { | void Nextion::set_component_background_color(const char *component, uint32_t color) { | ||||||
|   this->add_no_result_to_queue_with_printf_("set_component_background_color", "%s.bco=%d", component, color); |   this->add_no_result_to_queue_with_printf_("set_component_background_color", "%s.bco=%" PRIu32, component, color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_background_color(const char *component, const char *color) { | void Nextion::set_component_background_color(const char *component, const char *color) { | ||||||
| @@ -68,7 +68,8 @@ void Nextion::set_component_background_color(const char *component, Color color) | |||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_pressed_background_color(const char *component, uint32_t color) { | void Nextion::set_component_pressed_background_color(const char *component, uint32_t color) { | ||||||
|   this->add_no_result_to_queue_with_printf_("set_component_pressed_background_color", "%s.bco2=%d", component, color); |   this->add_no_result_to_queue_with_printf_("set_component_pressed_background_color", "%s.bco2=%" PRIu32, component, | ||||||
|  |                                             color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_pressed_background_color(const char *component, const char *color) { | void Nextion::set_component_pressed_background_color(const char *component, const char *color) { | ||||||
| @@ -89,7 +90,7 @@ void Nextion::set_component_picc(const char *component, uint8_t pic_id) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_font_color(const char *component, uint32_t color) { | void Nextion::set_component_font_color(const char *component, uint32_t color) { | ||||||
|   this->add_no_result_to_queue_with_printf_("set_component_font_color", "%s.pco=%d", component, color); |   this->add_no_result_to_queue_with_printf_("set_component_font_color", "%s.pco=%" PRIu32, component, color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_font_color(const char *component, const char *color) { | void Nextion::set_component_font_color(const char *component, const char *color) { | ||||||
| @@ -102,7 +103,7 @@ void Nextion::set_component_font_color(const char *component, Color color) { | |||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_pressed_font_color(const char *component, uint32_t color) { | void Nextion::set_component_pressed_font_color(const char *component, uint32_t color) { | ||||||
|   this->add_no_result_to_queue_with_printf_("set_component_pressed_font_color", "%s.pco2=%d", component, color); |   this->add_no_result_to_queue_with_printf_("set_component_pressed_font_color", "%s.pco2=%" PRIu32, component, color); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Nextion::set_component_pressed_font_color(const char *component, const char *color) { | void Nextion::set_component_pressed_font_color(const char *component, const char *color) { | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #include "nextion.h" | #include "nextion.h" | ||||||
| 
 | 
 | ||||||
|  | #ifdef ARDUINO | ||||||
| #ifdef USE_NEXTION_TFT_UPLOAD | #ifdef USE_NEXTION_TFT_UPLOAD | ||||||
| 
 | 
 | ||||||
| #include "esphome/core/application.h" | #include "esphome/core/application.h" | ||||||
| @@ -128,15 +129,15 @@ int Nextion::upload_by_chunks_(HTTPClient *http, int range_start) { | |||||||
|   return range_end + 1; |   return range_end + 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Nextion::upload_tft() { | bool Nextion::upload_tft() { | ||||||
|   if (this->is_updating_) { |   if (this->is_updating_) { | ||||||
|     ESP_LOGD(TAG, "Currently updating"); |     ESP_LOGD(TAG, "Currently updating"); | ||||||
|     return; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!network::is_connected()) { |   if (!network::is_connected()) { | ||||||
|     ESP_LOGD(TAG, "network is not connected"); |     ESP_LOGD(TAG, "network is not connected"); | ||||||
|     return; |     return false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   this->is_updating_ = true; |   this->is_updating_ = true; | ||||||
| @@ -164,7 +165,7 @@ void Nextion::upload_tft() { | |||||||
|     ESP_LOGD(TAG, "connection failed"); |     ESP_LOGD(TAG, "connection failed"); | ||||||
|     ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); |     ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); | ||||||
|     allocator.deallocate(this->transfer_buffer_, this->transfer_buffer_size_); |     allocator.deallocate(this->transfer_buffer_, this->transfer_buffer_size_); | ||||||
|     return; |     return false; | ||||||
|   } else { |   } else { | ||||||
|     ESP_LOGD(TAG, "Connected"); |     ESP_LOGD(TAG, "Connected"); | ||||||
|   } |   } | ||||||
| @@ -192,7 +193,7 @@ void Nextion::upload_tft() { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if ((code != 200 && code != 206) || tries > 5) { |   if ((code != 200 && code != 206) || tries > 5) { | ||||||
|     this->upload_end_(); |     return this->upload_end_(false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   String content_range_string = http.header("Content-Range"); |   String content_range_string = http.header("Content-Range"); | ||||||
| @@ -203,7 +204,7 @@ void Nextion::upload_tft() { | |||||||
| 
 | 
 | ||||||
|   if (this->content_length_ < 4096) { |   if (this->content_length_ < 4096) { | ||||||
|     ESP_LOGE(TAG, "Failed to get file size"); |     ESP_LOGE(TAG, "Failed to get file size"); | ||||||
|     this->upload_end_(); |     return this->upload_end_(false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   ESP_LOGD(TAG, "Updating Nextion %s...", this->device_model_.c_str()); |   ESP_LOGD(TAG, "Updating Nextion %s...", this->device_model_.c_str()); | ||||||
| @@ -246,7 +247,7 @@ void Nextion::upload_tft() { | |||||||
|     ESP_LOGD(TAG, "preparation for tft update done"); |     ESP_LOGD(TAG, "preparation for tft update done"); | ||||||
|   } else { |   } else { | ||||||
|     ESP_LOGD(TAG, "preparation for tft update failed %d \"%s\"", response[0], response.c_str()); |     ESP_LOGD(TAG, "preparation for tft update failed %d \"%s\"", response[0], response.c_str()); | ||||||
|     this->upload_end_(); |     return this->upload_end_(false); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Nextion wants 4096 bytes at a time. Make chunk_size a multiple of 4096
 |   // Nextion wants 4096 bytes at a time. Make chunk_size a multiple of 4096
 | ||||||
| @@ -280,7 +281,7 @@ void Nextion::upload_tft() { | |||||||
|       this->transfer_buffer_ = allocator.allocate(chunk_size); |       this->transfer_buffer_ = allocator.allocate(chunk_size); | ||||||
| 
 | 
 | ||||||
|       if (!this->transfer_buffer_) |       if (!this->transfer_buffer_) | ||||||
|         this->upload_end_(); |         return this->upload_end_(false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this->transfer_buffer_size_ = chunk_size; |     this->transfer_buffer_size_ = chunk_size; | ||||||
| @@ -295,7 +296,7 @@ void Nextion::upload_tft() { | |||||||
|     result = this->upload_by_chunks_(&http, result); |     result = this->upload_by_chunks_(&http, result); | ||||||
|     if (result < 0) { |     if (result < 0) { | ||||||
|       ESP_LOGD(TAG, "Error updating Nextion!"); |       ESP_LOGD(TAG, "Error updating Nextion!"); | ||||||
|       this->upload_end_(); |       return this->upload_end_(false); | ||||||
|     } |     } | ||||||
|     App.feed_wdt(); |     App.feed_wdt(); | ||||||
|     // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 |     // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | ||||||
| @@ -303,15 +304,19 @@ void Nextion::upload_tft() { | |||||||
|   } |   } | ||||||
|   ESP_LOGD(TAG, "Successfully updated Nextion!"); |   ESP_LOGD(TAG, "Successfully updated Nextion!"); | ||||||
| 
 | 
 | ||||||
|   this->upload_end_(); |   return this->upload_end_(true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Nextion::upload_end_() { | bool Nextion::upload_end_(bool successful) { | ||||||
|  |   this->is_updating_ = false; | ||||||
|   ESP_LOGD(TAG, "Restarting Nextion"); |   ESP_LOGD(TAG, "Restarting Nextion"); | ||||||
|   this->soft_reset(); |   this->soft_reset(); | ||||||
|   delay(1500);  // NOLINT
 |   if (successful) { | ||||||
|   ESP_LOGD(TAG, "Restarting esphome"); |     delay(1500);  // NOLINT
 | ||||||
|   ESP.restart();  // NOLINT(readability-static-accessed-through-instance)
 |     ESP_LOGD(TAG, "Restarting esphome"); | ||||||
|  |     ESP.restart();  // NOLINT(readability-static-accessed-through-instance)
 | ||||||
|  |   } | ||||||
|  |   return successful; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef USE_ESP8266 | #ifdef USE_ESP8266 | ||||||
| @@ -337,3 +342,4 @@ WiFiClient *Nextion::get_wifi_client_() { | |||||||
| }  // namespace esphome
 | }  // namespace esphome
 | ||||||
| 
 | 
 | ||||||
| #endif  // USE_NEXTION_TFT_UPLOAD
 | #endif  // USE_NEXTION_TFT_UPLOAD
 | ||||||
|  | #endif  // ARDUINO
 | ||||||
							
								
								
									
										268
									
								
								esphome/components/nextion/nextion_upload_idf.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								esphome/components/nextion/nextion_upload_idf.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,268 @@ | |||||||
|  | #include "nextion.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP_IDF | ||||||
|  | #ifdef USE_NEXTION_TFT_UPLOAD | ||||||
|  |  | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  | #include "esphome/core/util.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/components/network/util.h" | ||||||
|  |  | ||||||
|  | #include <esp_heap_caps.h> | ||||||
|  | #include <esp_http_client.h> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace nextion { | ||||||
|  | static const char *const TAG = "nextion_upload"; | ||||||
|  |  | ||||||
|  | // Followed guide | ||||||
|  | // 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) { | ||||||
|  |   ESP_LOGVV(TAG, "url: %s", url.c_str()); | ||||||
|  |   uint range_size = this->tft_size_ - range_start; | ||||||
|  |   ESP_LOGVV(TAG, "tft_size_: %i", this->tft_size_); | ||||||
|  |   ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |   int range_end = (range_start == 0) ? std::min(this->tft_size_, 16383) : this->tft_size_; | ||||||
|  |   if (range_size <= 0 or range_end <= range_start) { | ||||||
|  |     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; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   esp_http_client_config_t config = { | ||||||
|  |       .url = url.c_str(), | ||||||
|  |       .cert_pem = nullptr, | ||||||
|  |   }; | ||||||
|  |   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_http_client_set_header(client, "Range", range_header); | ||||||
|  |   ESP_LOGVV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "Opening http connetion"); | ||||||
|  |   esp_err_t err; | ||||||
|  |   if ((err = esp_http_client_open(client, 0)) != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err)); | ||||||
|  |     esp_http_client_cleanup(client); | ||||||
|  |     return -1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "Fetch content length"); | ||||||
|  |   int content_length = esp_http_client_fetch_headers(client); | ||||||
|  |   ESP_LOGV(TAG, "content_length = %d", content_length); | ||||||
|  |   if (content_length <= 0) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to get content length: %d", content_length); | ||||||
|  |     esp_http_client_cleanup(client); | ||||||
|  |     return -1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int total_read_len = 0, read_len; | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "Allocate buffer"); | ||||||
|  |   uint8_t *buffer = new uint8_t[4096]; | ||||||
|  |   std::string recv_string; | ||||||
|  |   if (buffer == nullptr) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to allocate memory for buffer"); | ||||||
|  |     ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGV(TAG, "Memory for buffer allocated successfully"); | ||||||
|  |  | ||||||
|  |     while (true) { | ||||||
|  |       App.feed_wdt(); | ||||||
|  |       ESP_LOGVV(TAG, "Available heap: %u", 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", | ||||||
|  |                  100.0 * (this->tft_size_ - this->content_length_) / this->tft_size_, this->content_length_); | ||||||
|  |         if (recv_string[0] != 0x05) {  // 0x05 == "ok" | ||||||
|  |           ESP_LOGD( | ||||||
|  |               TAG, "recv_string [%s]", | ||||||
|  |               format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str()); | ||||||
|  |         } | ||||||
|  |         // handle partial upload request | ||||||
|  |         if (recv_string[0] == 0x08 && recv_string.size() == 5) { | ||||||
|  |           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 | ||||||
|  |             delete[] buffer; | ||||||
|  |             ESP_LOGVV(TAG, "Memory for buffer deallocated"); | ||||||
|  |             esp_http_client_cleanup(client); | ||||||
|  |             esp_http_client_close(client); | ||||||
|  |             return result; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         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 | ||||||
|  |     delete[] buffer; | ||||||
|  |     ESP_LOGVV(TAG, "Memory for buffer deallocated"); | ||||||
|  |   } | ||||||
|  |   esp_http_client_cleanup(client); | ||||||
|  |   esp_http_client_close(client); | ||||||
|  |   return range_end + 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Nextion::upload_tft() { | ||||||
|  |   ESP_LOGD(TAG, "Nextion TFT upload requested"); | ||||||
|  |   ESP_LOGD(TAG, "url: %s", this->tft_url_.c_str()); | ||||||
|  |  | ||||||
|  |   if (this->is_updating_) { | ||||||
|  |     ESP_LOGW(TAG, "Currently updating"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!network::is_connected()) { | ||||||
|  |     ESP_LOGE(TAG, "Network is not connected"); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->is_updating_ = true; | ||||||
|  |  | ||||||
|  |   // Define the configuration for the HTTP client | ||||||
|  |   ESP_LOGV(TAG, "Establishing connection to HTTP server"); | ||||||
|  |   ESP_LOGVV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |   esp_http_client_config_t config = { | ||||||
|  |       .url = this->tft_url_.c_str(), | ||||||
|  |       .cert_pem = nullptr, | ||||||
|  |       .method = HTTP_METHOD_HEAD, | ||||||
|  |       .timeout_ms = 15000, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   // Initialize the HTTP client with the configuration | ||||||
|  |   ESP_LOGV(TAG, "Initializing HTTP client"); | ||||||
|  |   ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |   esp_http_client_handle_t http = esp_http_client_init(&config); | ||||||
|  |   if (!http) { | ||||||
|  |     ESP_LOGE(TAG, "Failed to initialize HTTP client."); | ||||||
|  |     return this->upload_end(false); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Perform the HTTP request | ||||||
|  |   ESP_LOGV(TAG, "Check if the client could connect"); | ||||||
|  |   ESP_LOGV(TAG, "Available heap: %u", esp_get_free_heap_size()); | ||||||
|  |   esp_err_t err = esp_http_client_perform(http); | ||||||
|  |   if (err != ESP_OK) { | ||||||
|  |     ESP_LOGE(TAG, "HTTP request failed: %s", esp_err_to_name(err)); | ||||||
|  |     esp_http_client_cleanup(http); | ||||||
|  |     return this->upload_end(false); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Check the HTTP Status Code | ||||||
|  |   int status_code = esp_http_client_get_status_code(http); | ||||||
|  |   ESP_LOGV(TAG, "HTTP Status Code: %d", status_code); | ||||||
|  |   size_t tft_file_size = esp_http_client_get_content_length(http); | ||||||
|  |   ESP_LOGD(TAG, "TFT file size: %zu", tft_file_size); | ||||||
|  |  | ||||||
|  |   if (tft_file_size < 4096) { | ||||||
|  |     ESP_LOGE(TAG, "File size check failed. Size: %zu", tft_file_size); | ||||||
|  |     esp_http_client_cleanup(http); | ||||||
|  |     return this->upload_end(false); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGV(TAG, "File size check passed. Proceeding..."); | ||||||
|  |   } | ||||||
|  |   this->content_length_ = tft_file_size; | ||||||
|  |   this->tft_size_ = tft_file_size; | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Updating Nextion"); | ||||||
|  |   // The Nextion will ignore the update command if it is sleeping | ||||||
|  |  | ||||||
|  |   this->send_command_("sleep=0"); | ||||||
|  |   this->set_backlight_brightness(1.0); | ||||||
|  |   vTaskDelay(pdMS_TO_TICKS(250));  // NOLINT | ||||||
|  |  | ||||||
|  |   App.feed_wdt(); | ||||||
|  |   char command[128]; | ||||||
|  |   // Tells the Nextion the content length of the tft file and baud rate it will be sent at | ||||||
|  |   // Once the Nextion accepts the command it will wait until the file is successfully uploaded | ||||||
|  |   // If it fails for any reason a power cycle of the display will be needed | ||||||
|  |   sprintf(command, "whmi-wris %d,%" PRIu32 ",1", this->content_length_, this->parent_->get_baud_rate()); | ||||||
|  |  | ||||||
|  |   // Clear serial receive buffer | ||||||
|  |   uint8_t d; | ||||||
|  |   while (this->available()) { | ||||||
|  |     this->read_byte(&d); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   this->send_command_(command); | ||||||
|  |  | ||||||
|  |   std::string response; | ||||||
|  |   ESP_LOGV(TAG, "Waiting for upgrade response"); | ||||||
|  |   this->recv_ret_string_(response, 2048, true);  // This can take some time to return | ||||||
|  |  | ||||||
|  |   // The Nextion display will, if it's ready to accept data, send a 0x05 byte. | ||||||
|  |   ESP_LOGD(TAG, "Upgrade response is [%s]", | ||||||
|  |            format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str()); | ||||||
|  |  | ||||||
|  |   if (response.find(0x05) != std::string::npos) { | ||||||
|  |     ESP_LOGV(TAG, "Preparation for tft update done"); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGE(TAG, "Preparation for tft update failed %d \"%s\"", response[0], response.c_str()); | ||||||
|  |     esp_http_client_cleanup(http); | ||||||
|  |     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(), | ||||||
|  |            content_length_, esp_get_free_heap_size()); | ||||||
|  |  | ||||||
|  |   ESP_LOGV(TAG, "Starting transfer by chunks loop"); | ||||||
|  |   int result = 0; | ||||||
|  |   while (content_length_ > 0) { | ||||||
|  |     result = upload_range(this->tft_url_.c_str(), result); | ||||||
|  |     if (result < 0) { | ||||||
|  |       ESP_LOGE(TAG, "Error updating Nextion!"); | ||||||
|  |       esp_http_client_cleanup(http); | ||||||
|  |       return this->upload_end(false); | ||||||
|  |     } | ||||||
|  |     App.feed_wdt(); | ||||||
|  |     ESP_LOGV(TAG, "Heap Size %" PRIu32 ", Bytes left %d", esp_get_free_heap_size(), content_length_); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Successfully updated Nextion!"); | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Close HTTP connection"); | ||||||
|  |   esp_http_client_close(http); | ||||||
|  |   esp_http_client_cleanup(http); | ||||||
|  |   return upload_end(true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool Nextion::upload_end(bool successful) { | ||||||
|  |   this->is_updating_ = false; | ||||||
|  |   ESP_LOGD(TAG, "Restarting Nextion"); | ||||||
|  |   this->soft_reset(); | ||||||
|  |   vTaskDelay(pdMS_TO_TICKS(1500));  // NOLINT | ||||||
|  |   if (successful) { | ||||||
|  |     ESP_LOGD(TAG, "Restarting esphome"); | ||||||
|  |     esp_restart();  // NOLINT(readability-static-accessed-through-instance) | ||||||
|  |   } | ||||||
|  |   return successful; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace nextion | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_NEXTION_TFT_UPLOAD | ||||||
|  | #endif  // USE_ESP_IDF | ||||||
		Reference in New Issue
	
	Block a user