mirror of
https://github.com/esphome/esphome.git
synced 2026-05-20 17:52:00 +08:00
[nextion] Add configurable HTTP parameters for TFT upload (#14234)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -27,6 +27,9 @@ CONF_PRECISION = "precision"
|
||||
CONF_SKIP_CONNECTION_HANDSHAKE = "skip_connection_handshake"
|
||||
CONF_START_UP_PAGE = "start_up_page"
|
||||
CONF_STARTUP_OVERRIDE_MS = "startup_override_ms"
|
||||
CONF_TFT_UPLOAD_HTTP_RETRIES = "tft_upload_http_retries"
|
||||
CONF_TFT_UPLOAD_HTTP_TIMEOUT = "tft_upload_http_timeout"
|
||||
CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT = "tft_upload_watchdog_timeout"
|
||||
CONF_TFT_URL = "tft_url"
|
||||
CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout"
|
||||
CONF_VARIABLE_NAME = "variable_name"
|
||||
|
||||
@@ -33,15 +33,24 @@ from .base_component import (
|
||||
CONF_SKIP_CONNECTION_HANDSHAKE,
|
||||
CONF_START_UP_PAGE,
|
||||
CONF_STARTUP_OVERRIDE_MS,
|
||||
CONF_TFT_UPLOAD_HTTP_RETRIES,
|
||||
CONF_TFT_UPLOAD_HTTP_TIMEOUT,
|
||||
CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT,
|
||||
CONF_TFT_URL,
|
||||
CONF_TOUCH_SLEEP_TIMEOUT,
|
||||
CONF_WAKE_UP_PAGE,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@senexcrenshaw", "@edwardtfn"]
|
||||
|
||||
DEPENDENCIES = ["uart"]
|
||||
AUTO_LOAD = ["binary_sensor", "switch", "sensor", "text_sensor"]
|
||||
|
||||
|
||||
def AUTO_LOAD() -> list[str]:
|
||||
base = ["binary_sensor", "switch", "sensor", "text_sensor"]
|
||||
if CORE.is_esp32:
|
||||
base.append("watchdog")
|
||||
return base
|
||||
|
||||
|
||||
NextionSetBrightnessAction = nextion_ns.class_(
|
||||
"NextionSetBrightnessAction", automation.Action
|
||||
@@ -55,7 +64,24 @@ BufferOverflowTrigger = nextion_ns.class_(
|
||||
"BufferOverflowTrigger", automation.Trigger.template()
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
|
||||
def _validate_tft_upload(config):
|
||||
has_tft_url = CONF_TFT_URL in config
|
||||
for conf_key in (
|
||||
CONF_TFT_UPLOAD_HTTP_TIMEOUT,
|
||||
CONF_TFT_UPLOAD_HTTP_RETRIES,
|
||||
CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT,
|
||||
):
|
||||
if conf_key in config and not has_tft_url:
|
||||
raise cv.Invalid(f"{conf_key} requires {CONF_TFT_URL} to be set")
|
||||
if CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT in config and not CORE.is_esp32:
|
||||
raise cv.Invalid(
|
||||
f"{CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT} is only available on ESP32"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.BASIC_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(Nextion),
|
||||
@@ -115,6 +141,14 @@ CONFIG_SCHEMA = (
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_START_UP_PAGE): cv.uint8_t,
|
||||
cv.Optional(CONF_TFT_UPLOAD_HTTP_RETRIES): cv.int_range(min=1, max=255),
|
||||
cv.Optional(CONF_TFT_UPLOAD_HTTP_TIMEOUT): cv.All(
|
||||
cv.positive_time_period_milliseconds,
|
||||
cv.Range(max=TimePeriod(milliseconds=65535)),
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_TFT_URL): cv.url,
|
||||
cv.Optional(CONF_TOUCH_SLEEP_TIMEOUT): cv.Any(
|
||||
0, cv.int_range(min=3, max=65535)
|
||||
@@ -123,7 +157,8 @@ CONFIG_SCHEMA = (
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("5s"))
|
||||
.extend(uart.UART_DEVICE_SCHEMA)
|
||||
.extend(uart.UART_DEVICE_SCHEMA),
|
||||
_validate_tft_upload,
|
||||
)
|
||||
|
||||
|
||||
@@ -176,6 +211,29 @@ async def to_code(config):
|
||||
if CONF_TFT_URL in config:
|
||||
cg.add_define("USE_NEXTION_TFT_UPLOAD")
|
||||
cg.add(var.set_tft_url(config[CONF_TFT_URL]))
|
||||
|
||||
# TFT upload HTTP timeout (default: 4.5s)
|
||||
if CONF_TFT_UPLOAD_HTTP_TIMEOUT in config:
|
||||
cg.add(
|
||||
var.set_tft_upload_http_timeout(
|
||||
config[CONF_TFT_UPLOAD_HTTP_TIMEOUT].total_milliseconds
|
||||
)
|
||||
)
|
||||
|
||||
# TFT upload HTTP retries (default: 5)
|
||||
if CONF_TFT_UPLOAD_HTTP_RETRIES in config:
|
||||
cg.add(
|
||||
var.set_tft_upload_http_retries(config[CONF_TFT_UPLOAD_HTTP_RETRIES])
|
||||
)
|
||||
|
||||
# TFT upload watchdog timeout (default: 0 = no adjustment)
|
||||
if CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT in config:
|
||||
cg.add(
|
||||
var.set_tft_upload_watchdog_timeout(
|
||||
config[CONF_TFT_UPLOAD_WATCHDOG_TIMEOUT].total_milliseconds
|
||||
)
|
||||
)
|
||||
|
||||
if CORE.is_esp32:
|
||||
# Re-enable ESP-IDF's HTTP client (excluded by default to save compile time)
|
||||
esp32.include_builtin_idf_component("esp_http_client")
|
||||
|
||||
@@ -191,6 +191,18 @@ void Nextion::dump_config() {
|
||||
#ifdef USE_NEXTION_MAX_QUEUE_SIZE
|
||||
ESP_LOGCONFIG(TAG, " Max queue size: %zu", this->max_queue_size_);
|
||||
#endif
|
||||
#ifdef USE_NEXTION_TFT_UPLOAD
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" TFT URL: %s\n"
|
||||
" TFT upload HTTP timeout: %" PRIu16 "ms\n"
|
||||
" TFT upload HTTP retries: %u",
|
||||
this->tft_url_.c_str(), this->tft_upload_http_timeout_, this->tft_upload_http_retries_);
|
||||
#ifdef USE_ESP32
|
||||
if (this->tft_upload_watchdog_timeout_ > 0) {
|
||||
ESP_LOGCONFIG(TAG, " TFT upload WDT timeout: %" PRIu32 "ms", this->tft_upload_watchdog_timeout_);
|
||||
}
|
||||
#endif // USE_ESP32
|
||||
#endif // USE_NEXTION_TFT_UPLOAD
|
||||
}
|
||||
|
||||
void Nextion::update() {
|
||||
|
||||
@@ -1071,6 +1071,33 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||
bool send_command_printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
#ifdef USE_NEXTION_TFT_UPLOAD
|
||||
/**
|
||||
* @brief Set the HTTP timeout for TFT upload requests.
|
||||
* @param timeout_ms Timeout in milliseconds. Defaults to 4500ms (4.5s).
|
||||
*/
|
||||
void set_tft_upload_http_timeout(uint16_t timeout_ms) { this->tft_upload_http_timeout_ = timeout_ms; }
|
||||
|
||||
#ifdef USE_ESP32
|
||||
/**
|
||||
* @brief Set the watchdog timeout during TFT upload.
|
||||
*
|
||||
* The system watchdog timeout is temporarily adjusted to this value
|
||||
* during the entire TFT transfer process and restored to the original
|
||||
* value after the transfer completes (whether successful or not).
|
||||
*
|
||||
* A value of 0 means no watchdog adjustment (default).
|
||||
*
|
||||
* @param timeout_ms Watchdog timeout in milliseconds. 0 = no adjustment.
|
||||
*/
|
||||
void set_tft_upload_watchdog_timeout(uint32_t timeout_ms) { this->tft_upload_watchdog_timeout_ = timeout_ms; }
|
||||
#endif // USE_ESP32
|
||||
|
||||
/**
|
||||
* @brief Set the number of HTTP retries for TFT upload requests.
|
||||
* @param retries Number of retries. Defaults to 5. Range: 1-255.
|
||||
*/
|
||||
void set_tft_upload_http_retries(uint8_t retries) { this->tft_upload_http_retries_ = retries; }
|
||||
|
||||
/**
|
||||
* Set the tft file URL.
|
||||
*/
|
||||
@@ -1439,8 +1466,12 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||
int tft_size_ = 0;
|
||||
uint32_t original_baud_rate_ = 0;
|
||||
bool upload_first_chunk_sent_ = false;
|
||||
uint16_t tft_upload_http_timeout_{4500}; ///< HTTP timeout in ms (default: 4.5s)
|
||||
uint8_t tft_upload_http_retries_{5}; ///< HTTP retry count (default: 5)
|
||||
|
||||
#ifdef USE_ESP32
|
||||
uint32_t tft_upload_watchdog_timeout_{0}; ///< WDT timeout in ms (0 = no adjustment)
|
||||
|
||||
/**
|
||||
* will request 4096 bytes chunks from the web server
|
||||
* and send each to Nextion
|
||||
|
||||
@@ -166,7 +166,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
// Define the configuration for the HTTP client
|
||||
ESP_LOGV(TAG, "Init HTTP client, heap: %" PRIu32, EspClass::getFreeHeap());
|
||||
HTTPClient http_client;
|
||||
http_client.setTimeout(15000); // Yes 15 seconds.... Helps 8266s along
|
||||
http_client.setTimeout(this->tft_upload_http_timeout_);
|
||||
|
||||
bool begin_status = false;
|
||||
#ifdef USE_ESP8266
|
||||
@@ -192,15 +192,15 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
http_client.collectHeaders(header_names, 1);
|
||||
ESP_LOGD(TAG, "URL: %s", this->tft_url_.c_str());
|
||||
http_client.setReuse(true);
|
||||
// try up to 5 times. DNS sometimes needs a second try or so
|
||||
|
||||
int tries = 1;
|
||||
int code = http_client.GET();
|
||||
delay(100); // NOLINT
|
||||
|
||||
App.feed_wdt();
|
||||
while (code != 200 && code != 206 && tries <= 5) {
|
||||
ESP_LOGW(TAG, "HTTP fail: URL: %s; Error: %s, retry %d/5", this->tft_url_.c_str(),
|
||||
HTTPClient::errorToString(code).c_str(), tries);
|
||||
while (code != 200 && code != 206 && tries <= this->tft_upload_http_retries_) {
|
||||
ESP_LOGW(TAG, "HTTP fail: URL: %s; Error: %s, retry %d/%u", this->tft_url_.c_str(),
|
||||
HTTPClient::errorToString(code).c_str(), tries, this->tft_upload_http_retries_);
|
||||
|
||||
delay(250); // NOLINT
|
||||
App.feed_wdt();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <esp_http_client.h>
|
||||
#include <cinttypes>
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/components/watchdog/watchdog.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
@@ -68,7 +69,7 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
|
||||
int partial_read_len = 0;
|
||||
uint8_t retries = 0;
|
||||
// Attempt to read the chunk with retries.
|
||||
while (retries < 5 && read_len < buffer_size) {
|
||||
while (retries < this->tft_upload_http_retries_ && 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) {
|
||||
@@ -167,6 +168,9 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Temporarily adjust watchdog timeout for the duration of the TFT upload
|
||||
watchdog::WatchdogManager wdm(this->tft_upload_watchdog_timeout_);
|
||||
|
||||
this->connection_state_.is_updating_ = true;
|
||||
|
||||
if (exit_reparse) {
|
||||
@@ -190,7 +194,7 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
.url = this->tft_url_.c_str(),
|
||||
.cert_pem = nullptr,
|
||||
.method = HTTP_METHOD_HEAD,
|
||||
.timeout_ms = 15000,
|
||||
.timeout_ms = static_cast<int>(this->tft_upload_http_timeout_),
|
||||
.disable_auto_redirect = false,
|
||||
.max_redirection_count = 10,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
display:
|
||||
- id: !extend main_lcd
|
||||
tft_url: http://esphome.io/default35.tft
|
||||
tft_upload_http_timeout: 20s
|
||||
tft_upload_http_retries: 10
|
||||
@@ -0,0 +1,3 @@
|
||||
display:
|
||||
- id: !extend main_lcd
|
||||
tft_upload_watchdog_timeout: 30s
|
||||
@@ -1,7 +1,5 @@
|
||||
packages:
|
||||
uart: !include ../../test_build_components/common/uart/esp32-ard.yaml
|
||||
base: !include common.yaml
|
||||
|
||||
display:
|
||||
- id: !extend main_lcd
|
||||
tft_url: http://esphome.io/default35.tft
|
||||
tft_upload: !include common_tft_upload.yaml
|
||||
tft_upload_watchdog: !include common_tft_upload_watchdog.yaml
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
packages:
|
||||
uart: !include ../../test_build_components/common/uart/esp32-idf.yaml
|
||||
base: !include common.yaml
|
||||
|
||||
display:
|
||||
- id: !extend main_lcd
|
||||
tft_url: http://esphome.io/default35.tft
|
||||
tft_upload: !include common_tft_upload.yaml
|
||||
tft_upload_watchdog: !include common_tft_upload_watchdog.yaml
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
packages:
|
||||
uart: !include ../../test_build_components/common/uart/esp8266-ard.yaml
|
||||
base: !include common.yaml
|
||||
|
||||
display:
|
||||
- id: !extend main_lcd
|
||||
tft_url: http://esphome.io/default35.tft
|
||||
tft_upload: !include common_tft_upload.yaml
|
||||
|
||||
Reference in New Issue
Block a user