Merge remote-tracking branch 'upstream/dev' into integration

# Conflicts:
#	esphome/components/api/api_frame_helper.h
#	esphome/core/application.h
This commit is contained in:
J. Nick Koston
2026-03-08 16:44:41 -10:00
20 changed files with 151 additions and 45 deletions
+5 -5
View File
@@ -228,13 +228,13 @@ class APIFrameHelper {
EXPLICIT_REJECT = 8, // Noise only
};
// Fast inline check for read_packet/write_protobuf_messages hot path.
// In DATA state, state_action_() is a no-op (falls through all checks to return OK).
// This avoids a 447-byte function call on every packet during normal operation.
// Fast inline state check for read_packet/write_protobuf_messages hot path.
// Returns OK only in DATA state; maps CLOSED/FAILED to BAD_STATE and any
// other intermediate state to WOULD_BLOCK.
inline APIError ESPHOME_ALWAYS_INLINE check_data_state_() const {
if (state_ == State::DATA)
if (this->state_ == State::DATA)
return APIError::OK;
if (state_ == State::CLOSED || state_ == State::FAILED)
if (this->state_ == State::CLOSED || this->state_ == State::FAILED)
return APIError::BAD_STATE;
return APIError::WOULD_BLOCK;
}
@@ -41,9 +41,9 @@ class DutyTimeSensor : public sensor::Sensor, public PollingComponent {
sensor::Sensor *last_duty_time_sensor_{nullptr};
ESPPreferenceObject pref_;
uint32_t total_sec_;
uint32_t last_time_;
uint32_t edge_time_;
uint32_t total_sec_{0};
uint32_t last_time_{0};
uint32_t edge_time_{0};
bool last_state_{false};
bool restore_;
};
@@ -56,8 +56,8 @@ class GrowattSolar : public PollingComponent, public modbus::ModbusDevice {
}
protected:
bool waiting_to_update_;
uint32_t last_send_;
bool waiting_to_update_{false};
uint32_t last_send_{0};
struct GrowattPhase {
sensor::Sensor *voltage_sensor_{nullptr};
+2 -2
View File
@@ -18,8 +18,8 @@ class HTE501Component : public PollingComponent, public i2c::I2CDevice {
void update() override;
protected:
sensor::Sensor *temperature_sensor_;
sensor::Sensor *humidity_sensor_;
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, CRC_CHECK_FAILED } error_code_{NONE};
};
@@ -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"
+62 -4
View File
@@ -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")
+12
View File
@@ -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() {
+31
View File
@@ -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,
};
+1 -1
View File
@@ -43,7 +43,7 @@ class SelectCall {
Select *const parent_;
optional<size_t> index_;
SelectOperation operation_{SELECT_OP_NONE};
bool cycle_;
bool cycle_{false};
};
} // namespace esphome::select
@@ -89,8 +89,8 @@ class UponorSmatrixComponent : public uart::UARTDevice, public Component {
std::vector<uint8_t> rx_buffer_;
std::queue<std::vector<uint8_t>> tx_queue_;
uint32_t last_rx_;
uint32_t last_tx_;
uint32_t last_rx_{0};
uint32_t last_tx_{0};
#ifdef USE_TIME
time::RealTimeClock *time_id_{nullptr};
@@ -23,7 +23,7 @@ class IPAddressWiFiInfo final : public Component, public text_sensor::TextSensor
const network::IPAddress &dns2) override;
protected:
std::array<text_sensor::TextSensor *, 5> ip_sensors_;
std::array<text_sensor::TextSensor *, 5> ip_sensors_{};
};
class DNSAddressWifiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiIPStateListener {
+3 -3
View File
@@ -25,9 +25,9 @@ class X9cOutput : public output::FloatOutput, public Component {
InternalGPIOPin *cs_pin_;
InternalGPIOPin *inc_pin_;
InternalGPIOPin *ud_pin_;
float initial_value_;
float pot_value_;
int step_delay_;
float initial_value_{0.0f};
float pot_value_{0.0f};
int step_delay_{0};
};
} // namespace x9c
-3
View File
@@ -33,9 +33,6 @@
#include <lwip/sockets.h>
#endif
#endif
#if defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP)
#include "esphome/components/socket/socket.h"
#endif
#endif // USE_SOCKET_SELECT_SUPPORT
#if (defined(USE_ESP8266) || defined(USE_RP2040)) && defined(USE_SOCKET_IMPL_LWIP_TCP)
namespace esphome::socket {
@@ -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
+2 -4
View File
@@ -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
+2 -4
View File
@@ -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