mirror of
https://github.com/esphome/esphome.git
synced 2026-05-24 18:06:27 +08:00
[core] Add missing uint32_t ID overloads for defer() and cancel_defer() (#13720)
CI / Create common environment (push) Has been cancelled
CI / Check pylint (push) Has been cancelled
CI / Run script/ci-custom (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.13) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.11) (push) Has been cancelled
CI / Determine which jobs to run (push) Has been cancelled
CI / Run integration tests (push) Has been cancelled
CI / Run C++ unit tests (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 IDF (push) Has been cancelled
CI / Run script/clang-tidy for ESP8266 (push) Has been cancelled
CI / Run script/clang-tidy for ZEPHYR (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 1/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 2/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 3/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 4/4 (push) Has been cancelled
CI / Test components batch (${{ matrix.components }}) (push) Has been cancelled
CI / pre-commit.ci lite (push) Has been cancelled
CI / Build target branch for memory impact (push) Has been cancelled
CI / Build PR branch for memory impact (push) Has been cancelled
CI / Comment memory impact (push) Has been cancelled
CI / CI Status (push) Has been cancelled
Stale / stale (push) Has been cancelled
Lock closed issues and PRs / lock (push) Has been cancelled
Publish Release / Initialize build (push) Has been cancelled
Publish Release / Build and publish to PyPi (push) Has been cancelled
Publish Release / Build ESPHome amd64 (push) Has been cancelled
Publish Release / Build ESPHome arm64 (push) Has been cancelled
Publish Release / Publish ESPHome docker to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome docker to ghcr (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to ghcr (push) Has been cancelled
Publish Release / deploy-ha-addon-repo (push) Has been cancelled
Publish Release / deploy-esphome-schema (push) Has been cancelled
Publish Release / version-notifier (push) Has been cancelled
Synchronise Device Classes from Home Assistant / Sync Device Classes (push) Has been cancelled
CI / Create common environment (push) Has been cancelled
CI / Check pylint (push) Has been cancelled
CI / Run script/ci-custom (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.13) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.11) (push) Has been cancelled
CI / Determine which jobs to run (push) Has been cancelled
CI / Run integration tests (push) Has been cancelled
CI / Run C++ unit tests (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 IDF (push) Has been cancelled
CI / Run script/clang-tidy for ESP8266 (push) Has been cancelled
CI / Run script/clang-tidy for ZEPHYR (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 1/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 2/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 3/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 4/4 (push) Has been cancelled
CI / Test components batch (${{ matrix.components }}) (push) Has been cancelled
CI / pre-commit.ci lite (push) Has been cancelled
CI / Build target branch for memory impact (push) Has been cancelled
CI / Build PR branch for memory impact (push) Has been cancelled
CI / Comment memory impact (push) Has been cancelled
CI / CI Status (push) Has been cancelled
Stale / stale (push) Has been cancelled
Lock closed issues and PRs / lock (push) Has been cancelled
Publish Release / Initialize build (push) Has been cancelled
Publish Release / Build and publish to PyPi (push) Has been cancelled
Publish Release / Build ESPHome amd64 (push) Has been cancelled
Publish Release / Build ESPHome arm64 (push) Has been cancelled
Publish Release / Publish ESPHome docker to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome docker to ghcr (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to ghcr (push) Has been cancelled
Publish Release / deploy-ha-addon-repo (push) Has been cancelled
Publish Release / deploy-esphome-schema (push) Has been cancelled
Publish Release / version-notifier (push) Has been cancelled
Synchronise Device Classes from Home Assistant / Sync Device Classes (push) Has been cancelled
This commit is contained in:
@@ -359,6 +359,10 @@ void Component::defer(const std::string &name, std::function<void()> &&f) { //
|
||||
void Component::defer(const char *name, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, name, 0, std::move(f));
|
||||
}
|
||||
void Component::defer(uint32_t id, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, id, 0, std::move(f));
|
||||
}
|
||||
bool Component::cancel_defer(uint32_t id) { return App.scheduler.cancel_timeout(this, id); }
|
||||
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
|
||||
App.scheduler.set_timeout(this, static_cast<const char *>(nullptr), timeout, std::move(f));
|
||||
}
|
||||
|
||||
@@ -494,11 +494,15 @@ class Component {
|
||||
/// Defer a callback to the next loop() call.
|
||||
void defer(std::function<void()> &&f); // NOLINT
|
||||
|
||||
/// Defer a callback with a numeric ID (zero heap allocation)
|
||||
void defer(uint32_t id, std::function<void()> &&f); // NOLINT
|
||||
|
||||
/// Cancel a defer callback using the specified name, name must not be empty.
|
||||
// Remove before 2026.7.0
|
||||
ESPDEPRECATED("Use const char* overload instead. Removed in 2026.7.0", "2026.1.0")
|
||||
bool cancel_defer(const std::string &name); // NOLINT
|
||||
bool cancel_defer(const char *name); // NOLINT
|
||||
bool cancel_defer(uint32_t id); // NOLINT
|
||||
|
||||
// Ordered for optimal packing on 32-bit systems
|
||||
const LogString *component_source_{nullptr};
|
||||
|
||||
@@ -20,6 +20,9 @@ globals:
|
||||
- id: retry_counter
|
||||
type: int
|
||||
initial_value: '0'
|
||||
- id: defer_counter
|
||||
type: int
|
||||
initial_value: '0'
|
||||
- id: tests_done
|
||||
type: bool
|
||||
initial_value: 'false'
|
||||
@@ -136,11 +139,49 @@ script:
|
||||
App.scheduler.cancel_retry(component1, 6002U);
|
||||
ESP_LOGI("test", "Cancelled numeric retry 6002");
|
||||
|
||||
// Test 12: defer with numeric ID (Component method)
|
||||
class TestDeferComponent : public Component {
|
||||
public:
|
||||
void test_defer_methods() {
|
||||
// Test defer with uint32_t ID - should execute on next loop
|
||||
this->defer(7001U, []() {
|
||||
ESP_LOGI("test", "Component numeric defer 7001 fired");
|
||||
id(defer_counter) += 1;
|
||||
});
|
||||
|
||||
// Test another defer with numeric ID
|
||||
this->defer(7002U, []() {
|
||||
ESP_LOGI("test", "Component numeric defer 7002 fired");
|
||||
id(defer_counter) += 1;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static TestDeferComponent test_defer_component;
|
||||
test_defer_component.test_defer_methods();
|
||||
|
||||
// Test 13: cancel_defer with numeric ID (Component method)
|
||||
class TestCancelDeferComponent : public Component {
|
||||
public:
|
||||
void test_cancel_defer() {
|
||||
// Set a defer that should be cancelled
|
||||
this->defer(8001U, []() {
|
||||
ESP_LOGE("test", "ERROR: Numeric defer 8001 should have been cancelled");
|
||||
});
|
||||
// Cancel it immediately
|
||||
bool cancelled = this->cancel_defer(8001U);
|
||||
ESP_LOGI("test", "Cancelled numeric defer 8001: %s", cancelled ? "true" : "false");
|
||||
}
|
||||
};
|
||||
|
||||
static TestCancelDeferComponent test_cancel_defer_component;
|
||||
test_cancel_defer_component.test_cancel_defer();
|
||||
|
||||
- id: report_results
|
||||
then:
|
||||
- lambda: |-
|
||||
ESP_LOGI("test", "Final results - Timeouts: %d, Intervals: %d, Retries: %d",
|
||||
id(timeout_counter), id(interval_counter), id(retry_counter));
|
||||
ESP_LOGI("test", "Final results - Timeouts: %d, Intervals: %d, Retries: %d, Defers: %d",
|
||||
id(timeout_counter), id(interval_counter), id(retry_counter), id(defer_counter));
|
||||
|
||||
sensor:
|
||||
- platform: template
|
||||
|
||||
@@ -19,6 +19,7 @@ async def test_scheduler_numeric_id_test(
|
||||
timeout_count = 0
|
||||
interval_count = 0
|
||||
retry_count = 0
|
||||
defer_count = 0
|
||||
|
||||
# Events for each test completion
|
||||
numeric_timeout_1001_fired = asyncio.Event()
|
||||
@@ -33,6 +34,9 @@ async def test_scheduler_numeric_id_test(
|
||||
max_id_timeout_fired = asyncio.Event()
|
||||
numeric_retry_done = asyncio.Event()
|
||||
numeric_retry_cancelled = asyncio.Event()
|
||||
numeric_defer_7001_fired = asyncio.Event()
|
||||
numeric_defer_7002_fired = asyncio.Event()
|
||||
numeric_defer_cancelled = asyncio.Event()
|
||||
final_results_logged = asyncio.Event()
|
||||
|
||||
# Track interval counts
|
||||
@@ -40,7 +44,7 @@ async def test_scheduler_numeric_id_test(
|
||||
numeric_retry_count = 0
|
||||
|
||||
def on_log_line(line: str) -> None:
|
||||
nonlocal timeout_count, interval_count, retry_count
|
||||
nonlocal timeout_count, interval_count, retry_count, defer_count
|
||||
nonlocal numeric_interval_count, numeric_retry_count
|
||||
|
||||
# Strip ANSI color codes
|
||||
@@ -105,15 +109,27 @@ async def test_scheduler_numeric_id_test(
|
||||
elif "Cancelled numeric retry 6002" in clean_line:
|
||||
numeric_retry_cancelled.set()
|
||||
|
||||
# Check for numeric defer tests
|
||||
elif "Component numeric defer 7001 fired" in clean_line:
|
||||
numeric_defer_7001_fired.set()
|
||||
|
||||
elif "Component numeric defer 7002 fired" in clean_line:
|
||||
numeric_defer_7002_fired.set()
|
||||
|
||||
elif "Cancelled numeric defer 8001: true" in clean_line:
|
||||
numeric_defer_cancelled.set()
|
||||
|
||||
# Check for final results
|
||||
elif "Final results" in clean_line:
|
||||
match = re.search(
|
||||
r"Timeouts: (\d+), Intervals: (\d+), Retries: (\d+)", clean_line
|
||||
r"Timeouts: (\d+), Intervals: (\d+), Retries: (\d+), Defers: (\d+)",
|
||||
clean_line,
|
||||
)
|
||||
if match:
|
||||
timeout_count = int(match.group(1))
|
||||
interval_count = int(match.group(2))
|
||||
retry_count = int(match.group(3))
|
||||
defer_count = int(match.group(4))
|
||||
final_results_logged.set()
|
||||
|
||||
async with (
|
||||
@@ -201,6 +217,23 @@ async def test_scheduler_numeric_id_test(
|
||||
"Numeric retry 6002 should have been cancelled"
|
||||
)
|
||||
|
||||
# Wait for numeric defer tests
|
||||
try:
|
||||
await asyncio.wait_for(numeric_defer_7001_fired.wait(), timeout=0.5)
|
||||
except TimeoutError:
|
||||
pytest.fail("Numeric defer 7001 did not fire within 0.5 seconds")
|
||||
|
||||
try:
|
||||
await asyncio.wait_for(numeric_defer_7002_fired.wait(), timeout=0.5)
|
||||
except TimeoutError:
|
||||
pytest.fail("Numeric defer 7002 did not fire within 0.5 seconds")
|
||||
|
||||
# Verify numeric defer was cancelled
|
||||
try:
|
||||
await asyncio.wait_for(numeric_defer_cancelled.wait(), timeout=0.5)
|
||||
except TimeoutError:
|
||||
pytest.fail("Numeric defer 8001 cancel confirmation not received")
|
||||
|
||||
# Wait for final results
|
||||
try:
|
||||
await asyncio.wait_for(final_results_logged.wait(), timeout=3.0)
|
||||
@@ -215,3 +248,4 @@ async def test_scheduler_numeric_id_test(
|
||||
assert retry_count >= 2, (
|
||||
f"Expected at least 2 retry attempts, got {retry_count}"
|
||||
)
|
||||
assert defer_count >= 2, f"Expected at least 2 defer fires, got {defer_count}"
|
||||
|
||||
Reference in New Issue
Block a user