From c1cba269b389864678ced61cb5718477d7f13645 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 18 Jan 2026 00:35:17 -1000 Subject: [PATCH] [globals] Convert restoring globals to PollingComponent to reduce CPU usage --- esphome/components/globals/__init__.py | 37 +++++++++++++------ .../components/globals/globals_component.h | 28 +++++++------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/esphome/components/globals/__init__.py b/esphome/components/globals/__init__.py index 633ccea66b..eb2948db8f 100644 --- a/esphome/components/globals/__init__.py +++ b/esphome/components/globals/__init__.py @@ -6,6 +6,7 @@ from esphome.const import ( CONF_INITIAL_VALUE, CONF_RESTORE_VALUE, CONF_TYPE, + CONF_UPDATE_INTERVAL, CONF_VALUE, ) from esphome.core import CoroPriority, coroutine_with_priority @@ -13,25 +14,37 @@ from esphome.core import CoroPriority, coroutine_with_priority CODEOWNERS = ["@esphome/core"] globals_ns = cg.esphome_ns.namespace("globals") GlobalsComponent = globals_ns.class_("GlobalsComponent", cg.Component) -RestoringGlobalsComponent = globals_ns.class_("RestoringGlobalsComponent", cg.Component) +RestoringGlobalsComponent = globals_ns.class_( + "RestoringGlobalsComponent", cg.PollingComponent +) RestoringGlobalStringComponent = globals_ns.class_( - "RestoringGlobalStringComponent", cg.Component + "RestoringGlobalStringComponent", cg.PollingComponent ) GlobalVarSetAction = globals_ns.class_("GlobalVarSetAction", automation.Action) CONF_MAX_RESTORE_DATA_LENGTH = "max_restore_data_length" +def validate_update_interval(config): + if CONF_UPDATE_INTERVAL in config and not config.get(CONF_RESTORE_VALUE, False): + raise cv.Invalid("update_interval requires restore_value to be true") + return config + + MULTI_CONF = True -CONFIG_SCHEMA = cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(GlobalsComponent), - cv.Required(CONF_TYPE): cv.string_strict, - cv.Optional(CONF_INITIAL_VALUE): cv.string_strict, - cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, - cv.Optional(CONF_MAX_RESTORE_DATA_LENGTH): cv.int_range(0, 254), - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(GlobalsComponent), + cv.Required(CONF_TYPE): cv.string_strict, + cv.Optional(CONF_INITIAL_VALUE): cv.string_strict, + cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean, + cv.Optional(CONF_MAX_RESTORE_DATA_LENGTH): cv.int_range(0, 254), + cv.Optional(CONF_UPDATE_INTERVAL): cv.update_interval, + } + ).extend(cv.COMPONENT_SCHEMA), + validate_update_interval, +) # Run with low priority so that namespaces are registered first @@ -65,6 +78,8 @@ async def to_code(config): value = value.encode() hash_ = int(hashlib.md5(value).hexdigest()[:8], 16) cg.add(glob.set_name_hash(hash_)) + if CONF_UPDATE_INTERVAL in config: + cg.add(glob.set_update_interval(config[CONF_UPDATE_INTERVAL])) @automation.register_action( diff --git a/esphome/components/globals/globals_component.h b/esphome/components/globals/globals_component.h index 1d2a08937e..3db29bea35 100644 --- a/esphome/components/globals/globals_component.h +++ b/esphome/components/globals/globals_component.h @@ -5,8 +5,7 @@ #include "esphome/core/helpers.h" #include -namespace esphome { -namespace globals { +namespace esphome::globals { template class GlobalsComponent : public Component { public: @@ -24,13 +23,14 @@ template class GlobalsComponent : public Component { T value_{}; }; -template class RestoringGlobalsComponent : public Component { +template class RestoringGlobalsComponent : public PollingComponent { public: using value_type = T; - explicit RestoringGlobalsComponent() = default; - explicit RestoringGlobalsComponent(T initial_value) : value_(initial_value) {} + explicit RestoringGlobalsComponent() : PollingComponent(1000) {} + explicit RestoringGlobalsComponent(T initial_value) : PollingComponent(1000), value_(initial_value) {} explicit RestoringGlobalsComponent( - std::array::type, std::extent::value> initial_value) { + std::array::type, std::extent::value> initial_value) + : PollingComponent(1000) { memcpy(this->value_, initial_value.data(), sizeof(T)); } @@ -44,7 +44,7 @@ template class RestoringGlobalsComponent : public Component { float get_setup_priority() const override { return setup_priority::HARDWARE; } - void loop() override { store_value_(); } + void update() override { store_value_(); } void on_shutdown() override { store_value_(); } @@ -66,13 +66,14 @@ template class RestoringGlobalsComponent : public Component { }; // Use with string or subclasses of strings -template class RestoringGlobalStringComponent : public Component { +template class RestoringGlobalStringComponent : public PollingComponent { public: using value_type = T; - explicit RestoringGlobalStringComponent() = default; - explicit RestoringGlobalStringComponent(T initial_value) { this->value_ = initial_value; } + explicit RestoringGlobalStringComponent() : PollingComponent(1000) {} + explicit RestoringGlobalStringComponent(T initial_value) : PollingComponent(1000) { this->value_ = initial_value; } explicit RestoringGlobalStringComponent( - std::array::type, std::extent::value> initial_value) { + std::array::type, std::extent::value> initial_value) + : PollingComponent(1000) { memcpy(this->value_, initial_value.data(), sizeof(T)); } @@ -90,7 +91,7 @@ template class RestoringGlobalStringComponent : public C float get_setup_priority() const override { return setup_priority::HARDWARE; } - void loop() override { store_value_(); } + void update() override { store_value_(); } void on_shutdown() override { store_value_(); } @@ -144,5 +145,4 @@ template T &id(GlobalsComponent *value) { return value->value(); template T &id(RestoringGlobalsComponent *value) { return value->value(); } template T &id(RestoringGlobalStringComponent *value) { return value->value(); } -} // namespace globals -} // namespace esphome +} // namespace esphome::globals