ESPWorker is a C++17 helper library for ESP32 projects that want FreeRTOS power without the boilerplate. It wraps task creation, joins, diagnostics, PSRAM stacks, and lifecycle events into a simple API that works with both Arduino-ESP32 and ESP-IDF.
- Works with FreeRTOS tasks while keeping
std::function/lambda ergonomics. - Joinable workers with runtime diagnostics (
JobDiag) and cooperative destruction. - Pull worker-pool metrics (
WorkerDiag) including counts and runtime stats. - Optional PSRAM stacks (
spawnExt) for memory hungry jobs. - Thread-safe event and error callbacks so firmware can log or react centrally.
- Configurable defaults and guardrails (max workers, priorities, affinities).
Quick start:
#include <ESPWorker.h>
ESPWorker worker;
void setup() {
Serial.begin(115200);
worker.init({
.maxWorkers = 4,
.stackSize = 4096,
.priority = 1,
.coreId = tskNO_AFFINITY,
.enableExternalStacks = true,
});
worker.onEvent([](WorkerEvent event) {
Serial.printf("[worker] %s\n", worker.eventToString(event));
});
worker.onError([](WorkerError error) {
Serial.printf("[worker][error] %s\n", worker.errorToString(error));
});
WorkerResult result = worker.spawn([]() {
while (true) {
vTaskDelay(pdMS_TO_TICKS(250));
}
}, {
.stackSize = 16 * 1024,
.priority = 3,
.name = "sensor-task",
});
if (result) {
result.handler->wait(pdMS_TO_TICKS(1000));
}
}Need deterministic cleanup? Store the handler and call destroy() when shutting down:
WorkerResult job = worker.spawn([](){ /* ... */ });
if (job) {
// Stop the task cooperatively
job.handler->destroy();
}Check the runnable examples under examples/:
examples/basic_worker– spawns workers, waits for completion, prints diagnostics.examples/psram_stack– usesspawnExtto place heavy stacks in PSRAM.
- Always call
worker.init()once before spawning tasks. Each ESPWorker instance controls its own limits. spawncreates persistent FreeRTOS tasks; remember to end the lambda (return) ordestroy()the handler to reclaim slots.- Errors such as
MaxWorkersReachedorTaskCreateFailedare reported in the returnedWorkerResultand via the error callback. - PSRAM stacks require PSRAM to be enabled in your board configuration; fall back to internal RAM otherwise.
void init(const ESPWorker::Config& config)– sets defaults (max workers, default stack/priority/core, PSRAM allowance).WorkerResult spawn(TaskCallback cb, const WorkerConfig& config = {})– create a worker. The returned handler provideswait()anddestroy()helpers plus per-job diagnostics.WorkerResult spawnExt(...)– identical tospawnbut forces PSRAM stacks when available.size_t activeWorkers() const/void cleanupFinished()– query or prune finished tasks.WorkerDiag getDiag() const– aggregated counts and runtime stats across the pool.void onEvent(EventCallback cb)/void onError(ErrorCallback cb)– receive lifecycle signals (Created → Started → Completed/Destroyed) and fatal issues.const char* eventToString(...)/errorToString(...)– convert enums to printable text for logging.
WorkerConfig (per job) and ESPWorker::Config (global defaults) expose priority, stack size, core affinity, external stack usage, and an optional name that shows up in diagnostics and watchdog dumps.
Stack sizes are expressed in bytes.
- Intended for ESP32-class boards where FreeRTOS and PSRAM are available; other architectures are untested.
- Requires C++17 support (
-std=gnu++17) and should not be called from ISR context. - Each worker consumes RAM proportional to its stack; keep
maxWorkersand per-job stacks aligned with your heap budget.
A native host test suite is still being assembled. For now rely on the examples/ sketches (build with PlatformIO or Arduino IDE) to verify integration, and consider adding regression tests when contributing changes.
ESPWorker is released under the MIT License.
- Check out other libraries: https://github.com/orgs/ESPToolKit/repositories
- Hang out on Discord: https://discord.gg/WG8sSqAy
- Support the project: https://ko-fi.com/esptoolkit
- Visit the website: https://www.esptoolkit.hu/