From 263fff0ba2fc5ea7b9c849da88600f17852a86aa Mon Sep 17 00:00:00 2001 From: schrob <83939986+schdro@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:35:00 +0100 Subject: [PATCH 1/7] Move CONF_OUTPUT_POWER into const.py (#14201) --- esphome/components/cc1101/__init__.py | 2 +- esphome/components/wifi/__init__.py | 2 +- esphome/const.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/cc1101/__init__.py b/esphome/components/cc1101/__init__.py index 14b92a18a4..e2e5986daf 100644 --- a/esphome/components/cc1101/__init__.py +++ b/esphome/components/cc1101/__init__.py @@ -9,6 +9,7 @@ from esphome.const import ( CONF_DATA, CONF_FREQUENCY, CONF_ID, + CONF_OUTPUT_POWER, CONF_VALUE, CONF_WAIT_TIME, ) @@ -22,7 +23,6 @@ ns = cg.esphome_ns.namespace("cc1101") CC1101Component = ns.class_("CC1101Component", cg.Component, spi.SPIDevice) # Config keys -CONF_OUTPUT_POWER = "output_power" CONF_RX_ATTENUATION = "rx_attenuation" CONF_DC_BLOCKING_FILTER = "dc_blocking_filter" CONF_IF_FREQUENCY = "if_frequency" diff --git a/esphome/components/wifi/__init__.py b/esphome/components/wifi/__init__.py index b89245b10e..2aa63b87cc 100644 --- a/esphome/components/wifi/__init__.py +++ b/esphome/components/wifi/__init__.py @@ -42,6 +42,7 @@ from esphome.const import ( CONF_ON_CONNECT, CONF_ON_DISCONNECT, CONF_ON_ERROR, + CONF_OUTPUT_POWER, CONF_PASSWORD, CONF_POWER_SAVE_MODE, CONF_PRIORITY, @@ -344,7 +345,6 @@ def _validate(config): return config -CONF_OUTPUT_POWER = "output_power" CONF_PASSIVE_SCAN = "passive_scan" CONFIG_SCHEMA = cv.All( cv.Schema( diff --git a/esphome/const.py b/esphome/const.py index 0179aa129e..ccc9d56dbb 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -748,6 +748,7 @@ CONF_OTA = "ota" CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature" CONF_OUTPUT = "output" CONF_OUTPUT_ID = "output_id" +CONF_OUTPUT_POWER = "output_power" CONF_OUTPUT_SPEAKER = "output_speaker" CONF_OUTPUTS = "outputs" CONF_OVERSAMPLING = "oversampling" From 6e70987451dfce381645e06ec61e87fab745b900 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Feb 2026 21:35:30 -0600 Subject: [PATCH 2/7] [binary_sensor] Conditionally compile filter infrastructure (#14215) --- esphome/components/binary_sensor/__init__.py | 1 + esphome/components/binary_sensor/binary_sensor.cpp | 6 ++++++ esphome/components/binary_sensor/binary_sensor.h | 6 ++++++ esphome/components/binary_sensor/filter.cpp | 5 +++++ esphome/components/binary_sensor/filter.h | 5 +++++ esphome/core/defines.h | 1 + 6 files changed, 24 insertions(+) diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py index c38d6b78d3..4500168cb1 100644 --- a/esphome/components/binary_sensor/__init__.py +++ b/esphome/components/binary_sensor/__init__.py @@ -562,6 +562,7 @@ async def setup_binary_sensor_core_(var, config): if inverted := config.get(CONF_INVERTED): cg.add(var.set_inverted(inverted)) if filters_config := config.get(CONF_FILTERS): + cg.add_define("USE_BINARY_SENSOR_FILTER") filters = await cg.build_registry_list(FILTER_REGISTRY, filters_config) cg.add(var.add_filters(filters)) diff --git a/esphome/components/binary_sensor/binary_sensor.cpp b/esphome/components/binary_sensor/binary_sensor.cpp index 7c3b06970d..c4d3a29a1e 100644 --- a/esphome/components/binary_sensor/binary_sensor.cpp +++ b/esphome/components/binary_sensor/binary_sensor.cpp @@ -18,11 +18,15 @@ void log_binary_sensor(const char *tag, const char *prefix, const char *type, Bi } void BinarySensor::publish_state(bool new_state) { +#ifdef USE_BINARY_SENSOR_FILTER if (this->filter_list_ == nullptr) { +#endif this->send_state_internal(new_state); +#ifdef USE_BINARY_SENSOR_FILTER } else { this->filter_list_->input(new_state); } +#endif } void BinarySensor::publish_initial_state(bool new_state) { this->invalidate_state(); @@ -47,6 +51,7 @@ bool BinarySensor::set_new_state(const optional &new_state) { return false; } +#ifdef USE_BINARY_SENSOR_FILTER void BinarySensor::add_filter(Filter *filter) { filter->parent_ = this; if (this->filter_list_ == nullptr) { @@ -63,6 +68,7 @@ void BinarySensor::add_filters(std::initializer_list filters) { this->add_filter(filter); } } +#endif // USE_BINARY_SENSOR_FILTER bool BinarySensor::is_status_binary_sensor() const { return false; } } // namespace esphome::binary_sensor diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index 83c992bfed..4b655e1bd1 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -2,7 +2,9 @@ #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" +#ifdef USE_BINARY_SENSOR_FILTER #include "esphome/components/binary_sensor/filter.h" +#endif #include @@ -45,8 +47,10 @@ class BinarySensor : public StatefulEntityBase, public EntityBase_DeviceCl */ void publish_initial_state(bool new_state); +#ifdef USE_BINARY_SENSOR_FILTER void add_filter(Filter *filter); void add_filters(std::initializer_list filters); +#endif // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) @@ -60,7 +64,9 @@ class BinarySensor : public StatefulEntityBase, public EntityBase_DeviceCl bool state{}; protected: +#ifdef USE_BINARY_SENSOR_FILTER Filter *filter_list_{nullptr}; +#endif bool set_new_state(const optional &new_state) override; }; diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp index d69671c5bf..25a69c413a 100644 --- a/esphome/components/binary_sensor/filter.cpp +++ b/esphome/components/binary_sensor/filter.cpp @@ -1,3 +1,6 @@ +#include "esphome/core/defines.h" +#ifdef USE_BINARY_SENSOR_FILTER + #include "filter.h" #include "binary_sensor.h" @@ -142,3 +145,5 @@ optional SettleFilter::new_value(bool value) { float SettleFilter::get_setup_priority() const { return setup_priority::HARDWARE; } } // namespace esphome::binary_sensor + +#endif // USE_BINARY_SENSOR_FILTER diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h index 59bc43eeba..2735a32ab0 100644 --- a/esphome/components/binary_sensor/filter.h +++ b/esphome/components/binary_sensor/filter.h @@ -1,5 +1,8 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_BINARY_SENSOR_FILTER + #include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" @@ -138,3 +141,5 @@ class SettleFilter : public Filter, public Component { }; } // namespace esphome::binary_sensor + +#endif // USE_BINARY_SENSOR_FILTER diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 1128df94f0..99e80785ec 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -29,6 +29,7 @@ #define USE_ALARM_CONTROL_PANEL #define USE_AREAS #define USE_BINARY_SENSOR +#define USE_BINARY_SENSOR_FILTER #define USE_BUTTON #define USE_CAMERA #define USE_CLIMATE From 93ce582ad30d1059cf59335882a6bd231a93127e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Feb 2026 21:35:51 -0600 Subject: [PATCH 3/7] [sensor] Conditionally compile filter infrastructure (#14214) Co-authored-by: Claude Opus 4.6 --- esphome/components/bme680_bsec/bme680_bsec.h | 1 + esphome/components/haier/hon_climate.h | 1 + esphome/components/kamstrup_kmp/kamstrup_kmp.h | 1 + esphome/components/sensor/__init__.py | 1 + esphome/components/sensor/filter.cpp | 5 +++++ esphome/components/sensor/filter.h | 6 +++++- esphome/components/sensor/sensor.cpp | 6 ++++++ esphome/components/sensor/sensor.h | 8 ++++++++ esphome/components/sound_level/sound_level.h | 1 + esphome/components/wireguard/wireguard.h | 1 + esphome/core/defines.h | 1 + 11 files changed, 31 insertions(+), 1 deletion(-) diff --git a/esphome/components/bme680_bsec/bme680_bsec.h b/esphome/components/bme680_bsec/bme680_bsec.h index ec919f31df..22aa2789e6 100644 --- a/esphome/components/bme680_bsec/bme680_bsec.h +++ b/esphome/components/bme680_bsec/bme680_bsec.h @@ -7,6 +7,7 @@ #include "esphome/core/preferences.h" #include "esphome/core/defines.h" #include +#include #ifdef USE_BSEC #include diff --git a/esphome/components/haier/hon_climate.h b/esphome/components/haier/hon_climate.h index 608d5e7f21..4565ed2981 100644 --- a/esphome/components/haier/hon_climate.h +++ b/esphome/components/haier/hon_climate.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" #endif diff --git a/esphome/components/kamstrup_kmp/kamstrup_kmp.h b/esphome/components/kamstrup_kmp/kamstrup_kmp.h index f84e360132..725cf20abf 100644 --- a/esphome/components/kamstrup_kmp/kamstrup_kmp.h +++ b/esphome/components/kamstrup_kmp/kamstrup_kmp.h @@ -1,5 +1,6 @@ #pragma once +#include #include "esphome/components/sensor/sensor.h" #include "esphome/components/uart/uart.h" #include "esphome/core/component.h" diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index ebbe0fbccc..b0e0c28bda 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -903,6 +903,7 @@ async def setup_sensor_core_(var, config): if config[CONF_FORCE_UPDATE]: cg.add(var.set_force_update(True)) if config.get(CONF_FILTERS): # must exist and not be empty + cg.add_define("USE_SENSOR_FILTER") filters = await build_filters(config[CONF_FILTERS]) cg.add(var.set_filters(filters)) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index ea0e2f0d7c..cd4db98457 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -1,3 +1,6 @@ +#include "esphome/core/defines.h" +#ifdef USE_SENSOR_FILTER + #include "filter.h" #include #include "esphome/core/application.h" @@ -580,3 +583,5 @@ void StreamingMovingAverageFilter::reset_batch() { } } // namespace esphome::sensor + +#endif // USE_SENSOR_FILTER diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index 573b916a5d..8bfcdb37cf 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -1,6 +1,8 @@ #pragma once -#include +#include "esphome/core/defines.h" +#ifdef USE_SENSOR_FILTER + #include #include #include "esphome/core/automation.h" @@ -638,3 +640,5 @@ class StreamingMovingAverageFilter : public StreamingFilter { }; } // namespace esphome::sensor + +#endif // USE_SENSOR_FILTER diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp index ae2ee3e3d1..a7af6403ef 100644 --- a/esphome/components/sensor/sensor.cpp +++ b/esphome/components/sensor/sensor.cpp @@ -68,11 +68,15 @@ void Sensor::publish_state(float state) { ESP_LOGV(TAG, "'%s': Received new state %f", this->name_.c_str(), state); +#ifdef USE_SENSOR_FILTER if (this->filter_list_ == nullptr) { +#endif this->internal_send_state_to_frontend(state); +#ifdef USE_SENSOR_FILTER } else { this->filter_list_->input(state); } +#endif } void Sensor::add_on_state_callback(std::function &&callback) { this->callback_.add(std::move(callback)); } @@ -80,6 +84,7 @@ void Sensor::add_on_raw_state_callback(std::function &&callback) { this->raw_callback_.add(std::move(callback)); } +#ifdef USE_SENSOR_FILTER void Sensor::add_filter(Filter *filter) { // inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of // filters @@ -109,6 +114,7 @@ void Sensor::clear_filters() { } this->filter_list_ = nullptr; } +#endif // USE_SENSOR_FILTER float Sensor::get_state() const { return this->state; } float Sensor::get_raw_state() const { return this->raw_state; } diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index 80981b8e28..54e75ee2a1 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -4,13 +4,17 @@ #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" +#ifdef USE_SENSOR_FILTER #include "esphome/components/sensor/filter.h" +#endif #include #include namespace esphome::sensor { +class Sensor; + void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *obj); #define LOG_SENSOR(prefix, type, obj) log_sensor(TAG, prefix, LOG_STR_LITERAL(type), obj) @@ -67,6 +71,7 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa /// Set force update mode. void set_force_update(bool force_update) { sensor_flags_.force_update = force_update; } +#ifdef USE_SENSOR_FILTER /// Add a filter to the filter chain. Will be appended to the back. void add_filter(Filter *filter); @@ -87,6 +92,7 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa /// Clear the entire filter chain. void clear_filters(); +#endif /// Getter-syntax for .state. float get_state() const; @@ -130,7 +136,9 @@ class Sensor : public EntityBase, public EntityBase_DeviceClass, public EntityBa LazyCallbackManager raw_callback_; ///< Storage for raw state callbacks. LazyCallbackManager callback_; ///< Storage for filtered state callbacks. +#ifdef USE_SENSOR_FILTER Filter *filter_list_{nullptr}; ///< Store all active filters. +#endif // Group small members together to avoid padding int8_t accuracy_decimals_{-1}; ///< Accuracy in decimals (-1 = not set) diff --git a/esphome/components/sound_level/sound_level.h b/esphome/components/sound_level/sound_level.h index dc35f69fe2..a1021eb1e8 100644 --- a/esphome/components/sound_level/sound_level.h +++ b/esphome/components/sound_level/sound_level.h @@ -6,6 +6,7 @@ #include "esphome/components/microphone/microphone_source.h" #include "esphome/components/sensor/sensor.h" +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/ring_buffer.h" diff --git a/esphome/components/wireguard/wireguard.h b/esphome/components/wireguard/wireguard.h index e8470c75cd..c11d592cd1 100644 --- a/esphome/components/wireguard/wireguard.h +++ b/esphome/components/wireguard/wireguard.h @@ -4,6 +4,7 @@ #include #include +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/components/time/real_time_clock.h" diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 99e80785ec..ff32edff16 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -112,6 +112,7 @@ #define USE_SAFE_MODE_CALLBACK #define USE_SELECT #define USE_SENSOR +#define USE_SENSOR_FILTER #define USE_SETUP_PRIORITY_OVERRIDE #define USE_STATUS_LED #define USE_STATUS_SENSOR From d239a2400dddfb9854ea5e6c7f476002b6bf22c4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 22 Feb 2026 21:36:21 -0600 Subject: [PATCH 4/7] [text_sensor] Conditionally compile filter infrastructure (#14213) --- esphome/components/text_sensor/__init__.py | 1 + esphome/components/text_sensor/filter.cpp | 5 +++++ esphome/components/text_sensor/filter.h | 5 +++++ esphome/components/text_sensor/text_sensor.cpp | 18 +++++++++++++----- esphome/components/text_sensor/text_sensor.h | 8 ++++++++ esphome/core/defines.h | 1 + 6 files changed, 33 insertions(+), 5 deletions(-) diff --git a/esphome/components/text_sensor/__init__.py b/esphome/components/text_sensor/__init__.py index 0d22400a8e..2e8edb43c9 100644 --- a/esphome/components/text_sensor/__init__.py +++ b/esphome/components/text_sensor/__init__.py @@ -204,6 +204,7 @@ async def setup_text_sensor_core_(var, config): cg.add(var.set_device_class(device_class)) if config.get(CONF_FILTERS): # must exist and not be empty + cg.add_define("USE_TEXT_SENSOR_FILTER") filters = await build_filters(config[CONF_FILTERS]) cg.add(var.set_filters(filters)) diff --git a/esphome/components/text_sensor/filter.cpp b/esphome/components/text_sensor/filter.cpp index 4ee12e8602..f6552c7c66 100644 --- a/esphome/components/text_sensor/filter.cpp +++ b/esphome/components/text_sensor/filter.cpp @@ -1,3 +1,6 @@ +#include "esphome/core/defines.h" +#ifdef USE_TEXT_SENSOR_FILTER + #include "filter.h" #include "text_sensor.h" #include "esphome/core/log.h" @@ -106,3 +109,5 @@ bool MapFilter::new_value(std::string &value) { } // namespace text_sensor } // namespace esphome + +#endif // USE_TEXT_SENSOR_FILTER diff --git a/esphome/components/text_sensor/filter.h b/esphome/components/text_sensor/filter.h index 1922b503ca..f88e8645cc 100644 --- a/esphome/components/text_sensor/filter.h +++ b/esphome/components/text_sensor/filter.h @@ -1,5 +1,8 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_TEXT_SENSOR_FILTER + #include "esphome/core/component.h" #include "esphome/core/helpers.h" @@ -164,3 +167,5 @@ class MapFilter : public Filter { } // namespace text_sensor } // namespace esphome + +#endif // USE_TEXT_SENSOR_FILTER diff --git a/esphome/components/text_sensor/text_sensor.cpp b/esphome/components/text_sensor/text_sensor.cpp index c48bdf4b82..c66d08ec40 100644 --- a/esphome/components/text_sensor/text_sensor.cpp +++ b/esphome/components/text_sensor/text_sensor.cpp @@ -24,7 +24,9 @@ void TextSensor::publish_state(const std::string &state) { this->publish_state(s void TextSensor::publish_state(const char *state) { this->publish_state(state, strlen(state)); } void TextSensor::publish_state(const char *state, size_t len) { +#ifdef USE_TEXT_SENSOR_FILTER if (this->filter_list_ == nullptr) { +#endif // No filters: raw_state == state, store once and use for both callbacks // Only assign if changed to avoid heap allocation if (len != this->state.size() || memcmp(state, this->state.data(), len) != 0) { @@ -33,6 +35,7 @@ void TextSensor::publish_state(const char *state, size_t len) { this->raw_callback_.call(this->state); ESP_LOGV(TAG, "'%s': Received new state %s", this->name_.c_str(), this->state.c_str()); this->notify_frontend_(); +#ifdef USE_TEXT_SENSOR_FILTER } else { // Has filters: need separate raw storage #pragma GCC diagnostic push @@ -46,8 +49,10 @@ void TextSensor::publish_state(const char *state, size_t len) { this->filter_list_->input(this->raw_state); #pragma GCC diagnostic pop } +#endif } +#ifdef USE_TEXT_SENSOR_FILTER void TextSensor::add_filter(Filter *filter) { // inefficient, but only happens once on every sensor setup and nobody's going to have massive amounts of // filters @@ -77,6 +82,7 @@ void TextSensor::clear_filters() { } this->filter_list_ = nullptr; } +#endif // USE_TEXT_SENSOR_FILTER void TextSensor::add_on_state_callback(std::function callback) { this->callback_.add(std::move(callback)); @@ -87,14 +93,16 @@ void TextSensor::add_on_raw_state_callback(std::functionstate; } const std::string &TextSensor::get_raw_state() const { - if (this->filter_list_ == nullptr) { - return this->state; // No filters, raw == filtered - } -// Suppress deprecation warning - get_raw_state() is the replacement API +#ifdef USE_TEXT_SENSOR_FILTER + if (this->filter_list_ != nullptr) { + // Suppress deprecation warning - get_raw_state() is the replacement API #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->raw_state; + return this->raw_state; #pragma GCC diagnostic pop + } +#endif + return this->state; // No filters, raw == filtered } void TextSensor::internal_send_state_to_frontend(const std::string &state) { this->internal_send_state_to_frontend(state.data(), state.size()); diff --git a/esphome/components/text_sensor/text_sensor.h b/esphome/components/text_sensor/text_sensor.h index 1352a8c1e4..97373dc716 100644 --- a/esphome/components/text_sensor/text_sensor.h +++ b/esphome/components/text_sensor/text_sensor.h @@ -3,7 +3,9 @@ #include "esphome/core/component.h" #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" +#ifdef USE_TEXT_SENSOR_FILTER #include "esphome/components/text_sensor/filter.h" +#endif #include #include @@ -11,6 +13,8 @@ namespace esphome { namespace text_sensor { +class TextSensor; + void log_text_sensor(const char *tag, const char *prefix, const char *type, TextSensor *obj); #define LOG_TEXT_SENSOR(prefix, type, obj) log_text_sensor(TAG, prefix, LOG_STR_LITERAL(type), obj) @@ -45,6 +49,7 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass { void publish_state(const char *state); void publish_state(const char *state, size_t len); +#ifdef USE_TEXT_SENSOR_FILTER /// Add a filter to the filter chain. Will be appended to the back. void add_filter(Filter *filter); @@ -56,6 +61,7 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass { /// Clear the entire filter chain. void clear_filters(); +#endif void add_on_state_callback(std::function callback); /// Add a callback that will be called every time the sensor sends a raw value. @@ -73,7 +79,9 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass { LazyCallbackManager raw_callback_; ///< Storage for raw state callbacks. LazyCallbackManager callback_; ///< Storage for filtered state callbacks. +#ifdef USE_TEXT_SENSOR_FILTER Filter *filter_list_{nullptr}; ///< Store all active filters. +#endif }; } // namespace text_sensor diff --git a/esphome/core/defines.h b/esphome/core/defines.h index ff32edff16..a1e3d1707f 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -119,6 +119,7 @@ #define USE_SWITCH #define USE_TEXT #define USE_TEXT_SENSOR +#define USE_TEXT_SENSOR_FILTER #define USE_TIME #define USE_TOUCHSCREEN #define USE_UART_DEBUGGER From 5c388a5200b65a9e4470d4f4a681e41c49517915 Mon Sep 17 00:00:00 2001 From: schrob <83939986+schdro@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:39:36 +0100 Subject: [PATCH 5/7] [openthread_info] Optimize: Devirtualize/unify (#14208) --- .../openthread_info_text_sensor.h | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/esphome/components/openthread_info/openthread_info_text_sensor.h b/esphome/components/openthread_info/openthread_info_text_sensor.h index ac5623e0c1..10e83281f0 100644 --- a/esphome/components/openthread_info/openthread_info_text_sensor.h +++ b/esphome/components/openthread_info/openthread_info_text_sensor.h @@ -25,7 +25,7 @@ class OpenThreadInstancePollingComponent : public PollingComponent { virtual void update_instance(otInstance *instance) = 0; }; -class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::TextSensor { +class IPAddressOpenThreadInfo final : public PollingComponent, public text_sensor::TextSensor { public: void update() override { std::optional address = openthread::global_openthread_component->get_omr_address(); @@ -48,7 +48,7 @@ class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::Tex std::string last_ip_; }; -class RoleOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { +class RoleOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { public: void update_instance(otInstance *instance) override { otDeviceRole role = otThreadGetDeviceRole(instance); @@ -64,7 +64,7 @@ class RoleOpenThreadInfo : public OpenThreadInstancePollingComponent, public tex otDeviceRole last_role_; }; -class Rloc16OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { +class Rloc16OpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { public: void update_instance(otInstance *instance) override { uint16_t rloc16 = otThreadGetRloc16(instance); @@ -75,14 +75,13 @@ class Rloc16OpenThreadInfo : public OpenThreadInstancePollingComponent, public t this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: uint16_t last_rloc16_; }; -class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { +class ExtAddrOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { public: void update_instance(otInstance *instance) override { const auto *extaddr = otLinkGetExtendedAddress(instance); @@ -93,14 +92,13 @@ class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: std::array last_extaddr_{}; }; -class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { +class Eui64OpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { public: void update_instance(otInstance *instance) override { otExtAddress addr; @@ -113,14 +111,13 @@ class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public te this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: std::array last_eui64_{}; }; -class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { +class ChannelOpenThreadInfo final : public OpenThreadInstancePollingComponent, public text_sensor::TextSensor { public: void update_instance(otInstance *instance) override { uint8_t channel = otLinkGetChannel(instance); @@ -131,7 +128,6 @@ class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: @@ -153,7 +149,7 @@ class DatasetOpenThreadInfo : public OpenThreadInstancePollingComponent { virtual void update_dataset(otOperationalDataset *dataset) = 0; }; -class NetworkNameOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { +class NetworkNameOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor { public: void update_dataset(otOperationalDataset *dataset) override { if (this->last_network_name_ != dataset->mNetworkName.m8) { @@ -161,14 +157,13 @@ class NetworkNameOpenThreadInfo : public DatasetOpenThreadInfo, public text_sens this->publish_state(this->last_network_name_); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: std::string last_network_name_; }; -class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { +class NetworkKeyOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor { public: void update_dataset(otOperationalDataset *dataset) override { if (!std::equal(this->last_key_.begin(), this->last_key_.end(), dataset->mNetworkKey.m8)) { @@ -178,14 +173,13 @@ class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_senso this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: std::array last_key_{}; }; -class PanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { +class PanIdOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor { public: void update_dataset(otOperationalDataset *dataset) override { uint16_t panid = dataset->mPanId; @@ -196,14 +190,13 @@ class PanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::Te this->publish_state(buf); } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: uint16_t last_panid_; }; -class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor::TextSensor { +class ExtPanIdOpenThreadInfo final : public DatasetOpenThreadInfo, public text_sensor::TextSensor { public: void update_dataset(otOperationalDataset *dataset) override { if (!std::equal(this->last_extpanid_.begin(), this->last_extpanid_.end(), dataset->mExtendedPanId.m8)) { @@ -214,7 +207,6 @@ class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor: } } - float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } void dump_config() override; protected: From 680160453355210018b073e0036c256d45a143ce Mon Sep 17 00:00:00 2001 From: schrob <83939986+schdro@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:40:40 +0100 Subject: [PATCH 6/7] [openthread] Add Thread version DEBUG trace (#14196) --- esphome/components/openthread/openthread_esp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/openthread/openthread_esp.cpp b/esphome/components/openthread/openthread_esp.cpp index ec212d1f68..4f8db0634a 100644 --- a/esphome/components/openthread/openthread_esp.cpp +++ b/esphome/components/openthread/openthread_esp.cpp @@ -104,6 +104,8 @@ void OpenThreadComponent::ot_main() { esp_cli_custom_command_init(); #endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION + ESP_LOGD(TAG, "Thread Version: %" PRIu16, otThreadGetVersion()); + otLinkModeConfig link_mode_config{}; #if CONFIG_OPENTHREAD_FTD link_mode_config.mRxOnWhenIdle = true; From ee94bc471541a460c989b51cf317530b7ffa4611 Mon Sep 17 00:00:00 2001 From: schrob <83939986+schdro@users.noreply.github.com> Date: Mon, 23 Feb 2026 04:43:42 +0100 Subject: [PATCH 7/7] [openthread] Refactor to optimize and match code rules (#14156) --- esphome/components/openthread/openthread.cpp | 4 +-- esphome/components/openthread/openthread.h | 10 +++---- .../components/openthread/openthread_esp.cpp | 29 ++++++++++--------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/esphome/components/openthread/openthread.cpp b/esphome/components/openthread/openthread.cpp index 90da17e2d3..d22a14aeae 100644 --- a/esphome/components/openthread/openthread.cpp +++ b/esphome/components/openthread/openthread.cpp @@ -35,9 +35,9 @@ void OpenThreadComponent::dump_config() { #elif CONFIG_OPENTHREAD_MTD ESP_LOGCONFIG(TAG, " Device Type: MTD"); // TBD: Synchronized Sleepy End Device - if (this->poll_period > 0) { + if (this->poll_period_ > 0) { ESP_LOGCONFIG(TAG, " Device is configured as Sleepy End Device (SED)"); - uint32_t duration = this->poll_period / 1000; + uint32_t duration = this->poll_period_ / 1000; ESP_LOGCONFIG(TAG, " Poll Period: %" PRIu32 "s", duration); } else { ESP_LOGCONFIG(TAG, " Device is configured as Minimal End Device (MED)"); diff --git a/esphome/components/openthread/openthread.h b/esphome/components/openthread/openthread.h index 3c60acaadd..9e429f289b 100644 --- a/esphome/components/openthread/openthread.h +++ b/esphome/components/openthread/openthread.h @@ -36,22 +36,22 @@ class OpenThreadComponent : public Component { const char *get_use_address() const; void set_use_address(const char *use_address); #if CONFIG_OPENTHREAD_MTD - void set_poll_period(uint32_t poll_period) { this->poll_period = poll_period; } + void set_poll_period(uint32_t poll_period) { this->poll_period_ = poll_period; } #endif protected: std::optional get_omr_address_(InstanceLock &lock); + std::function factory_reset_external_callback_; +#if CONFIG_OPENTHREAD_MTD + uint32_t poll_period_{0}; +#endif bool teardown_started_{false}; bool teardown_complete_{false}; - std::function factory_reset_external_callback_; private: // Stores a pointer to a string literal (static storage duration). // ONLY set from Python-generated code with string literals - never dynamic strings. const char *use_address_{""}; -#if CONFIG_OPENTHREAD_MTD - uint32_t poll_period{0}; -#endif }; extern OpenThreadComponent *global_openthread_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/esphome/components/openthread/openthread_esp.cpp b/esphome/components/openthread/openthread_esp.cpp index 4f8db0634a..bb70701471 100644 --- a/esphome/components/openthread/openthread_esp.cpp +++ b/esphome/components/openthread/openthread_esp.cpp @@ -81,9 +81,11 @@ void OpenThreadComponent::ot_main() { // Initialize the OpenThread stack // otLoggingSetLevel(OT_LOG_LEVEL_DEBG); ESP_ERROR_CHECK(esp_openthread_init(&config)); + // Fetch OT instance once to avoid repeated call into OT stack + otInstance *instance = esp_openthread_get_instance(); #if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE - ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance())); + ESP_ERROR_CHECK(esp_openthread_state_indicator_init(instance)); #endif #if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC @@ -112,28 +114,29 @@ void OpenThreadComponent::ot_main() { link_mode_config.mDeviceType = true; link_mode_config.mNetworkData = true; #elif CONFIG_OPENTHREAD_MTD - if (this->poll_period > 0) { - if (otLinkSetPollPeriod(esp_openthread_get_instance(), this->poll_period) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to set OpenThread pollperiod."); + if (this->poll_period_ > 0) { + if (otLinkSetPollPeriod(instance, this->poll_period_) != OT_ERROR_NONE) { + ESP_LOGE(TAG, "Failed to set pollperiod"); } - uint32_t link_polling_period = otLinkGetPollPeriod(esp_openthread_get_instance()); - ESP_LOGD(TAG, "Link Polling Period: %" PRIu32, link_polling_period); + ESP_LOGD(TAG, "Link Polling Period: %" PRIu32, otLinkGetPollPeriod(instance)); } - link_mode_config.mRxOnWhenIdle = this->poll_period == 0; + link_mode_config.mRxOnWhenIdle = this->poll_period_ == 0; link_mode_config.mDeviceType = false; link_mode_config.mNetworkData = false; #endif - if (otThreadSetLinkMode(esp_openthread_get_instance(), link_mode_config) != OT_ERROR_NONE) { - ESP_LOGE(TAG, "Failed to set OpenThread linkmode."); + if (otThreadSetLinkMode(instance, link_mode_config) != OT_ERROR_NONE) { + ESP_LOGE(TAG, "Failed to set linkmode"); } - link_mode_config = otThreadGetLinkMode(esp_openthread_get_instance()); +#ifdef ESPHOME_LOG_HAS_DEBUG // Fetch link mode from OT only when DEBUG + link_mode_config = otThreadGetLinkMode(instance); ESP_LOGD(TAG, "Link Mode Device Type: %s\n" "Link Mode Network Data: %s\n" "Link Mode RX On When Idle: %s", - link_mode_config.mDeviceType ? "true" : "false", link_mode_config.mNetworkData ? "true" : "false", - link_mode_config.mRxOnWhenIdle ? "true" : "false"); + TRUEFALSE(link_mode_config.mDeviceType), TRUEFALSE(link_mode_config.mNetworkData), + TRUEFALSE(link_mode_config.mRxOnWhenIdle)); +#endif // Run the main loop #if CONFIG_OPENTHREAD_CLI @@ -144,7 +147,7 @@ void OpenThreadComponent::ot_main() { #ifndef USE_OPENTHREAD_FORCE_DATASET // Check if openthread has a valid dataset from a previous execution - otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); + otError error = otDatasetGetActiveTlvs(instance, &dataset); if (error != OT_ERROR_NONE) { // Make sure the length is 0 so we fallback to the configuration dataset.mLength = 0;