From 2a88c39a0e033c5a2404fa8d7245671c6d7ebe22 Mon Sep 17 00:00:00 2001 From: zekageri Date: Fri, 6 Mar 2026 12:30:06 +0100 Subject: [PATCH] Add additional ESPRebootManager examples --- README.md | 6 ++ examples/busy_and_retry/busy_and_retry.ino | 74 +++++++++++++++++++ .../callback_timeout/callback_timeout.ino | 65 ++++++++++++++++ examples/guard_blocking/guard_blocking.ino | 73 ++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 examples/busy_and_retry/busy_and_retry.ino create mode 100644 examples/callback_timeout/callback_timeout.ino create mode 100644 examples/guard_blocking/guard_blocking.ino diff --git a/README.md b/README.md index 9b89c55..f0f5340 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,12 @@ void setup() { } ``` +## Examples +- [`basic_reboot_request`](examples/basic_reboot_request/basic_reboot_request.ino): minimal accepted request flow with guard + evaluation callbacks. +- [`busy_and_retry`](examples/busy_and_retry/busy_and_retry.ino): demonstrates `Busy` submit status and retrying once the manager returns to `Idle`. +- [`guard_blocking`](examples/guard_blocking/guard_blocking.ino): shows a guard rejecting reboot until a maintenance window opens. +- [`callback_timeout`](examples/callback_timeout/callback_timeout.ino): demonstrates `CallbackTimeout` behavior when a guard runs longer than `callbackTimeoutMs`. + ## API Summary - `bool init(const ESPRebootManagerConfig& config = {})` - `void deinit()` diff --git a/examples/busy_and_retry/busy_and_retry.ino b/examples/busy_and_retry/busy_and_retry.ino new file mode 100644 index 0000000..40b5997 --- /dev/null +++ b/examples/busy_and_retry/busy_and_retry.ino @@ -0,0 +1,74 @@ +#include +#include + +ESPRebootManager rebootManager; + +bool firstQueued = false; +bool secondRetried = false; +bool finished = false; + +void printSubmitResult(const char* label, const RebootSubmitResult& result) { + Serial.printf("%s submit status=%u requestId=%lu\n", + label, + static_cast(result.status), + static_cast(result.requestId)); +} + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + ESPRebootManagerConfig config; + config.taskName = "reboot-manager"; + config.callbackTimeoutMs = 1000; + config.rebootExecutor = []() { + Serial.println("[executor] simulated reboot"); + }; + + if (!rebootManager.init(config)) { + Serial.println("Failed to init ESPRebootManager"); + return; + } + + rebootManager.onRebootRequest([](const RebootRequestContext&) { + return RebootVote{}; + }); + + rebootManager.onEvaluation([](const RebootEvaluation& evaluation) { + Serial.printf("[evaluation] accepted=%u code=%u id=%lu reason=%s delayMs=%lu\n", + static_cast(evaluation.accepted), + static_cast(evaluation.code), + static_cast(evaluation.requestId), + evaluation.reason, + static_cast(evaluation.delayMs)); + }); + + RebootSubmitResult first = rebootManager.requestReboot("firmware-update", 4000); + printSubmitResult("first", first); + firstQueued = (first.status == RebootSubmitStatus::Queued); + + // A second request during the first one should return Busy. + RebootSubmitResult second = rebootManager.requestReboot("wifi-reset", 0); + printSubmitResult("second-immediate", second); +} + +void loop() { + if (!firstQueued || finished) { + delay(250); + return; + } + + const RebootRequestStatus status = rebootManager.rebootStatus(); + Serial.printf("[status] %u\n", static_cast(status)); + + if (!secondRetried && status == RebootRequestStatus::Idle) { + secondRetried = true; + RebootSubmitResult retry = rebootManager.requestReboot("wifi-reset", 0); + printSubmitResult("second-retry", retry); + finished = (retry.status == RebootSubmitStatus::Queued); + } + + delay(500); +} diff --git a/examples/callback_timeout/callback_timeout.ino b/examples/callback_timeout/callback_timeout.ino new file mode 100644 index 0000000..2e1b98c --- /dev/null +++ b/examples/callback_timeout/callback_timeout.ino @@ -0,0 +1,65 @@ +#include +#include +#include + +ESPRebootManager rebootManager; + +bool submitted = false; +bool printedFinal = false; + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + ESPRebootManagerConfig config; + config.taskName = "reboot-manager"; + config.callbackTimeoutMs = 200; + config.rebootExecutor = []() { + Serial.println("[executor] should not run when callback times out"); + }; + + if (!rebootManager.init(config)) { + Serial.println("Failed to init ESPRebootManager"); + return; + } + + rebootManager.onRebootRequest([](const RebootRequestContext&) { + RebootVote vote; + std::snprintf(vote.detail, sizeof(vote.detail), "guard took too long"); + delay(600); + vote.allow = true; + return vote; + }); + + rebootManager.onEvaluation([](const RebootEvaluation& evaluation) { + Serial.printf("[evaluation] accepted=%u code=%u blocker=%s detail=%s\n", + static_cast(evaluation.accepted), + static_cast(evaluation.code), + evaluation.blockerName, + evaluation.detail); + }); + + RebootSubmitResult result = rebootManager.requestReboot("simulate-timeout", 0); + submitted = (result.status == RebootSubmitStatus::Queued); + Serial.printf("submit status=%u\n", static_cast(result.status)); +} + +void loop() { + if (!submitted || printedFinal) { + delay(200); + return; + } + + if (rebootManager.rebootStatus() == RebootRequestStatus::Idle) { + const RebootEvaluation latest = rebootManager.lastEvaluation(); + Serial.printf("final accepted=%u code=%u detail=%s\n", + static_cast(latest.accepted), + static_cast(latest.code), + latest.detail); + printedFinal = true; + } + + delay(200); +} diff --git a/examples/guard_blocking/guard_blocking.ino b/examples/guard_blocking/guard_blocking.ino new file mode 100644 index 0000000..984d80b --- /dev/null +++ b/examples/guard_blocking/guard_blocking.ino @@ -0,0 +1,73 @@ +#include +#include +#include + +ESPRebootManager rebootManager; + +bool maintenanceWindowOpen = false; +bool firstQueued = false; +bool secondQueued = false; + +void setup() { + Serial.begin(115200); + while (!Serial) { + delay(10); + } + + ESPRebootManagerConfig config; + config.taskName = "reboot-manager"; + config.callbackTimeoutMs = 1000; + config.rebootExecutor = []() { + Serial.println("[executor] simulated reboot"); + }; + + if (!rebootManager.init(config)) { + Serial.println("Failed to init ESPRebootManager"); + return; + } + + rebootManager.onRebootRequest([](const RebootRequestContext&) { + RebootVote vote; + if (!maintenanceWindowOpen) { + vote.allow = false; + std::snprintf(vote.detail, sizeof(vote.detail), "maintenance window is closed"); + } + return vote; + }); + + rebootManager.onEvaluation([](const RebootEvaluation& evaluation) { + if (evaluation.accepted) { + Serial.printf("[evaluation] accepted id=%lu reason=%s\n", + static_cast(evaluation.requestId), + evaluation.reason); + return; + } + + Serial.printf("[evaluation] rejected id=%lu code=%u blocker=%s detail=%s\n", + static_cast(evaluation.requestId), + static_cast(evaluation.code), + evaluation.blockerName, + evaluation.detail); + }); + + RebootSubmitResult first = rebootManager.requestReboot("scheduled-maintenance", 1000); + firstQueued = (first.status == RebootSubmitStatus::Queued); + Serial.printf("first submit status=%u\n", static_cast(first.status)); +} + +void loop() { + static uint32_t startedAt = millis(); + + if (firstQueued && !maintenanceWindowOpen && millis() - startedAt >= 5000) { + maintenanceWindowOpen = true; + Serial.println("Maintenance window opened. Retrying reboot request..."); + } + + if (maintenanceWindowOpen && !secondQueued && rebootManager.rebootStatus() == RebootRequestStatus::Idle) { + RebootSubmitResult second = rebootManager.requestReboot("scheduled-maintenance", 1000); + secondQueued = (second.status == RebootSubmitStatus::Queued); + Serial.printf("second submit status=%u\n", static_cast(second.status)); + } + + delay(250); +}