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 ESPDEPRECATED("Use const
char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
51 bool cancel_timeout(Component *
component, const std::
string &name);
52 bool cancel_timeout(Component *
component, const
char *name);
53 bool cancel_timeout(Component *
component, uint32_t
id);
55 ESPDEPRECATED("Use const
char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
56 void set_interval(Component *
component, const std::
string &name, uint32_t interval, std::function<
void()> func);
66 void set_interval(Component *
component, const
char *name, uint32_t interval, std::function<
void()> func);
68 void set_interval(Component *
component, uint32_t
id, uint32_t interval, std::function<
void()> func);
70 ESPDEPRECATED("Use const
char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
71 bool cancel_interval(Component *
component, const std::
string &name);
72 bool cancel_interval(Component *
component, const
char *name);
73 bool cancel_interval(Component *
component, uint32_t
id);
75 ESPDEPRECATED("Use const
char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
76 void set_retry(Component *
component, const std::
string &name, uint32_t initial_wait_time, uint8_t max_attempts,
77 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
78 void set_retry(Component *
component, const
char *name, uint32_t initial_wait_time, uint8_t max_attempts,
79 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
81 void set_retry(Component *
component, uint32_t
id, uint32_t initial_wait_time, uint8_t max_attempts,
82 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
84 ESPDEPRECATED("Use const
char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0")
85 bool cancel_retry(Component *
component, const std::
string &name);
86 bool cancel_retry(Component *
component, const
char *name);
87 bool cancel_retry(Component *
component, uint32_t
id);
94 optional<uint32_t> next_schedule_in(uint32_t now);
98 void call(uint32_t now);
100 void process_to_add();
104 enum class NameType : uint8_t {
111 struct SchedulerItem {
116 const char *static_name;
128 std::function<void()> callback;
129 uint16_t next_execution_high_;
131#ifdef ESPHOME_THREAD_MULTI_ATOMICS
134 std::atomic<bool> remove{
false};
137 enum Type : uint8_t {
TIMEOUT, INTERVAL }
type : 1;
138 NameType name_type_ : 2;
144 enum Type : uint8_t {
TIMEOUT, INTERVAL }
type : 1;
146 NameType name_type_ : 2;
155 next_execution_low_(0),
156 next_execution_high_(0),
157#ifdef ESPHOME_THREAD_MULTI_ATOMICS
160 name_type_(NameType::STATIC_STRING),
165 name_type_(NameType::STATIC_STRING),
168 name_.static_name =
nullptr;
172 ~SchedulerItem() =
default;
175 SchedulerItem(
const SchedulerItem &) =
delete;
176 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
179 SchedulerItem(SchedulerItem &&) =
delete;
180 SchedulerItem &operator=(SchedulerItem &&) =
delete;
183 const char *get_name()
const {
return (name_type_ == NameType::STATIC_STRING) ? name_.static_name :
nullptr; }
186 uint32_t get_name_hash_or_id()
const {
return (name_type_ != NameType::STATIC_STRING) ? name_.hash_or_id : 0; }
189 NameType get_name_type()
const {
return name_type_; }
192 void set_static_name(
const char *name) {
193 name_.static_name = name;
194 name_type_ = NameType::STATIC_STRING;
198 void set_hashed_name(uint32_t hash) {
199 name_.hash_or_id = hash;
200 name_type_ = NameType::HASHED_STRING;
204 void set_numeric_id(uint32_t
id) {
205 name_.hash_or_id =
id;
206 name_type_ = NameType::NUMERIC_ID;
209 static bool cmp(
const std::unique_ptr<SchedulerItem> &a,
const std::unique_ptr<SchedulerItem> &b);
214 constexpr uint64_t get_next_execution()
const {
215 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
218 constexpr void set_next_execution(uint64_t value) {
219 next_execution_low_ =
static_cast<uint32_t>(value);
222 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
224 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
225 const LogString *get_source()
const {
return component ?
component->get_component_log_str() : LOG_STR(
"unknown"); }
230 void set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
const char *static_name,
231 uint32_t hash_or_id, uint32_t delay, std::function<
void()> func,
bool is_retry =
false,
232 bool skip_cancel =
false);
236 void set_retry_common_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
237 uint32_t initial_wait_time, uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
238 float backoff_increase_factor);
240 bool cancel_retry_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id);
242 uint64_t millis_64_(uint32_t now);
249 std::unique_ptr<SchedulerItem> pop_raw_locked_();
252 std::unique_ptr<SchedulerItem> get_item_from_pool_locked_();
257 bool cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
258 SchedulerItem::Type
type,
bool match_retry =
false);
261 bool cancel_item_(Component *
component, NameType name_type,
const char *static_name, uint32_t hash_or_id,
262 SchedulerItem::Type
type,
bool match_retry =
false);
265 inline bool HOT names_match_static_(
const char *name1,
const char *name2)
const {
270 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
276 inline bool HOT matches_item_locked_(
const std::unique_ptr<SchedulerItem> &item, Component *
component,
277 NameType name_type,
const char *static_name, uint32_t hash_or_id,
278 SchedulerItem::Type
type,
bool match_retry,
bool skip_removed =
true)
const {
287 if (item->component !=
component || item->type !=
type || (skip_removed && item->remove) ||
288 (match_retry && !item->is_retry)) {
292 if (item->get_name_type() != name_type)
295 if (name_type == NameType::STATIC_STRING) {
296 return this->names_match_static_(item->get_name(), static_name);
298 return item->get_name_hash_or_id() == hash_or_id;
302 uint32_t execute_item_(SchedulerItem *item, uint32_t now);
305 bool should_skip_item_(SchedulerItem *item)
const {
306 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
313 void recycle_item_main_loop_(std::unique_ptr<SchedulerItem> item);
316 void full_cleanup_removed_items_();
318#ifdef ESPHOME_DEBUG_SCHEDULER
320 void debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name, uint32_t hash_or_id,
321 SchedulerItem::Type
type, uint32_t delay, uint64_t now);
324#ifndef ESPHOME_THREAD_SINGLE
326 inline void process_defer_queue_(uint32_t &now) {
347 size_t defer_queue_end = this->defer_queue_.size();
349 while (this->defer_queue_front_ < defer_queue_end) {
350 std::unique_ptr<SchedulerItem> item;
352 LockGuard lock(this->lock_);
359 item = std::move(this->defer_queue_[this->defer_queue_front_]);
360 this->defer_queue_front_++;
365 if (!this->should_skip_item_(item.get())) {
366 now = this->execute_item_(item.get(), now);
370 LockGuard lock(this->lock_);
371 this->recycle_item_main_loop_(std::move(item));
377 if (this->defer_queue_front_ >= defer_queue_end) {
378 LockGuard lock(this->lock_);
379 this->cleanup_defer_queue_locked_();
385 inline void cleanup_defer_queue_locked_() {
387 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
389 this->defer_queue_.clear();
402 size_t remaining = this->defer_queue_.size() - this->defer_queue_front_;
403 for (
size_t i = 0; i < remaining; i++) {
404 this->defer_queue_[i] = std::move(this->defer_queue_[this->defer_queue_front_ + i]);
406 this->defer_queue_.resize(remaining);
408 this->defer_queue_front_ = 0;
416 bool is_item_removed_(SchedulerItem *item)
const {
417#ifdef ESPHOME_THREAD_MULTI_ATOMICS
419 return item->remove.load(std::memory_order_acquire);
432 void set_item_removed_(SchedulerItem *item,
bool removed) {
433#ifdef ESPHOME_THREAD_MULTI_ATOMICS
437 item->remove.store(removed, removed ? std::memory_order_release : std::memory_order_relaxed);
442 item->remove = removed;
450 template<
typename Container>
451 size_t mark_matching_items_removed_locked_(Container &container, Component *
component, NameType name_type,
452 const char *static_name, uint32_t hash_or_id, SchedulerItem::Type
type,
455 for (
auto &item : container) {
462 if (this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id,
type, match_retry)) {
463 this->set_item_removed_(item.get(),
true);
473 template<
typename Container>
474 bool has_cancelled_timeout_in_container_locked_(
const Container &container, Component *
component, NameType name_type,
475 const char *static_name, uint32_t hash_or_id,
476 bool match_retry)
const {
477 for (
const auto &item : container) {
484 if (is_item_removed_(item.get()) &&
485 this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id, SchedulerItem::TIMEOUT,
486 match_retry,
false)) {
494 std::vector<std::unique_ptr<SchedulerItem>> items_;
495 std::vector<std::unique_ptr<SchedulerItem>> to_add_;
496#ifndef ESPHOME_THREAD_SINGLE
500 std::vector<std::unique_ptr<SchedulerItem>> defer_queue_;
501 size_t defer_queue_front_{0};
513 std::vector<std::unique_ptr<SchedulerItem>> scheduler_item_pool_;
515#ifdef ESPHOME_THREAD_MULTI_ATOMICS
526 std::atomic<uint32_t> last_millis_{0};
538#ifdef ESPHOME_THREAD_MULTI_ATOMICS
539 std::atomic<uint16_t> millis_major_{0};
541 uint16_t millis_major_{0};
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