Merge branch 'scheduler_copy' into integration

This commit is contained in:
J. Nick Koston 2025-06-28 15:49:33 -05:00
commit 3ee8103353
No known key found for this signature in database
5 changed files with 51 additions and 6 deletions

View File

@ -68,6 +68,10 @@ bool Component::cancel_interval(const std::string &name) { // NOLINT
return App.scheduler.cancel_interval(this, name);
}
bool Component::cancel_interval(const char *name) { // NOLINT
return App.scheduler.cancel_interval(this, name);
}
void Component::set_retry(const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> &&f, float backoff_increase_factor) { // NOLINT
App.scheduler.set_retry(this, name, initial_wait_time, max_attempts, std::move(f), backoff_increase_factor);
@ -89,6 +93,10 @@ bool Component::cancel_timeout(const std::string &name) { // NOLINT
return App.scheduler.cancel_timeout(this, name);
}
bool Component::cancel_timeout(const char *name) { // NOLINT
return App.scheduler.cancel_timeout(this, name);
}
void Component::call_loop() { this->loop(); }
void Component::call_setup() { this->setup(); }
void Component::call_dump_config() {

View File

@ -285,6 +285,7 @@ class Component {
* @return Whether an interval functions was deleted.
*/
bool cancel_interval(const std::string &name); // NOLINT
bool cancel_interval(const char *name); // NOLINT
/** Set an retry function with a unique name. Empty name means no cancelling possible.
*
@ -369,6 +370,7 @@ class Component {
* @return Whether a timeout functions was deleted.
*/
bool cancel_timeout(const std::string &name); // NOLINT
bool cancel_timeout(const char *name); // NOLINT
/** Defer a callback to the next loop() call.
*

View File

@ -7,6 +7,7 @@
#include "esphome/core/log.h"
#include <algorithm>
#include <cinttypes>
#include <cstring>
namespace esphome {
@ -124,6 +125,9 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
}
bool HOT Scheduler::cancel_timeout(Component *component, const char *name) {
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
}
void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval,
std::function<void()> func) {
this->set_timer_common_(component, SchedulerItem::INTERVAL, false, &name, interval, std::move(func));
@ -136,6 +140,9 @@ void HOT Scheduler::set_interval(Component *component, const char *name, uint32_
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
}
bool HOT Scheduler::cancel_interval(Component *component, const char *name) {
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
}
struct RetryArgs {
std::function<RetryResult(uint8_t)> func;
@ -357,13 +364,25 @@ void HOT Scheduler::push_(std::unique_ptr<Scheduler::SchedulerItem> item) {
LockGuard guard{this->lock_};
this->to_add_.push_back(std::move(item));
}
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
// Common implementation for cancel operations
bool HOT Scheduler::cancel_item_common_(Component *component, bool is_static_string, const void *name_ptr,
SchedulerItem::Type type) {
// Get the name as const char*
const char *name_cstr =
is_static_string ? static_cast<const char *>(name_ptr) : static_cast<const std::string *>(name_ptr)->c_str();
// Handle null or empty names
if (name_cstr == nullptr)
return false;
// obtain lock because this function iterates and can be called from non-loop task context
LockGuard guard{this->lock_};
bool ret = false;
for (auto &it : this->items_) {
const char *item_name = it->get_name();
if (it->component == component && item_name != nullptr && name == item_name && it->type == type && !it->remove) {
if (it->component == component && item_name != nullptr && strcmp(name_cstr, item_name) == 0 && it->type == type &&
!it->remove) {
to_remove_++;
it->remove = true;
ret = true;
@ -371,7 +390,7 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name,
}
for (auto &it : this->to_add_) {
const char *item_name = it->get_name();
if (it->component == component && item_name != nullptr && name == item_name && it->type == type) {
if (it->component == component && item_name != nullptr && strcmp(name_cstr, item_name) == 0 && it->type == type) {
it->remove = true;
ret = true;
}
@ -379,6 +398,15 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name,
return ret;
}
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
return this->cancel_item_common_(component, false, &name, type);
}
bool HOT Scheduler::cancel_item_(Component *component, const char *name, SchedulerItem::Type type) {
return this->cancel_item_common_(component, true, name, type);
}
uint64_t Scheduler::millis_() {
// Get the current 32-bit millis value
const uint32_t now = millis();

View File

@ -28,6 +28,7 @@ class Scheduler {
void set_timeout(Component *component, const char *name, uint32_t timeout, std::function<void()> func);
bool cancel_timeout(Component *component, const std::string &name);
bool cancel_timeout(Component *component, const char *name);
void set_interval(Component *component, const std::string &name, uint32_t interval, std::function<void()> func);
@ -44,6 +45,7 @@ class Scheduler {
void set_interval(Component *component, const char *name, uint32_t interval, std::function<void()> func);
bool cancel_interval(Component *component, const std::string &name);
bool cancel_interval(Component *component, const char *name);
void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
bool cancel_retry(Component *component, const std::string &name);
@ -137,7 +139,12 @@ class Scheduler {
void cleanup_();
void pop_raw_();
void push_(std::unique_ptr<SchedulerItem> item);
// Common implementation for cancel operations
bool cancel_item_common_(Component *component, bool is_static_string, const void *name_ptr, SchedulerItem::Type type);
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
bool cancel_item_(Component *component, const char *name, SchedulerItem::Type type);
bool empty_() {
this->cleanup_();
return this->items_.empty();

View File

@ -111,7 +111,7 @@ async def test_scheduler_string_test(
try:
await asyncio.wait_for(static_interval_fired.wait(), timeout=1.0)
except asyncio.TimeoutError:
pytest.fail("Static interval did not fire within 1 seconds")
pytest.fail("Static interval did not fire within 1 second")
try:
await asyncio.wait_for(static_interval_cancelled.wait(), timeout=2.0)
@ -127,7 +127,7 @@ async def test_scheduler_string_test(
try:
await asyncio.wait_for(dynamic_timeout_fired.wait(), timeout=1.0)
except asyncio.TimeoutError:
pytest.fail("Dynamic timeout did not fire within 1 seconds")
pytest.fail("Dynamic timeout did not fire within 1 second")
try:
await asyncio.wait_for(dynamic_interval_fired.wait(), timeout=1.5)
@ -138,7 +138,7 @@ async def test_scheduler_string_test(
try:
await asyncio.wait_for(cancel_test_done.wait(), timeout=1.0)
except asyncio.TimeoutError:
pytest.fail("Cancel test did not complete within 1 seconds")
pytest.fail("Cancel test did not complete within 1 second")
# Wait for final results
try: