{"id":31588580,"url":"https://github.com/esptoolkit/esp-timer","last_synced_at":"2026-05-05T17:32:55.048Z","repository":{"id":315077854,"uuid":"1057789108","full_name":"ESPToolKit/esp-timer","owner":"ESPToolKit","description":"Async timer helpers mirroring setTimeout / setInterval with dedicated countdown utilities for seconds, minutes and milliseconds.","archived":false,"fork":false,"pushed_at":"2025-09-25T09:46:14.000Z","size":31,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-25T11:36:11.387Z","etag":null,"topics":["arduino","async","embedded","esp32","freertos","software-timer","timer"],"latest_commit_sha":null,"homepage":"https://esptoolkitfrontend.onrender.com/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ESPToolKit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-16T07:59:01.000Z","updated_at":"2025-09-25T09:45:08.000Z","dependencies_parsed_at":"2025-09-16T16:32:16.131Z","dependency_job_id":"6f3e230a-6912-416b-a551-6727aeb875ac","html_url":"https://github.com/ESPToolKit/esp-timer","commit_stats":null,"previous_names":["esptoolkit/esp-timer"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ESPToolKit/esp-timer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESPToolKit%2Fesp-timer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESPToolKit%2Fesp-timer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESPToolKit%2Fesp-timer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESPToolKit%2Fesp-timer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ESPToolKit","download_url":"https://codeload.github.com/ESPToolKit/esp-timer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ESPToolKit%2Fesp-timer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278547821,"owners_count":26004775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","async","embedded","esp32","freertos","software-timer","timer"],"created_at":"2025-10-06T02:10:58.998Z","updated_at":"2026-05-05T17:32:55.043Z","avatar_url":"https://github.com/ESPToolKit.png","language":"C++","funding_links":["https://ko-fi.com/esptoolkit"],"categories":[],"sub_categories":[],"readme":"# ESPTimer\n\nLightweight JS-like timers for ESP32 with non-blocking FreeRTOS tasks. ESPTimer mirrors `setTimeout`/`setInterval` plus second/millisecond/minute counters so you can schedule work without sprinkling `delay` everywhere.\n\n## CI / Release / License\n[![CI](https://github.com/ESPToolKit/esp-timer/actions/workflows/ci.yml/badge.svg)](https://github.com/ESPToolKit/esp-timer/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/ESPToolKit/esp-timer?sort=semver)](https://github.com/ESPToolKit/esp-timer/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE.md)\n\n## Features\n- `setTimeout` (one-shot) and `setInterval` (periodic) helpers with numeric IDs.\n- Counter helpers: per-second, per-millisecond, and per-minute callbacks with remaining time.\n- Each timer type runs on its own FreeRTOS task, with configurable stack, priority, and core affinity (`ESPTimerConfig`).\n- Pause, resume, toggle run status, clear, and query status per timer ID.\n- Thread-safe API so multiple tasks can schedule and control timers simultaneously.\n\n## Examples\nInclude the umbrella header, create an `ESPTimer` instance, and call `init` once:\n\n```cpp\n#include \u003cESPTimer.h\u003e\n\nESPTimer timer;\nvolatile bool shouldShutdownTimers = false;\n\nvoid setup() {\n    Serial.begin(115200);\n    timer.init();\n    if (!timer.isInitialized()) {\n        Serial.println(\"Timer init failed\");\n        return;\n    }\n\n    uint32_t timeoutId = timer.setTimeout([](){\n        Serial.println(\"Fired once after 1.5 s\");\n    }, 1500);\n\n    uint32_t intervalId = timer.setInterval([](){\n        Serial.println(\"1.5 s interval\");\n    }, 1500);\n\n    timer.setSecCounter([](int secLeft){\n        Serial.printf(\"%d seconds remaining\\n\", secLeft);\n    }, 10000);\n\n    timer.setMsCounter([](uint32_t msLeft){\n        // Keep work super light inside ms counters\n    }, 1000);\n\n    timer.setMinCounter([](int minLeft){\n        Serial.printf(\"%d minutes remaining\\n\", minLeft);\n    }, 60000);\n\n    if (timeoutId == 0 || intervalId == 0) {\n        Serial.println(\"Timer capacity or allocation failure\");\n    }\n\n    if (intervalId != 0) {\n        timer.pauseInterval(intervalId);\n        timer.resumeInterval(intervalId);\n    }\n\n    timer.setTimeout([](){\n        shouldShutdownTimers = true;\n    }, 30000);\n}\n\nvoid loop() {\n    if (shouldShutdownTimers \u0026\u0026 timer.isInitialized()) {\n        timer.deinit();\n        shouldShutdownTimers = false;\n    }\n}\n```\n\nExplore `examples/Basic/Basic.ino` for a complete sketch that demonstrates all timer types.\n\n## Gotchas\n- `setMsCounter` wakes every millisecond; keep callbacks trivial or they will starve other work.\n- `pause*` calls are idempotent and only transition `Running → Paused`. Use the matching `resume*` or `toggleRunStatus*` helpers to continue.\n- Each timer type owns its own FreeRTOS task. Tune `ESPTimerConfig` when you need larger stacks or different priorities.\n- IDs are unique per `ESPTimer` instance. Clearing a timer frees the ID; reusing stale IDs after `clear*` will fail.\n- `usePSRAMBuffers = true` is best-effort for timer-owned dynamic buffers. If PSRAM is unavailable, allocation falls back to normal heap automatically.\n- `init()` is transactional. If mutex/task/storage setup fails, `isInitialized()` remains `false` and scheduling helpers return `0`.\n- Runtime capacity is fixed at `init()` time. When a timer lane is full, its `set*` helper returns `0` instead of throwing or aborting.\n- ESPTimer does not throw from library-owned code paths. `std::function` construction before the API boundary may still allocate depending on your toolchain and callback capture size.\n\n## API Reference\n- `void init(const ESPTimerConfig\u0026 cfg = {})` – allocate persistent storage, then spawn each timer worker with the provided stack/priority/core settings. On failure the instance stays uninitialized.\n- `void deinit()` – idempotently stop all timer workers, clear active timers/counters, and free runtime resources.\n- `bool isInitialized() const` – `true` when timer workers and synchronization primitives are active.\n- Scheduling helpers\n  - `uint32_t setTimeout(std::function\u003cvoid()\u003e cb, uint32_t delayMs)` – returns `0` when uninitialized, full, or unable to accept the timer.\n  - `uint32_t setInterval(std::function\u003cvoid()\u003e cb, uint32_t periodMs)` – returns `0` on failure.\n  - `uint32_t setSecCounter(std::function\u003cvoid(int)\u003e cb, uint32_t totalMs)` – returns `0` on failure.\n  - `uint32_t setMsCounter(std::function\u003cvoid(uint32_t)\u003e cb, uint32_t totalMs)` – returns `0` on failure.\n  - `uint32_t setMinCounter(std::function\u003cvoid(int)\u003e cb, uint32_t totalMs)` – returns `0` on failure.\n- Control helpers: `pause*`, `resume*`, `toggleRunStatus*`, `clear*`, `ESPTimerStatus getStatus(id)`.\n  - Timeout-specific clear: `clearTimeout(id)`.\n\n`ESPTimerConfig` knobs (per task type):\n- Stack sizes (`stackSizeTimeout`, `stackSizeInterval`, `stackSizeSec`, `stackSizeMs`, `stackSizeMin`).\n- Priorities (`priorityTimeout`, …).\n- Core affinity (`core*`, `-1` = no pin).\n- Buffer policy (`usePSRAMBuffers`) for timer-owned vectors and callback dispatch staging buffers.\n- Fixed capacities (`maxTimeouts`, `maxIntervals`, `maxSecCounters`, `maxMsCounters`, `maxMinCounters`) used to preallocate all timer-owned runtime slots.\n\n`usePSRAMBuffers` only affects allocations owned by ESPTimer. Callback captures (`std::function`) can still allocate outside this policy depending on capture size and STL behavior.\n\n`ESPTimerStatus` reports `Invalid`, `Running`, `Paused`, `Stopped`, or `Completed`.\n\nStack sizes are expressed in bytes.\n\n## Restrictions\n- Designed for ESP32 boards where FreeRTOS is available (Arduino-ESP32 or ESP-IDF). Other MCUs are untested.\n- Requires C++17 due to heavy use of `std::function` and lambdas.\n- Each timer type consumes its own FreeRTOS task + stack memory—factor that into your RAM budget when enabling multiple counters.\n\n## Tests\nUnity-based smoke tests live in `test/test_basic`. Drop the folder into your PlatformIO workspace (or add your own `platformio.ini` at the repo root) and run `pio test -e esp32dev` against an ESP32 dev kit. The test harness is Arduino friendly and exercises every timer type.\n\n## Formatting Baseline\n\nThis repository follows the firmware formatting baseline from `esptoolkit-template`:\n- `.clang-format` is the source of truth for C/C++/INO layout.\n- `.editorconfig` enforces tabs (`tab_width = 4`), LF endings, and final newline.\n- Format all tracked firmware sources with `bash scripts/format_cpp.sh`.\n\n## License\nMIT — see [LICENSE.md](LICENSE.md).\n\n## ESPToolKit\n- Check out other libraries: \u003chttps://github.com/orgs/ESPToolKit/repositories\u003e\n- Hang out on Discord: \u003chttps://discord.gg/WG8sSqAy\u003e\n- Support the project: \u003chttps://ko-fi.com/esptoolkit\u003e\n- Visit the website: \u003chttps://www.esptoolkit.hu/\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesptoolkit%2Fesp-timer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fesptoolkit%2Fesp-timer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesptoolkit%2Fesp-timer/lists"}