mirror of
https://github.com/esphome/esphome.git
synced 2025-04-14 23:00:29 +01:00
Nextion support to esp-idf
(#5667)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
fde7a04ee7
commit
d81bec860b
@ -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
|
Loading…
x
Reference in New Issue
Block a user