8#ifdef ESPHOME_THREAD_MULTI_ATOMICS
27 friend void ::esphome::retry_handler(
const std::shared_ptr<RetryArgs> &args);
32 template<
typename... Ts>
friend class DelayAction;
37 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
38 void set_timeout(Component *
component, const std::
string &name, uint32_t timeout, std::function<
void()> &&func);
48 void set_timeout(Component *
component, const
char *name, uint32_t timeout, std::function<
void()> &&func);
50 void set_timeout(Component *
component, uint32_t
id, uint32_t timeout, std::function<
void()> &&func);
52 void set_timeout(Component *
component, InternalSchedulerID
id, uint32_t timeout, std::function<
void()> &&func) {
53 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL,
nullptr,
54 static_cast<uint32_t>(
id), timeout, std::move(func));
57 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
58 bool cancel_timeout(Component *
component, const std::
string &name);
59 bool cancel_timeout(Component *
component, const
char *name);
60 bool cancel_timeout(Component *
component, uint32_t
id);
61 bool cancel_timeout(Component *
component, InternalSchedulerID
id) {
62 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
63 SchedulerItem::TIMEOUT);
66 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
67 void set_interval(Component *
component, const std::
string &name, uint32_t interval, std::function<
void()> &&func);
77 void set_interval(Component *
component, const
char *name, uint32_t interval, std::function<
void()> &&func);
79 void set_interval(Component *
component, uint32_t
id, uint32_t interval, std::function<
void()> &&func);
81 void set_interval(Component *
component, InternalSchedulerID
id, uint32_t interval, std::function<
void()> &&func) {
82 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL,
nullptr,
83 static_cast<uint32_t>(
id), interval, std::move(func));
86 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
87 bool cancel_interval(Component *
component, const std::
string &name);
88 bool cancel_interval(Component *
component, const
char *name);
89 bool cancel_interval(Component *
component, uint32_t
id);
90 bool cancel_interval(Component *
component, InternalSchedulerID
id) {
91 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
92 SchedulerItem::INTERVAL);
96 ESPDEPRECATED(
"set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
98 void set_retry(Component *
component, const std::
string &name, uint32_t initial_wait_time, uint8_t max_attempts,
99 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
101 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
103 void set_retry(Component *
component, const
char *name, uint32_t initial_wait_time, uint8_t max_attempts,
104 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
106 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
108 void set_retry(Component *
component, uint32_t
id, uint32_t initial_wait_time, uint8_t max_attempts,
109 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
112 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
113 bool cancel_retry(Component *
component, const std::
string &name);
115 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
116 bool cancel_retry(Component *
component, const
char *name);
118 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
119 bool cancel_retry(Component *
component, uint32_t
id);
129 optional<uint32_t> next_schedule_in(uint32_t now);
133 void call(uint32_t now);
135 void process_to_add();
139 enum class NameType : uint8_t {
143 NUMERIC_ID_INTERNAL = 3
147 struct SchedulerItem;
155 struct SchedulerItemDeleter {
156 void operator()(SchedulerItem *ptr)
const noexcept;
158 using SchedulerItemPtr = std::unique_ptr<SchedulerItem, SchedulerItemDeleter>;
160 struct SchedulerItem {
165 const char *static_name;
177 std::function<void()> callback;
178 uint16_t next_execution_high_;
180#ifdef ESPHOME_THREAD_MULTI_ATOMICS
183 std::atomic<bool> remove{
false};
187 NameType name_type_ : 2;
195 NameType name_type_ : 2;
204 next_execution_low_(0),
205 next_execution_high_(0),
206#ifdef ESPHOME_THREAD_MULTI_ATOMICS
209 name_type_(NameType::STATIC_STRING),
214 name_type_(NameType::STATIC_STRING),
217 name_.static_name =
nullptr;
221 ~SchedulerItem() =
default;
224 SchedulerItem(
const SchedulerItem &) =
delete;
225 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
228 SchedulerItem(SchedulerItem &&) =
delete;
229 SchedulerItem &operator=(SchedulerItem &&) =
delete;
232 const char *get_name()
const {
return (name_type_ == NameType::STATIC_STRING) ? name_.static_name :
nullptr; }
235 uint32_t get_name_hash_or_id()
const {
return (name_type_ != NameType::STATIC_STRING) ? name_.hash_or_id : 0; }
238 NameType get_name_type()
const {
return name_type_; }
242 void set_name(NameType
type,
const char *static_name, uint32_t hash_or_id) {
243 if (
type == NameType::STATIC_STRING) {
244 name_.static_name = static_name;
246 name_.hash_or_id = hash_or_id;
251 static bool cmp(
const SchedulerItemPtr &a,
const SchedulerItemPtr &b);
256 constexpr uint64_t get_next_execution()
const {
257 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
260 constexpr void set_next_execution(uint64_t value) {
261 next_execution_low_ =
static_cast<uint32_t>(value);
264 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
266 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
267 const LogString *get_source()
const {
return component ?
component->get_component_log_str() : LOG_STR(
"unknown"); }
272 void set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
const char *static_name,
273 uint32_t hash_or_id, uint32_t delay, std::function<
void()> &&func,
bool is_retry =
false,
274 bool skip_cancel =
false);
278#pragma GCC diagnostic push
279#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
280 void set_retry_common_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
281 uint32_t initial_wait_time, uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
282 float backoff_increase_factor);
283#pragma GCC diagnostic pop
285 bool cancel_retry_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id);
290 uint64_t millis_64_from_(uint32_t now) {
291#ifdef USE_NATIVE_64BIT_TIME
295 return Millis64Impl::compute(now);
304 SchedulerItemPtr pop_raw_locked_();
307 SchedulerItemPtr get_item_from_pool_locked_();
312 bool cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
313 SchedulerItem::Type
type,
bool match_retry =
false);
316 bool cancel_item_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
317 SchedulerItem::Type
type,
bool match_retry =
false);
320 inline bool HOT names_match_static_(
const char *name1,
const char *name2)
const {
325 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
331 inline bool HOT matches_item_locked_(
const SchedulerItemPtr &item, Component *
component, NameType name_type,
332 const char *static_name, uint32_t hash_or_id, SchedulerItem::Type
type,
333 bool match_retry,
bool skip_removed =
true)
const {
343 (skip_removed && this->is_item_removed_locked_(item.get())) || (match_retry && !item->is_retry)) {
347 if (item->get_name_type() != name_type)
350 if (name_type == NameType::STATIC_STRING) {
351 return this->names_match_static_(item->get_name(), static_name);
353 return item->get_name_hash_or_id() == hash_or_id;
357 uint32_t execute_item_(SchedulerItem *item, uint32_t now);
360 bool should_skip_item_(SchedulerItem *item)
const {
361 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
368 void recycle_item_main_loop_(SchedulerItemPtr item);
371 void full_cleanup_removed_items_();
382 is_retry_cancelled_locked_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id);
384#ifdef ESPHOME_DEBUG_SCHEDULER
386 void debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name, uint32_t hash_or_id,
387 SchedulerItem::Type
type, uint32_t delay, uint64_t now);
390#ifndef ESPHOME_THREAD_SINGLE
392 inline void process_defer_queue_(uint32_t &now) {
413 size_t defer_queue_end = this->defer_queue_.size();
418 if (this->defer_queue_front_ >= defer_queue_end)
424 SchedulerItemPtr item;
427 while (this->defer_queue_front_ < defer_queue_end) {
433 item = std::move(this->defer_queue_[this->defer_queue_front_]);
434 this->defer_queue_front_++;
435 this->lock_.unlock();
439 if (!this->should_skip_item_(item.get())) {
440 now = this->execute_item_(item.get(), now);
444 this->recycle_item_main_loop_(std::move(item));
447 this->cleanup_defer_queue_locked_();
448 this->lock_.unlock();
455 inline void cleanup_defer_queue_locked_() {
457 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
459 this->defer_queue_.clear();
463 this->compact_defer_queue_locked_();
465 this->defer_queue_front_ = 0;
471 void __attribute__((noinline)) compact_defer_queue_locked_();
478 bool is_item_removed_(SchedulerItem *item)
const {
479#ifdef ESPHOME_THREAD_MULTI_ATOMICS
481 return item->remove.load(std::memory_order_acquire);
493 bool is_item_removed_locked_(SchedulerItem *item)
const {
494#ifdef ESPHOME_THREAD_MULTI_ATOMICS
496 return item->remove.load(std::memory_order_relaxed);
506 void set_item_removed_(SchedulerItem *item,
bool removed) {
507#ifdef ESPHOME_THREAD_MULTI_ATOMICS
511 item->remove.store(removed, removed ? std::memory_order_release : std::memory_order_relaxed);
516 item->remove = removed;
524 __attribute__((noinline))
size_t mark_matching_items_removed_locked_(std::vector<SchedulerItemPtr> &container,
525 Component *
component, NameType name_type,
526 const char *static_name, uint32_t hash_or_id,
527 SchedulerItem::Type
type,
bool match_retry) {
529 for (
auto &item : container) {
534 if (item && this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id,
type, match_retry)) {
535 this->set_item_removed_(item.get(),
true);
543 std::vector<SchedulerItemPtr> items_;
544 std::vector<SchedulerItemPtr> to_add_;
545#ifndef ESPHOME_THREAD_SINGLE
549 std::vector<SchedulerItemPtr> defer_queue_;
550 size_t defer_queue_front_{0};
562 std::vector<SchedulerItemPtr> scheduler_item_pool_;
struct @65::@66 __attribute__
const Component * component
Providing packet encoding functions for exchanging data with a remote host.
void retry_handler(const std::shared_ptr< RetryArgs > &args)
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq