mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 22:26:36 +00:00
Add const char overload for Component::defer() (#9324)
This commit is contained in:
parent
58b4e7dab2
commit
86e7013f40
@ -248,6 +248,9 @@ bool Component::cancel_defer(const std::string &name) { // NOLINT
|
||||
void Component::defer(const std::string &name, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||
}
|
||||
void Component::defer(const char *name, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||
}
|
||||
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, "", timeout, std::move(f));
|
||||
}
|
||||
|
@ -380,6 +380,21 @@ class Component {
|
||||
*/
|
||||
void defer(const std::string &name, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/** Defer a callback to the next loop() call with a const char* name.
|
||||
*
|
||||
* IMPORTANT: The provided name pointer must remain valid for the lifetime of the deferred task.
|
||||
* This means the name should be:
|
||||
* - A string literal (e.g., "update")
|
||||
* - A static const char* variable
|
||||
* - A pointer with lifetime >= the deferred execution
|
||||
*
|
||||
* For dynamic strings, use the std::string overload instead.
|
||||
*
|
||||
* @param name The name of the defer function (must have static lifetime)
|
||||
* @param f The callback
|
||||
*/
|
||||
void defer(const char *name, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/// Defer a callback to the next loop() call.
|
||||
void defer(std::function<void()> &&f); // NOLINT
|
||||
|
||||
|
@ -75,20 +75,42 @@ script:
|
||||
App.scheduler.cancel_timeout(component1, "cancel_static_timeout");
|
||||
ESP_LOGI("test", "Cancelled static timeout using const char*");
|
||||
|
||||
// Test 6 & 7: Test defer with const char* overload using a test component
|
||||
class TestDeferComponent : public Component {
|
||||
public:
|
||||
void test_static_defer() {
|
||||
// Test 6: Static string literal with defer (const char* overload)
|
||||
this->defer("static_defer_1", []() {
|
||||
ESP_LOGI("test", "Static defer 1 fired");
|
||||
id(timeout_counter) += 1;
|
||||
});
|
||||
|
||||
// Test 7: Static const char* with defer
|
||||
static const char* DEFER_NAME = "static_defer_2";
|
||||
this->defer(DEFER_NAME, []() {
|
||||
ESP_LOGI("test", "Static defer 2 fired");
|
||||
id(timeout_counter) += 1;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static TestDeferComponent test_defer_component;
|
||||
test_defer_component.test_static_defer();
|
||||
|
||||
- id: test_dynamic_strings
|
||||
then:
|
||||
- logger.log: "Testing dynamic string timeouts and intervals"
|
||||
- lambda: |-
|
||||
auto *component2 = id(test_sensor2);
|
||||
|
||||
// Test 6: Dynamic string with set_timeout (std::string)
|
||||
// Test 8: Dynamic string with set_timeout (std::string)
|
||||
std::string dynamic_name = "dynamic_timeout_" + std::to_string(id(dynamic_counter)++);
|
||||
App.scheduler.set_timeout(component2, dynamic_name, 100, []() {
|
||||
ESP_LOGI("test", "Dynamic timeout fired");
|
||||
id(timeout_counter) += 1;
|
||||
});
|
||||
|
||||
// Test 7: Dynamic string with set_interval
|
||||
// Test 9: Dynamic string with set_interval
|
||||
std::string interval_name = "dynamic_interval_" + std::to_string(id(dynamic_counter)++);
|
||||
App.scheduler.set_interval(component2, interval_name, 250, [interval_name]() {
|
||||
ESP_LOGI("test", "Dynamic interval fired: %s", interval_name.c_str());
|
||||
@ -99,7 +121,7 @@ script:
|
||||
}
|
||||
});
|
||||
|
||||
// Test 8: Cancel with different string object but same content
|
||||
// Test 10: Cancel with different string object but same content
|
||||
std::string cancel_name = "cancel_test";
|
||||
App.scheduler.set_timeout(component2, cancel_name, 2000, []() {
|
||||
ESP_LOGI("test", "This should be cancelled");
|
||||
@ -110,6 +132,21 @@ script:
|
||||
App.scheduler.cancel_timeout(component2, cancel_name_2);
|
||||
ESP_LOGI("test", "Cancelled timeout using different string object");
|
||||
|
||||
// Test 11: Dynamic string with defer (using std::string overload)
|
||||
class TestDynamicDeferComponent : public Component {
|
||||
public:
|
||||
void test_dynamic_defer() {
|
||||
std::string defer_name = "dynamic_defer_" + std::to_string(id(dynamic_counter)++);
|
||||
this->defer(defer_name, [defer_name]() {
|
||||
ESP_LOGI("test", "Dynamic defer fired: %s", defer_name.c_str());
|
||||
id(timeout_counter) += 1;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static TestDynamicDeferComponent test_dynamic_defer_component;
|
||||
test_dynamic_defer_component.test_dynamic_defer();
|
||||
|
||||
- id: report_results
|
||||
then:
|
||||
- lambda: |-
|
||||
|
@ -26,8 +26,11 @@ async def test_scheduler_string_test(
|
||||
static_interval_cancelled = asyncio.Event()
|
||||
empty_string_timeout_fired = asyncio.Event()
|
||||
static_timeout_cancelled = asyncio.Event()
|
||||
static_defer_1_fired = asyncio.Event()
|
||||
static_defer_2_fired = asyncio.Event()
|
||||
dynamic_timeout_fired = asyncio.Event()
|
||||
dynamic_interval_fired = asyncio.Event()
|
||||
dynamic_defer_fired = asyncio.Event()
|
||||
cancel_test_done = asyncio.Event()
|
||||
final_results_logged = asyncio.Event()
|
||||
|
||||
@ -72,6 +75,15 @@ async def test_scheduler_string_test(
|
||||
elif "Cancelled static timeout using const char*" in clean_line:
|
||||
static_timeout_cancelled.set()
|
||||
|
||||
# Check for static defer tests
|
||||
elif "Static defer 1 fired" in clean_line:
|
||||
static_defer_1_fired.set()
|
||||
timeout_count += 1
|
||||
|
||||
elif "Static defer 2 fired" in clean_line:
|
||||
static_defer_2_fired.set()
|
||||
timeout_count += 1
|
||||
|
||||
# Check for dynamic string tests
|
||||
elif "Dynamic timeout fired" in clean_line:
|
||||
dynamic_timeout_fired.set()
|
||||
@ -81,6 +93,11 @@ async def test_scheduler_string_test(
|
||||
dynamic_interval_count += 1
|
||||
dynamic_interval_fired.set()
|
||||
|
||||
# Check for dynamic defer test
|
||||
elif "Dynamic defer fired" in clean_line:
|
||||
dynamic_defer_fired.set()
|
||||
timeout_count += 1
|
||||
|
||||
# Check for cancel test
|
||||
elif "Cancelled timeout using different string object" in clean_line:
|
||||
cancel_test_done.set()
|
||||
@ -133,6 +150,17 @@ async def test_scheduler_string_test(
|
||||
"Static timeout should have been cancelled"
|
||||
)
|
||||
|
||||
# Wait for static defer tests
|
||||
try:
|
||||
await asyncio.wait_for(static_defer_1_fired.wait(), timeout=0.5)
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail("Static defer 1 did not fire within 0.5 seconds")
|
||||
|
||||
try:
|
||||
await asyncio.wait_for(static_defer_2_fired.wait(), timeout=0.5)
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail("Static defer 2 did not fire within 0.5 seconds")
|
||||
|
||||
# Wait for dynamic string tests
|
||||
try:
|
||||
await asyncio.wait_for(dynamic_timeout_fired.wait(), timeout=1.0)
|
||||
@ -144,6 +172,12 @@ async def test_scheduler_string_test(
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail("Dynamic interval did not fire within 1.5 seconds")
|
||||
|
||||
# Wait for dynamic defer test
|
||||
try:
|
||||
await asyncio.wait_for(dynamic_defer_fired.wait(), timeout=1.0)
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail("Dynamic defer did not fire within 1 second")
|
||||
|
||||
# Wait for cancel test
|
||||
try:
|
||||
await asyncio.wait_for(cancel_test_done.wait(), timeout=1.0)
|
||||
@ -157,7 +191,9 @@ async def test_scheduler_string_test(
|
||||
pytest.fail("Final results were not logged within 4 seconds")
|
||||
|
||||
# Verify results
|
||||
assert timeout_count >= 3, f"Expected at least 3 timeouts, got {timeout_count}"
|
||||
assert timeout_count >= 6, (
|
||||
f"Expected at least 6 timeouts (including defers), got {timeout_count}"
|
||||
)
|
||||
assert interval_count >= 3, (
|
||||
f"Expected at least 3 interval fires, got {interval_count}"
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user