16static const char *
const TAG =
"scheduler";
25static constexpr size_t MAX_POOL_SIZE = 5;
30static constexpr uint32_t MAX_LOGICALLY_DELETED_ITEMS = 5;
32static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
34static constexpr uint32_t MAX_INTERVAL_DELAY = 5000;
36#if defined(ESPHOME_LOG_HAS_VERBOSE) || defined(ESPHOME_DEBUG_SCHEDULER)
40struct SchedulerNameLog {
45 const char *format(Scheduler::NameType name_type,
const char *static_name, uint32_t hash_or_id) {
46 using NameType = Scheduler::NameType;
47 if (name_type == NameType::STATIC_STRING) {
51 ESPHOME_strncpy_P(buffer, ESPHOME_PSTR(
"(null)"),
sizeof(buffer));
53 }
else if (name_type == NameType::HASHED_STRING) {
54 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"hash:0x%08" PRIX32), hash_or_id);
56 }
else if (name_type == NameType::NUMERIC_ID) {
57 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"id:%" PRIu32), hash_or_id);
60 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"iid:%" PRIu32), hash_or_id);
70#ifdef ESPHOME_DEBUG_SCHEDULER
72static void validate_static_string(
const char *name) {
78 uintptr_t addr =
reinterpret_cast<uintptr_t
>(name);
82 uintptr_t stack_addr =
reinterpret_cast<uintptr_t
>(&stack_var);
86 if (addr > (stack_addr - 0x2000) && addr < (stack_addr + 0x2000)) {
88 "WARNING: Scheduler name '%s' at %p appears to be on the stack - this is unsafe!\n"
89 " Stack reference at %p",
90 name, name, &stack_var);
95 static const char *static_str =
"test";
96 uintptr_t static_addr =
reinterpret_cast<uintptr_t
>(static_str);
99 if (addr > static_addr + 0x100000 || (static_addr > 0x100000 && addr < static_addr - 0x100000)) {
100 ESP_LOGW(TAG,
"WARNING: Scheduler name '%s' at %p might be on heap (static ref at %p)", name, name, static_str);
113uint32_t Scheduler::calculate_interval_offset_(uint32_t
delay) {
120bool Scheduler::is_retry_cancelled_locked_(Component *
component, NameType name_type,
const char *static_name,
121 uint32_t hash_or_id) {
122 return has_cancelled_timeout_in_container_locked_(this->items_,
component, name_type, static_name, hash_or_id,
124 has_cancelled_timeout_in_container_locked_(this->to_add_,
component, name_type, static_name, hash_or_id,
130void HOT Scheduler::set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
131 const char *static_name, uint32_t hash_or_id, uint32_t
delay,
132 std::function<
void()> func,
bool is_retry,
bool skip_cancel) {
133 if (
delay == SCHEDULER_DONT_RUN) {
136 LockGuard guard{this->lock_};
137 this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type);
143 const uint64_t now = this->millis_64_(
millis());
146 LockGuard guard{this->lock_};
149 auto item = this->get_item_from_pool_locked_();
151 item->set_name(name_type, static_name, hash_or_id);
153 item->callback = std::move(func);
155 this->set_item_removed_(item.get(),
false);
156 item->is_retry = is_retry;
160 auto *target = &this->to_add_;
162#ifndef ESPHOME_THREAD_SINGLE
165 if (
delay == 0 &&
type == SchedulerItem::TIMEOUT) {
167 target = &this->defer_queue_;
172 if (
type == SchedulerItem::INTERVAL) {
173 item->interval =
delay;
176 item->set_next_execution(now + offset);
177#ifdef ESPHOME_LOG_HAS_VERBOSE
178 SchedulerNameLog name_log;
179 ESP_LOGV(TAG,
"Scheduler interval for %s is %" PRIu32
"ms, offset %" PRIu32
"ms",
180 name_log.format(name_type, static_name, hash_or_id),
delay, offset);
184 item->set_next_execution(now +
delay);
187#ifdef ESPHOME_DEBUG_SCHEDULER
188 this->debug_log_timer_(item.get(), name_type, static_name, hash_or_id,
type,
delay, now);
193 if (is_retry && (name_type != NameType::STATIC_STRING || static_name !=
nullptr) &&
194 type == SchedulerItem::TIMEOUT &&
195 this->is_retry_cancelled_locked_(
component, name_type, static_name, hash_or_id)) {
197#ifdef ESPHOME_DEBUG_SCHEDULER
198 SchedulerNameLog skip_name_log;
199 ESP_LOGD(TAG,
"Skipping retry '%s' - found cancelled item",
200 skip_name_log.format(name_type, static_name, hash_or_id));
208 this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type);
210 target->push_back(std::move(item));
213void HOT Scheduler::set_timeout(Component *
component,
const char *name, uint32_t timeout, std::function<
void()> func) {
214 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::STATIC_STRING, name, 0, timeout,
218void HOT Scheduler::set_timeout(Component *
component,
const std::string &name, uint32_t timeout,
219 std::function<
void()> func) {
220 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name),
221 timeout, std::move(func));
223void HOT Scheduler::set_timeout(Component *
component, uint32_t
id, uint32_t timeout, std::function<
void()> func) {
224 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID,
nullptr,
id, timeout,
227bool HOT Scheduler::cancel_timeout(Component *
component,
const std::string &name) {
228 return this->cancel_item_(
component, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name), SchedulerItem::TIMEOUT);
230bool HOT Scheduler::cancel_timeout(Component *
component,
const char *name) {
231 return this->cancel_item_(
component, NameType::STATIC_STRING, name, 0, SchedulerItem::TIMEOUT);
233bool HOT Scheduler::cancel_timeout(Component *
component, uint32_t
id) {
234 return this->cancel_item_(
component, NameType::NUMERIC_ID,
nullptr,
id, SchedulerItem::TIMEOUT);
236void HOT Scheduler::set_interval(Component *
component,
const std::string &name, uint32_t interval,
237 std::function<
void()> func) {
238 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name),
239 interval, std::move(func));
242void HOT Scheduler::set_interval(Component *
component,
const char *name, uint32_t interval,
243 std::function<
void()> func) {
244 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::STATIC_STRING, name, 0, interval,
247void HOT Scheduler::set_interval(Component *
component, uint32_t
id, uint32_t interval, std::function<
void()> func) {
248 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID,
nullptr,
id, interval,
251bool HOT Scheduler::cancel_interval(Component *
component,
const std::string &name) {
252 return this->cancel_item_(
component, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name), SchedulerItem::INTERVAL);
254bool HOT Scheduler::cancel_interval(Component *
component,
const char *name) {
255 return this->cancel_item_(
component, NameType::STATIC_STRING, name, 0, SchedulerItem::INTERVAL);
257bool HOT Scheduler::cancel_interval(Component *
component, uint32_t
id) {
258 return this->cancel_item_(
component, NameType::NUMERIC_ID,
nullptr,
id, SchedulerItem::INTERVAL);
263#pragma GCC diagnostic push
264#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
270 Scheduler *scheduler;
273 const char *static_name;
277 float backoff_increase_factor;
278 Scheduler::NameType name_type;
279 uint8_t retry_countdown;
283 RetryResult const retry_result = args->func(--args->retry_countdown);
289 const char *static_name = (args->name_type == Scheduler::NameType::STATIC_STRING) ? args->name_.static_name :
nullptr;
290 uint32_t hash_or_id = (args->name_type != Scheduler::NameType::STATIC_STRING) ? args->name_.hash_or_id : 0;
291 args->scheduler->set_timer_common_(
292 args->component, Scheduler::SchedulerItem::TIMEOUT, args->name_type, static_name, hash_or_id,
293 args->current_interval, [args]() { retry_handler(args); },
296 args->current_interval *= args->backoff_increase_factor;
299void HOT Scheduler::set_retry_common_(Component *
component, NameType name_type,
const char *static_name,
300 uint32_t hash_or_id, uint32_t initial_wait_time, uint8_t max_attempts,
301 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
302 this->cancel_retry_(
component, name_type, static_name, hash_or_id);
304 if (initial_wait_time == SCHEDULER_DONT_RUN)
307#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
309 SchedulerNameLog name_log;
310 ESP_LOGVV(TAG,
"set_retry(name='%s', initial_wait_time=%" PRIu32
", max_attempts=%u, backoff_factor=%0.1f)",
311 name_log.format(name_type, static_name, hash_or_id), initial_wait_time, max_attempts,
312 backoff_increase_factor);
316 if (backoff_increase_factor < 0.0001) {
317 ESP_LOGE(TAG,
"set_retry: backoff_factor %0.1f too small, using 1.0: %s", backoff_increase_factor,
318 (name_type == NameType::STATIC_STRING && static_name) ? static_name :
"");
319 backoff_increase_factor = 1;
322 auto args = std::make_shared<RetryArgs>();
323 args->func = std::move(func);
325 args->scheduler =
this;
326 args->name_type = name_type;
327 if (name_type == NameType::STATIC_STRING) {
328 args->name_.static_name = static_name;
330 args->name_.hash_or_id = hash_or_id;
332 args->current_interval = initial_wait_time;
334 args->retry_countdown = max_attempts;
337 this->set_timer_common_(
338 component, SchedulerItem::TIMEOUT, name_type, static_name, hash_or_id, 0, [args]() {
retry_handler(args); },
342void HOT Scheduler::set_retry(Component *
component,
const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
343 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
344 this->set_retry_common_(
component, NameType::STATIC_STRING, name, 0, initial_wait_time, max_attempts, std::move(func),
345 backoff_increase_factor);
348bool HOT Scheduler::cancel_retry_(Component *
component, NameType name_type,
const char *static_name,
349 uint32_t hash_or_id) {
350 return this->cancel_item_(
component, name_type, static_name, hash_or_id, SchedulerItem::TIMEOUT,
353bool HOT Scheduler::cancel_retry(Component *
component,
const char *name) {
354 return this->cancel_retry_(
component, NameType::STATIC_STRING, name, 0);
357void HOT Scheduler::set_retry(Component *
component,
const std::string &name, uint32_t initial_wait_time,
358 uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
359 float backoff_increase_factor) {
360 this->set_retry_common_(
component, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name), initial_wait_time,
361 max_attempts, std::move(func), backoff_increase_factor);
364bool HOT Scheduler::cancel_retry(Component *
component,
const std::string &name) {
368void HOT Scheduler::set_retry(Component *
component, uint32_t
id, uint32_t initial_wait_time, uint8_t max_attempts,
369 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
370 this->set_retry_common_(
component, NameType::NUMERIC_ID,
nullptr,
id, initial_wait_time, max_attempts,
371 std::move(func), backoff_increase_factor);
374bool HOT Scheduler::cancel_retry(Component *
component, uint32_t
id) {
375 return this->cancel_retry_(
component, NameType::NUMERIC_ID,
nullptr,
id);
378#pragma GCC diagnostic pop
380optional<uint32_t> HOT Scheduler::next_schedule_in(uint32_t now) {
386 if (this->cleanup_() == 0)
389 auto &item = this->items_[0];
391 const auto now_64 = this->millis_64_(now);
392 const uint64_t next_exec = item->get_next_execution();
393 if (next_exec < now_64)
395 return next_exec - now_64;
398void Scheduler::full_cleanup_removed_items_() {
404 LockGuard guard{this->lock_};
408 for (
size_t read = 0; read < this->items_.size(); ++read) {
409 if (!is_item_removed_(this->items_[read].get())) {
411 this->items_[write] = std::move(this->items_[read]);
415 this->recycle_item_main_loop_(std::move(this->items_[read]));
418 this->items_.erase(this->items_.begin() + write, this->items_.end());
420 std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
421 this->to_remove_ = 0;
424void HOT Scheduler::call(uint32_t now) {
425#ifndef ESPHOME_THREAD_SINGLE
426 this->process_defer_queue_(now);
430 const auto now_64 = this->millis_64_(now);
431 this->process_to_add();
434 bool has_added_items =
false;
436#ifdef ESPHOME_DEBUG_SCHEDULER
437 static uint64_t last_print = 0;
439 if (now_64 - last_print > 2000) {
441 std::vector<std::unique_ptr<SchedulerItem>> old_items;
442#ifdef ESPHOME_THREAD_MULTI_ATOMICS
443 const auto last_dbg = this->last_millis_.load(std::memory_order_relaxed);
444 const auto major_dbg = this->millis_major_.load(std::memory_order_relaxed);
445 ESP_LOGD(TAG,
"Items: count=%zu, pool=%zu, now=%" PRIu64
" (%" PRIu16
", %" PRIu32
")", this->items_.size(),
446 this->scheduler_item_pool_.size(), now_64, major_dbg, last_dbg);
448 ESP_LOGD(TAG,
"Items: count=%zu, pool=%zu, now=%" PRIu64
" (%" PRIu16
", %" PRIu32
")", this->items_.size(),
449 this->scheduler_item_pool_.size(), now_64, this->millis_major_, this->last_millis_);
453 while (!this->items_.empty()) {
454 std::unique_ptr<SchedulerItem> item;
456 LockGuard guard{this->lock_};
457 item = this->pop_raw_locked_();
460 SchedulerNameLog name_log;
461 bool is_cancelled = is_item_removed_(item.get());
462 ESP_LOGD(TAG,
" %s '%s/%s' interval=%" PRIu32
" next_execution in %" PRIu64
"ms at %" PRIu64
"%s",
463 item->get_type_str(), LOG_STR_ARG(item->get_source()),
464 name_log.format(item->get_name_type(), item->get_name(), item->get_name_hash_or_id()), item->interval,
465 item->get_next_execution() - now_64, item->get_next_execution(), is_cancelled ?
" [CANCELLED]" :
"");
467 old_items.push_back(std::move(item));
472 LockGuard guard{this->lock_};
473 this->items_ = std::move(old_items);
475 std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
486 if (this->to_remove_ >= MAX_LOGICALLY_DELETED_ITEMS) {
487 this->full_cleanup_removed_items_();
489 while (!this->items_.empty()) {
491 auto &item = this->items_[0];
492 if (item->get_next_execution() > now_64) {
497 if (item->component !=
nullptr && item->component->is_failed()) {
498 LockGuard guard{this->lock_};
499 this->recycle_item_main_loop_(this->pop_raw_locked_());
507#ifdef ESPHOME_THREAD_MULTI_NO_ATOMICS
510 LockGuard guard{this->lock_};
511 if (is_item_removed_(item.get())) {
512 this->recycle_item_main_loop_(this->pop_raw_locked_());
519 if (is_item_removed_(item.get())) {
520 LockGuard guard{this->lock_};
521 this->recycle_item_main_loop_(this->pop_raw_locked_());
527#ifdef ESPHOME_DEBUG_SCHEDULER
529 SchedulerNameLog name_log;
530 ESP_LOGV(TAG,
"Running %s '%s/%s' with interval=%" PRIu32
" next_execution=%" PRIu64
" (now=%" PRIu64
")",
531 item->get_type_str(), LOG_STR_ARG(item->get_source()),
532 name_log.format(item->get_name_type(), item->get_name(), item->get_name_hash_or_id()), item->interval,
533 item->get_next_execution(), now_64);
540 now = this->execute_item_(item.get(), now);
542 LockGuard guard{this->lock_};
546 auto executed_item = this->pop_raw_locked_();
548 if (executed_item->remove) {
551 this->recycle_item_main_loop_(std::move(executed_item));
555 if (executed_item->type == SchedulerItem::INTERVAL) {
556 executed_item->set_next_execution(now_64 + executed_item->interval);
559 this->to_add_.push_back(std::move(executed_item));
562 this->recycle_item_main_loop_(std::move(executed_item));
565 has_added_items |= !this->to_add_.empty();
568 if (has_added_items) {
569 this->process_to_add();
572void HOT Scheduler::process_to_add() {
573 LockGuard guard{this->lock_};
574 for (
auto &it : this->to_add_) {
575 if (is_item_removed_(it.get())) {
577 this->recycle_item_main_loop_(std::move(it));
581 this->items_.push_back(std::move(it));
582 std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
584 this->to_add_.clear();
586size_t HOT Scheduler::cleanup_() {
594 if (this->to_remove_ == 0)
595 return this->items_.size();
605 LockGuard guard{this->lock_};
606 while (!this->items_.empty()) {
607 auto &item = this->items_[0];
611 this->recycle_item_main_loop_(this->pop_raw_locked_());
613 return this->items_.size();
615std::unique_ptr<Scheduler::SchedulerItem> HOT Scheduler::pop_raw_locked_() {
616 std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
619 auto item = std::move(this->items_.back());
621 this->items_.pop_back();
626uint32_t HOT Scheduler::execute_item_(SchedulerItem *item, uint32_t now) {
628 WarnIfComponentBlockingGuard guard{item->component, now};
630 return guard.finish();
634bool HOT Scheduler::cancel_item_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
635 SchedulerItem::Type
type,
bool match_retry) {
636 LockGuard guard{this->lock_};
637 return this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type, match_retry);
642bool HOT Scheduler::cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name,
643 uint32_t hash_or_id, SchedulerItem::Type
type,
bool match_retry) {
645 if (name_type == NameType::STATIC_STRING && static_name ==
nullptr) {
649 size_t total_cancelled = 0;
651#ifndef ESPHOME_THREAD_SINGLE
653 if (
type == SchedulerItem::TIMEOUT) {
654 total_cancelled += this->mark_matching_items_removed_locked_(this->defer_queue_,
component, name_type, static_name,
655 hash_or_id,
type, match_retry);
664 if (!this->items_.empty()) {
665 size_t heap_cancelled = this->mark_matching_items_removed_locked_(this->items_,
component, name_type, static_name,
666 hash_or_id,
type, match_retry);
667 total_cancelled += heap_cancelled;
668 this->to_remove_ += heap_cancelled;
672 total_cancelled += this->mark_matching_items_removed_locked_(this->to_add_,
component, name_type, static_name,
673 hash_or_id,
type, match_retry);
675 return total_cancelled > 0;
678uint64_t Scheduler::millis_64_(uint32_t now) {
693#ifdef ESPHOME_THREAD_SINGLE
699 uint16_t major = this->millis_major_;
703 if (now < last && (last - now) > HALF_MAX_UINT32) {
704 this->millis_major_++;
706 this->last_millis_ = now;
707#ifdef ESPHOME_DEBUG_SCHEDULER
708 ESP_LOGD(TAG,
"Detected true 32-bit rollover at %" PRIu32
"ms (was %" PRIu32
")", now, last);
710 }
else if (now > last) {
712 this->last_millis_ = now;
716 return now + (
static_cast<uint64_t
>(major) << 32);
718#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
726 uint16_t major = this->millis_major_;
731 static const uint32_t ROLLOVER_WINDOW = 10000;
734 bool near_rollover = (last > (std::numeric_limits<uint32_t>::max() - ROLLOVER_WINDOW)) || (now < ROLLOVER_WINDOW);
736 if (near_rollover || (now < last && (last - now) > HALF_MAX_UINT32)) {
738 LockGuard guard{this->lock_};
740 last = this->last_millis_;
742 if (now < last && (last - now) > HALF_MAX_UINT32) {
744 this->millis_major_++;
746#ifdef ESPHOME_DEBUG_SCHEDULER
747 ESP_LOGD(TAG,
"Detected true 32-bit rollover at %" PRIu32
"ms (was %" PRIu32
")", now, last);
751 this->last_millis_ = now;
752 }
else if (now > last) {
759 this->last_millis_ = now;
765 return now + (
static_cast<uint64_t
>(major) << 32);
767#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
778 uint16_t major = this->millis_major_.load(std::memory_order_acquire);
786 uint32_t last = this->last_millis_.load(std::memory_order_acquire);
790 if (now < last && (last - now) > HALF_MAX_UINT32) {
792 LockGuard guard{this->lock_};
794 last = this->last_millis_.load(std::memory_order_relaxed);
796 if (now < last && (last - now) > HALF_MAX_UINT32) {
798 this->millis_major_.fetch_add(1, std::memory_order_relaxed);
800#ifdef ESPHOME_DEBUG_SCHEDULER
801 ESP_LOGD(TAG,
"Detected true 32-bit rollover at %" PRIu32
"ms (was %" PRIu32
")", now, last);
809 this->last_millis_.store(now, std::memory_order_release);
813 while (now > last && (now - last) < HALF_MAX_UINT32) {
814 if (this->last_millis_.compare_exchange_weak(last, now,
815 std::memory_order_release,
816 std::memory_order_relaxed)) {
823 uint16_t major_end = this->millis_major_.load(std::memory_order_relaxed);
824 if (major_end == major)
825 return now + (
static_cast<uint64_t
>(major) << 32);
828 __builtin_unreachable();
832 "No platform threading model defined. One of ESPHOME_THREAD_SINGLE, ESPHOME_THREAD_MULTI_NO_ATOMICS, or ESPHOME_THREAD_MULTI_ATOMICS must be defined."
836bool HOT Scheduler::SchedulerItem::cmp(
const std::unique_ptr<SchedulerItem> &a,
837 const std::unique_ptr<SchedulerItem> &b) {
840 return (a->next_execution_high_ == b->next_execution_high_) ? (a->next_execution_low_ > b->next_execution_low_)
841 : (a->next_execution_high_ > b->next_execution_high_);
848void Scheduler::recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item) {
852 if (this->scheduler_item_pool_.size() < MAX_POOL_SIZE) {
854 item->callback =
nullptr;
855 this->scheduler_item_pool_.push_back(std::move(item));
856#ifdef ESPHOME_DEBUG_SCHEDULER
857 ESP_LOGD(TAG,
"Recycled item to pool (pool size now: %zu)", this->scheduler_item_pool_.size());
860#ifdef ESPHOME_DEBUG_SCHEDULER
861 ESP_LOGD(TAG,
"Pool full (size: %zu), deleting item", this->scheduler_item_pool_.size());
867#ifdef ESPHOME_DEBUG_SCHEDULER
868void Scheduler::debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name,
869 uint32_t hash_or_id, SchedulerItem::Type
type, uint32_t
delay, uint64_t now) {
871 if (name_type == NameType::STATIC_STRING && static_name !=
nullptr) {
872 validate_static_string(static_name);
876 SchedulerNameLog name_log;
877 const char *type_str = (
type == SchedulerItem::TIMEOUT) ?
"timeout" :
"interval";
878 if (
type == SchedulerItem::TIMEOUT) {
879 ESP_LOGD(TAG,
"set_%s(name='%s/%s', %s=%" PRIu32
")", type_str, LOG_STR_ARG(item->get_source()),
880 name_log.format(name_type, static_name, hash_or_id), type_str,
delay);
882 ESP_LOGD(TAG,
"set_%s(name='%s/%s', %s=%" PRIu32
", offset=%" PRIu32
")", type_str, LOG_STR_ARG(item->get_source()),
883 name_log.format(name_type, static_name, hash_or_id), type_str,
delay,
884 static_cast<uint32_t>(item->get_next_execution() - now));
891std::unique_ptr<Scheduler::SchedulerItem> Scheduler::get_item_from_pool_locked_() {
892 std::unique_ptr<SchedulerItem> item;
893 if (!this->scheduler_item_pool_.empty()) {
894 item = std::move(this->scheduler_item_pool_.back());
895 this->scheduler_item_pool_.pop_back();
896#ifdef ESPHOME_DEBUG_SCHEDULER
897 ESP_LOGD(TAG,
"Reused item from pool (pool size now: %zu)", this->scheduler_item_pool_.size());
900 item = make_unique<SchedulerItem>();
901#ifdef ESPHOME_DEBUG_SCHEDULER
902 ESP_LOGD(TAG,
"Allocated new item (pool empty)");
void set_current_component(Component *component)
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.", "2026.2.0") void set_retry(const std uint32_t uint8_t std::function< RetryResult(uint8_t)> float backoff_increase_factor
const Component * component
Providing packet encoding functions for exchanging data with a remote host.
float random_float()
Return a random float between 0 and 1.
void retry_handler(const std::shared_ptr< RetryArgs > &args)
void IRAM_ATTR HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.