diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index 4feb0811c9..e8b8332902 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -35,7 +35,9 @@ static constexpr uint32_t MAX_INTERVAL_DELAY = 5000; // Uses a stack buffer to avoid heap allocation // Uses ESPHOME_snprintf_P/ESPHOME_PSTR for ESP8266 to keep format strings in flash struct SchedulerNameLog { - char buffer[20]; // Enough for "id:4294967295" or "hash:0xFFFFFFFF" or "(null)" + // Sized for the widest formatted output: "self:0x" + 16 hex digits (64-bit pointer) + nul. + // Also covers "id:4294967295", "hash:0xFFFFFFFF", "iid:4294967295", "(null)". + char buffer[28]; // Format a scheduler item name for logging // Returns pointer to formatted string (either static_name or internal buffer) @@ -58,7 +60,8 @@ struct SchedulerNameLog { return buffer; } else { // SELF_POINTER // static_name carries the void* key for SELF_POINTER (pointer-width union slot). - ESPHOME_snprintf_P(buffer, sizeof(buffer), ESPHOME_PSTR("self:%p"), static_name); + // Cast to const void* — %p requires a void* argument. + ESPHOME_snprintf_P(buffer, sizeof(buffer), ESPHOME_PSTR("self:%p"), static_cast(static_name)); return buffer; } } @@ -301,19 +304,19 @@ bool HOT Scheduler::cancel_interval(Component *component, uint32_t id) { // passed through the existing static_name pointer slot. Matching is by raw pointer equality // (see matches_item_locked_'s SELF_POINTER branch). No Component pointer is stored, so // is_failed() skip and component-based log attribution don't apply. -void HOT Scheduler::set_timeout(void *self, uint32_t timeout, std::function &&func) { +void HOT Scheduler::set_timeout(const void *self, uint32_t timeout, std::function &&func) { this->set_timer_common_(nullptr, SchedulerItem::TIMEOUT, NameType::SELF_POINTER, static_cast(self), 0, timeout, std::move(func)); } -void HOT Scheduler::set_interval(void *self, uint32_t interval, std::function &&func) { +void HOT Scheduler::set_interval(const void *self, uint32_t interval, std::function &&func) { this->set_timer_common_(nullptr, SchedulerItem::INTERVAL, NameType::SELF_POINTER, static_cast(self), 0, interval, std::move(func)); } -bool HOT Scheduler::cancel_timeout(void *self) { +bool HOT Scheduler::cancel_timeout(const void *self) { return this->cancel_item_(nullptr, NameType::SELF_POINTER, static_cast(self), 0, SchedulerItem::TIMEOUT); } -bool HOT Scheduler::cancel_interval(void *self) { +bool HOT Scheduler::cancel_interval(const void *self) { return this->cancel_item_(nullptr, NameType::SELF_POINTER, static_cast(self), 0, SchedulerItem::INTERVAL); } diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index cb75dce38a..671665f4c0 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -168,11 +168,11 @@ class Scheduler { * * If you need either of those, use the existing `(Component *, id)` overloads. */ - void set_timeout(void *self, uint32_t timeout, std::function &&func); - /// Self-keyed interval. See set_timeout(void *, ...) for semantics. - void set_interval(void *self, uint32_t interval, std::function &&func); - bool cancel_timeout(void *self); - bool cancel_interval(void *self); + void set_timeout(const void *self, uint32_t timeout, std::function &&func); + /// Self-keyed interval. See set_timeout(const void *, ...) for semantics. + void set_interval(const void *self, uint32_t interval, std::function &&func); + bool cancel_timeout(const void *self); + bool cancel_interval(const void *self); protected: struct SchedulerItem { diff --git a/tests/integration/fixtures/scheduler_self_keyed.yaml b/tests/integration/fixtures/scheduler_self_keyed.yaml index bee8a488b1..9a691136f3 100644 --- a/tests/integration/fixtures/scheduler_self_keyed.yaml +++ b/tests/integration/fixtures/scheduler_self_keyed.yaml @@ -21,8 +21,10 @@ script: then: - logger.log: "Testing self-keyed scheduler API" - lambda: |- - // Two distinct heap-allocated keys - they must not collide - // even though both are self-keyed and share no Component pointer. + // Two distinct keys backed by addresses of static markers — they + // must not collide even though both are self-keyed and share no + // Component pointer. Static storage gives them stable, unique + // addresses for the lifetime of the program. static int key_a_marker = 0; static int key_b_marker = 0; void *key_a = &key_a_marker;