8#ifdef ESPHOME_THREAD_MULTI_ATOMICS
25 friend void ::esphome::retry_handler(
const std::shared_ptr<RetryArgs> &args);
30 template<
typename... Ts>
friend class DelayAction;
35 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
36 void set_timeout(Component *
component, const std::
string &name, uint32_t timeout, std::function<
void()> func);
46 void set_timeout(Component *
component, const
char *name, uint32_t timeout, std::function<
void()> func);
48 void set_timeout(Component *
component, uint32_t
id, uint32_t timeout, std::function<
void()> func);
50 void set_timeout(Component *
component, InternalSchedulerID
id, uint32_t timeout, std::function<
void()> func) {
51 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL,
nullptr,
52 static_cast<uint32_t>(
id), timeout, std::move(func));
55 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
56 bool cancel_timeout(Component *
component, const std::
string &name);
57 bool cancel_timeout(Component *
component, const
char *name);
58 bool cancel_timeout(Component *
component, uint32_t
id);
59 bool cancel_timeout(Component *
component, InternalSchedulerID
id) {
60 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
61 SchedulerItem::TIMEOUT);
64 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
65 void set_interval(Component *
component, const std::
string &name, uint32_t interval, std::function<
void()> func);
75 void set_interval(Component *
component, const
char *name, uint32_t interval, std::function<
void()> func);
77 void set_interval(Component *
component, uint32_t
id, uint32_t interval, std::function<
void()> func);
79 void set_interval(Component *
component, InternalSchedulerID
id, uint32_t interval, std::function<
void()> func) {
80 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL,
nullptr,
81 static_cast<uint32_t>(
id), interval, std::move(func));
84 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
85 bool cancel_interval(Component *
component, const std::
string &name);
86 bool cancel_interval(Component *
component, const
char *name);
87 bool cancel_interval(Component *
component, uint32_t
id);
88 bool cancel_interval(Component *
component, InternalSchedulerID
id) {
89 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
90 SchedulerItem::INTERVAL);
94 ESPDEPRECATED(
"set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
96 void set_retry(Component *
component, const std::
string &name, uint32_t initial_wait_time, uint8_t max_attempts,
97 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
99 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
101 void set_retry(Component *
component, const
char *name, uint32_t initial_wait_time, uint8_t max_attempts,
102 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
104 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
106 void set_retry(Component *
component, uint32_t
id, uint32_t initial_wait_time, uint8_t max_attempts,
107 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
110 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
111 bool cancel_retry(Component *
component, const std::
string &name);
113 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
114 bool cancel_retry(Component *
component, const
char *name);
116 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
117 bool cancel_retry(Component *
component, uint32_t
id);
124 optional<uint32_t> next_schedule_in(uint32_t now);
128 void call(uint32_t now);
130 void process_to_add();
134 enum class NameType : uint8_t {
138 NUMERIC_ID_INTERNAL = 3
142 struct SchedulerItem {
147 const char *static_name;
159 std::function<void()> callback;
160 uint16_t next_execution_high_;
162#ifdef ESPHOME_THREAD_MULTI_ATOMICS
165 std::atomic<bool> remove{
false};
169 NameType name_type_ : 2;
177 NameType name_type_ : 2;
186 next_execution_low_(0),
187 next_execution_high_(0),
188#ifdef ESPHOME_THREAD_MULTI_ATOMICS
191 name_type_(NameType::STATIC_STRING),
196 name_type_(NameType::STATIC_STRING),
199 name_.static_name =
nullptr;
203 ~SchedulerItem() =
default;
206 SchedulerItem(
const SchedulerItem &) =
delete;
207 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
210 SchedulerItem(SchedulerItem &&) =
delete;
211 SchedulerItem &operator=(SchedulerItem &&) =
delete;
214 const char *get_name()
const {
return (name_type_ == NameType::STATIC_STRING) ? name_.static_name :
nullptr; }
217 uint32_t get_name_hash_or_id()
const {
return (name_type_ != NameType::STATIC_STRING) ? name_.hash_or_id : 0; }
220 NameType get_name_type()
const {
return name_type_; }
224 void set_name(NameType
type,
const char *static_name, uint32_t hash_or_id) {
225 if (
type == NameType::STATIC_STRING) {
226 name_.static_name = static_name;
228 name_.hash_or_id = hash_or_id;
233 static bool cmp(
const std::unique_ptr<SchedulerItem> &a,
const std::unique_ptr<SchedulerItem> &b);
238 constexpr uint64_t get_next_execution()
const {
239 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
242 constexpr void set_next_execution(uint64_t value) {
243 next_execution_low_ =
static_cast<uint32_t>(value);
246 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
248 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
249 const LogString *get_source()
const {
return component ?
component->get_component_log_str() : LOG_STR(
"unknown"); }
254 void set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
const char *static_name,
255 uint32_t hash_or_id, uint32_t delay, std::function<
void()> func,
bool is_retry =
false,
256 bool skip_cancel =
false);
260#pragma GCC diagnostic push
261#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
262 void set_retry_common_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
263 uint32_t initial_wait_time, uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
264 float backoff_increase_factor);
265#pragma GCC diagnostic pop
267 bool cancel_retry_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id);
269 uint64_t millis_64_(uint32_t now);
276 std::unique_ptr<SchedulerItem> pop_raw_locked_();
279 std::unique_ptr<SchedulerItem> get_item_from_pool_locked_();
284 bool cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
285 SchedulerItem::Type
type,
bool match_retry =
false);
288 bool cancel_item_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
289 SchedulerItem::Type
type,
bool match_retry =
false);
292 inline bool HOT names_match_static_(
const char *name1,
const char *name2)
const {
297 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
303 inline bool HOT matches_item_locked_(
const std::unique_ptr<SchedulerItem> &item, Component *
component,
304 NameType name_type,
const char *static_name, uint32_t hash_or_id,
305 SchedulerItem::Type
type,
bool match_retry,
bool skip_removed =
true)
const {
314 if (item->component !=
component || item->type !=
type || (skip_removed && item->remove) ||
315 (match_retry && !item->is_retry)) {
319 if (item->get_name_type() != name_type)
322 if (name_type == NameType::STATIC_STRING) {
323 return this->names_match_static_(item->get_name(), static_name);
325 return item->get_name_hash_or_id() == hash_or_id;
329 uint32_t execute_item_(SchedulerItem *item, uint32_t now);
332 bool should_skip_item_(SchedulerItem *item)
const {
333 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
340 void recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item);
343 void full_cleanup_removed_items_();
354 is_retry_cancelled_locked_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id);
356#ifdef ESPHOME_DEBUG_SCHEDULER
358 void debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name, uint32_t hash_or_id,
359 SchedulerItem::Type
type, uint32_t delay, uint64_t now);
362#ifndef ESPHOME_THREAD_SINGLE
364 inline void process_defer_queue_(uint32_t &now) {
385 size_t defer_queue_end = this->defer_queue_.size();
387 while (this->defer_queue_front_ < defer_queue_end) {
388 std::unique_ptr<SchedulerItem> item;
390 LockGuard lock(this->lock_);
397 item = std::move(this->defer_queue_[this->defer_queue_front_]);
398 this->defer_queue_front_++;
403 if (!this->should_skip_item_(item.get())) {
404 now = this->execute_item_(item.get(), now);
408 LockGuard lock(this->lock_);
409 this->recycle_item_main_loop_(std::move(item));
415 if (this->defer_queue_front_ >= defer_queue_end) {
416 LockGuard lock(this->lock_);
417 this->cleanup_defer_queue_locked_();
423 inline void cleanup_defer_queue_locked_() {
425 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
427 this->defer_queue_.clear();
440 size_t remaining = this->defer_queue_.size() - this->defer_queue_front_;
441 for (
size_t i = 0; i < remaining; i++) {
442 this->defer_queue_[i] = std::move(this->defer_queue_[this->defer_queue_front_ + i]);
446 this->defer_queue_.erase(this->defer_queue_.begin() + remaining, this->defer_queue_.end());
448 this->defer_queue_front_ = 0;
456 bool is_item_removed_(SchedulerItem *item)
const {
457#ifdef ESPHOME_THREAD_MULTI_ATOMICS
459 return item->remove.load(std::memory_order_acquire);
472 void set_item_removed_(SchedulerItem *item,
bool removed) {
473#ifdef ESPHOME_THREAD_MULTI_ATOMICS
477 item->remove.store(removed, removed ? std::memory_order_release : std::memory_order_relaxed);
482 item->remove = removed;
490 template<
typename Container>
491 size_t mark_matching_items_removed_locked_(Container &container, Component *
component, NameType name_type,
492 const char *static_name, uint32_t hash_or_id, SchedulerItem::Type
type,
495 for (
auto &item : container) {
502 if (this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id,
type, match_retry)) {
503 this->set_item_removed_(item.get(),
true);
513 template<
typename Container>
514 bool has_cancelled_timeout_in_container_locked_(
const Container &container, Component *
component, NameType name_type,
515 const char *static_name, uint32_t hash_or_id,
516 bool match_retry)
const {
517 for (
const auto &item : container) {
524 if (is_item_removed_(item.get()) &&
525 this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id, SchedulerItem::TIMEOUT,
526 match_retry,
false)) {
534 std::vector<std::unique_ptr<SchedulerItem>> items_;
535 std::vector<std::unique_ptr<SchedulerItem>> to_add_;
536#ifndef ESPHOME_THREAD_SINGLE
540 std::vector<std::unique_ptr<SchedulerItem>> defer_queue_;
541 size_t defer_queue_front_{0};
553 std::vector<std::unique_ptr<SchedulerItem>> scheduler_item_pool_;
555#ifdef ESPHOME_THREAD_MULTI_ATOMICS
566 std::atomic<uint32_t> last_millis_{0};
578#ifdef ESPHOME_THREAD_MULTI_ATOMICS
579 std::atomic<uint16_t> millis_major_{0};
581 uint16_t millis_major_{0};
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