From 90dafa3fa45bc5b279136f069030e1ea4edde780 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 26 Mar 2026 15:59:58 -1000 Subject: [PATCH 1/4] [logger] Warn when VERBOSE/VERY_VERBOSE logging is active (#15189) --- esphome/components/logger/logger.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index cd6543bfb84..23b69c36c60 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -243,6 +243,16 @@ void Logger::dump_config() { #endif #ifdef USE_ZEPHYR dump_crash_(); +#endif + // Warn users that VERBOSE/VERY_VERBOSE logging impacts performance. + // Only the compiled log level matters — all log calls up to this level + // are in the binary and will be formatted (vsnprintf) and block UART. +#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE + ESP_LOGW(TAG, "VERY_VERBOSE logging is active — significant performance impact, short-term debugging only\n" + " May cause connection instability. Set log level to DEBUG or lower for long-term use."); +#elif ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE + ESP_LOGI(TAG, "VERBOSE logging is active — performance impact, short-term debugging only\n" + " Set log level to DEBUG or lower for long-term use."); #endif } From 6feb2d04dfd61c3fe1d03980fe1516b846eacf6b Mon Sep 17 00:00:00 2001 From: Edward Firmo <94725493+edwardtfn@users.noreply.github.com> Date: Fri, 27 Mar 2026 04:36:35 +0100 Subject: [PATCH 2/4] [nextion] Replace `static std::string COMMAND_DELIMITER` with `constexpr` (#15195) Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- esphome/components/nextion/nextion.cpp | 13 +++++++++---- esphome/components/nextion/nextion.h | 2 -- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/esphome/components/nextion/nextion.cpp b/esphome/components/nextion/nextion.cpp index 612bfbc968c..fa1582c209f 100644 --- a/esphome/components/nextion/nextion.cpp +++ b/esphome/components/nextion/nextion.cpp @@ -10,6 +10,10 @@ namespace nextion { static const char *const TAG = "nextion"; +// Nextion command terminator: three consecutive 0xFF bytes (per Nextion Instruction Set v1.1). +static constexpr uint8_t COMMAND_DELIMITER[3] = {0xFF, 0xFF, 0xFF}; +static constexpr size_t DELIMITER_SIZE = sizeof(COMMAND_DELIMITER); + void Nextion::setup() { this->is_setup_ = false; this->connection_state_.ignore_is_setup_ = true; @@ -415,7 +419,8 @@ void Nextion::process_nextion_commands_() { #ifdef NEXTION_PROTOCOL_LOG this->print_queue_members_(); #endif - while ((to_process_length = this->command_data_.find(COMMAND_DELIMITER)) != std::string::npos) { + while ((to_process_length = this->command_data_.find(reinterpret_cast(COMMAND_DELIMITER), 0, + DELIMITER_SIZE)) != std::string::npos) { #ifdef USE_NEXTION_MAX_COMMANDS_PER_LOOP if (++commands_processed > this->max_commands_per_loop_) { ESP_LOGW(TAG, "Command processing limit exceeded"); @@ -423,8 +428,8 @@ void Nextion::process_nextion_commands_() { } #endif // USE_NEXTION_MAX_COMMANDS_PER_LOOP ESP_LOGN(TAG, "queue size: %zu", this->nextion_queue_.size()); - while (to_process_length + COMMAND_DELIMITER.length() < this->command_data_.length() && - static_cast(this->command_data_[to_process_length + COMMAND_DELIMITER.length()]) == 0xFF) { + while (to_process_length + DELIMITER_SIZE < this->command_data_.length() && + static_cast(this->command_data_[to_process_length + DELIMITER_SIZE]) == 0xFF) { ++to_process_length; ESP_LOGN(TAG, "Add 0xFF"); } @@ -829,7 +834,7 @@ void Nextion::process_nextion_commands_() { break; } - this->command_data_.erase(0, to_process_length + COMMAND_DELIMITER.length() + 1); + this->command_data_.erase(0, to_process_length + DELIMITER_SIZE + 1); } const uint32_t ms = App.get_loop_component_start_time(); diff --git a/esphome/components/nextion/nextion.h b/esphome/components/nextion/nextion.h index bb5998cf5dd..217d2e605d2 100644 --- a/esphome/components/nextion/nextion.h +++ b/esphome/components/nextion/nextion.h @@ -29,8 +29,6 @@ class NextionComponentBase; using nextion_writer_t = display::DisplayWriter; -static const std::string COMMAND_DELIMITER{static_cast(255), static_cast(255), static_cast(255)}; - #ifdef USE_NEXTION_COMMAND_SPACING class NextionCommandPacer { public: From 27272b7bb56eb3657b45113bf3531e00cb63d488 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 26 Mar 2026 19:13:21 -1000 Subject: [PATCH 3/4] Use codegen enum expressions instead of raw strings for AlarmControlPanelState --- .../components/alarm_control_panel/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/esphome/components/alarm_control_panel/__init__.py b/esphome/components/alarm_control_panel/__init__.py index ff1c0d1c302..4ee073a15b1 100644 --- a/esphome/components/alarm_control_panel/__init__.py +++ b/esphome/components/alarm_control_panel/__init__.py @@ -35,6 +35,7 @@ AlarmControlPanel = alarm_control_panel_ns.class_("AlarmControlPanel", cg.Entity StateAnyForwarder = alarm_control_panel_ns.class_("StateAnyForwarder") StateEnterForwarder = alarm_control_panel_ns.class_("StateEnterForwarder") +AlarmControlPanelState = alarm_control_panel_ns.enum("AlarmControlPanelState") ArmAwayAction = alarm_control_panel_ns.class_("ArmAwayAction", automation.Action) ArmHomeAction = alarm_control_panel_ns.class_("ArmHomeAction", automation.Action) @@ -117,13 +118,13 @@ async def setup_alarm_control_panel_core_(var, config): var, "add_on_state_callback", [], conf, forwarder=StateAnyForwarder ) _STATE_ENTER_MAP = { - CONF_ON_TRIGGERED: "ACP_STATE_TRIGGERED", - CONF_ON_ARMING: "ACP_STATE_ARMING", - CONF_ON_PENDING: "ACP_STATE_PENDING", - CONF_ON_ARMED_HOME: "ACP_STATE_ARMED_HOME", - CONF_ON_ARMED_NIGHT: "ACP_STATE_ARMED_NIGHT", - CONF_ON_ARMED_AWAY: "ACP_STATE_ARMED_AWAY", - CONF_ON_DISARMED: "ACP_STATE_DISARMED", + CONF_ON_TRIGGERED: AlarmControlPanelState.ACP_STATE_TRIGGERED, + CONF_ON_ARMING: AlarmControlPanelState.ACP_STATE_ARMING, + CONF_ON_PENDING: AlarmControlPanelState.ACP_STATE_PENDING, + CONF_ON_ARMED_HOME: AlarmControlPanelState.ACP_STATE_ARMED_HOME, + CONF_ON_ARMED_NIGHT: AlarmControlPanelState.ACP_STATE_ARMED_NIGHT, + CONF_ON_ARMED_AWAY: AlarmControlPanelState.ACP_STATE_ARMED_AWAY, + CONF_ON_DISARMED: AlarmControlPanelState.ACP_STATE_DISARMED, } for conf_key, state_enum in _STATE_ENTER_MAP.items(): for conf in config.get(conf_key, []): @@ -132,7 +133,7 @@ async def setup_alarm_control_panel_core_(var, config): "add_on_state_callback", [], conf, - forwarder=StateEnterForwarder.template(cg.RawExpression(state_enum)), + forwarder=StateEnterForwarder.template(state_enum), ) for conf in config.get(CONF_ON_CLEARED, []): await automation.build_callback_automation( From 1014858855e2f831bd58c4e7b9f115a073425ca9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 26 Mar 2026 19:17:06 -1000 Subject: [PATCH 4/4] Fix stale comment about state callback contract --- esphome/components/alarm_control_panel/alarm_control_panel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/alarm_control_panel/alarm_control_panel.cpp b/esphome/components/alarm_control_panel/alarm_control_panel.cpp index 26921be13d3..fc72c13ce30 100644 --- a/esphome/components/alarm_control_panel/alarm_control_panel.cpp +++ b/esphome/components/alarm_control_panel/alarm_control_panel.cpp @@ -35,7 +35,7 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) { LOG_STR_ARG(alarm_control_panel_state_to_string(state)), LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state))); this->current_state_ = state; - // Single state callback - triggers check get_state() for specific states + // Single state callback - listeners receive the new state as an argument this->state_callback_.call(state); #if defined(USE_ALARM_CONTROL_PANEL) && defined(USE_CONTROLLER_REGISTRY) ControllerRegistry::notify_alarm_control_panel_update(this);