Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`
Expand Down
74 changes: 74 additions & 0 deletions examples/busy_and_retry/busy_and_retry.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include <Arduino.h>
#include <ESPRebootManager.h>

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<unsigned>(result.status),
static_cast<unsigned long>(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<unsigned>(evaluation.accepted),
static_cast<unsigned>(evaluation.code),
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason,
static_cast<unsigned long>(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<unsigned>(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);
}
65 changes: 65 additions & 0 deletions examples/callback_timeout/callback_timeout.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <Arduino.h>
#include <ESPRebootManager.h>
#include <cstdio>

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<unsigned>(evaluation.accepted),
static_cast<unsigned>(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<unsigned>(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<unsigned>(latest.accepted),
static_cast<unsigned>(latest.code),
latest.detail);
printedFinal = true;
}

delay(200);
}
73 changes: 73 additions & 0 deletions examples/guard_blocking/guard_blocking.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <Arduino.h>
#include <ESPRebootManager.h>
#include <cstdio>

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<unsigned long>(evaluation.requestId),
evaluation.reason);
return;
}

Serial.printf("[evaluation] rejected id=%lu code=%u blocker=%s detail=%s\n",
static_cast<unsigned long>(evaluation.requestId),
static_cast<unsigned>(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<unsigned>(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<unsigned>(second.status));
}

delay(250);
}