Skip to content
This repository was archived by the owner on Aug 3, 2026. It is now read-only.
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
163 changes: 159 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,54 @@ name: CI

on:
push:
branches: [ main, master ]
branches: ['**']
tags: ['v*']
pull_request:
workflow_dispatch:

jobs:
build-examples:
platformio-v2-api:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
board: [esp32dev, esp32-s3-devkitc-1, esp32-c3-devkitm-1, esp32-p4-evboard]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Cache PlatformIO
uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-platformio-${{ hashFiles('**/library.json') }}
restore-keys: |
${{ runner.os }}-platformio-

- name: Install PIOArduino Core
run: python -m pip install --upgrade https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.18.zip

- name: Install PIOArduino ESP32 Platform
run: pio platform install https://github.com/pioarduino/platform-espressif32.git

- name: Build v2 API compile sketch
run: |
pio ci examples/v2_api_compile \
--board ${{ matrix.board }} \
--lib="." \
--project-option "platform=https://github.com/pioarduino/platform-espressif32.git" \
--project-option "build_unflags=-std=gnu++11" \
--project-option "build_flags=-std=gnu++17" \
--project-option "lib_deps=ArduinoJson@>=7.0.0, https://github.com/ESPToolKit/esp-date.git, https://github.com/ESPToolKit/esp-worker.git"

platformio-examples:
runs-on: ubuntu-latest
needs: platformio-v2-api
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -53,9 +93,124 @@ jobs:
fi
done

arduino-cli:
platformio-device-tests:
runs-on: ubuntu-latest
needs: platformio-examples
strategy:
fail-fast: false
matrix:
board: [esp32dev, esp32-s3-devkitc-1, esp32-c3-devkitm-1, esp32-p4-evboard]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Cache PlatformIO
uses: actions/cache@v4
with:
path: ~/.platformio
key: ${{ runner.os }}-platformio-${{ hashFiles('**/library.json') }}
restore-keys: |
${{ runner.os }}-platformio-

- name: Install PIOArduino Core
run: python -m pip install --upgrade https://github.com/pioarduino/platformio-core/archive/refs/tags/v6.1.18.zip

- name: Install PIOArduino ESP32 Platform
run: pio platform install https://github.com/pioarduino/platform-espressif32.git

- name: Build device Unity test sketch
run: |
pio ci test/test_esp_scheduler \
--board ${{ matrix.board }} \
--lib="." \
--project-option "platform=https://github.com/pioarduino/platform-espressif32.git" \
--project-option "build_unflags=-std=gnu++11" \
--project-option "build_flags=-std=gnu++17" \
--project-option "lib_deps=ArduinoJson@>=7.0.0, https://github.com/ESPToolKit/esp-date.git, https://github.com/ESPToolKit/esp-worker.git"

arduino-cli-v2-api:
runs-on: ubuntu-latest
needs: platformio-device-tests
env:
ESP32_CORE_VERSION: 3.3.3
ESP32_PACKAGE_URL: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
ARDUINO_BOARDS: |
esp32:esp32:esp32 esp32dev
esp32:esp32:esp32s3 esp32-s3-devkitc-1
esp32:esp32:esp32c3 esp32-c3-devkitm-1
esp32:esp32:esp32p4 esp32-p4-evboard
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Arduino CLI
uses: arduino/setup-arduino-cli@v1

- name: Prepare Arduino directories
run: |
mkdir -p "${HOME}/.arduino15"
mkdir -p "${HOME}/Arduino/libraries"

- name: Cache Arduino dependencies
uses: actions/cache@v4
with:
path: |
~/.arduino15
~/Arduino/libraries
key: ${{ runner.os }}-arduino-esp32-${{ env.ESP32_CORE_VERSION }}-${{ hashFiles('library.properties') }}
restore-keys: |
${{ runner.os }}-arduino-esp32-${{ env.ESP32_CORE_VERSION }}-
${{ runner.os }}-arduino-esp32-

- name: Configure board manager for ESP32
run: |
set -e
arduino-cli config init --overwrite
arduino-cli config set library.enable_unsafe_install true
arduino-cli config add board_manager.additional_urls "${ESP32_PACKAGE_URL}"
arduino-cli config dump

- name: Install ESP32 core
run: |
arduino-cli core update-index --additional-urls "${ESP32_PACKAGE_URL}"
arduino-cli core install esp32:esp32@${ESP32_CORE_VERSION} --additional-urls "${ESP32_PACKAGE_URL}"

- name: Install libraries
run: |
arduino-cli lib update-index
arduino-cli lib install "ArduinoJson"
arduino-cli lib install --git-url "https://github.com/ESPToolKit/esp-date.git"
arduino-cli lib install --git-url "https://github.com/ESPToolKit/esp-worker.git"

- name: Add local library to sketchbook
run: |
set -e
SKETCHBOOK_DIR="${HOME}/Arduino"
mkdir -p "$SKETCHBOOK_DIR/libraries/ESPScheduler"
rsync -a --delete --exclude ".git" ./ "$SKETCHBOOK_DIR/libraries/ESPScheduler/"

- name: Build v2 API compile sketch
env:
BOARDS: ${{ env.ARDUINO_BOARDS }}
run: |
set -euo pipefail
while read -r fqbn board_name; do
if [ -z "$fqbn" ]; then
continue
fi
echo "::group::Compiling v2 API sketch for ${board_name} (${fqbn})"
arduino-cli compile --fqbn "$fqbn" examples/v2_api_compile
echo "::endgroup::"
done <<< "$BOARDS"

arduino-cli-examples:
runs-on: ubuntu-latest
needs: build-examples
needs: arduino-cli-v2-api
env:
ESP32_CORE_VERSION: 3.3.3
ESP32_PACKAGE_URL: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Expand Down
70 changes: 41 additions & 29 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,45 @@ The format follows Keep a Changelog and the project adheres to Semantic Versioni

## [Unreleased]
### Added
- Compile-only `examples/v2_api_compile` sketch to exercise the native v2 API surface in CI.
- Lifecycle and overlap coverage in the Unity test sketch for skip, queue-one, allow-parallel, background no-`tick()`, explicit shutdown, and v1 compatibility cleanup behavior.
- Optional built-in `ESPWorker` async backend selection through `SchedulerConfig`.

### Changed
- CI now runs on every branch push and is split into PlatformIO v2 API builds, PlatformIO example builds, PlatformIO device test sketch builds, Arduino CLI v2 API builds, and Arduino CLI example builds.
- Background command submission now treats a full control queue as `QueueFull` immediately instead of waiting for the control timeout window.
- `SchedulerCore` now uses a scheduler-owned job id index, explicit pending-schedule bookkeeping, direct-indexed completion events, and heap-top validation instead of recovering hot-path state through whole-container scans.

### Fixed
- Scheduler reschedule paths now clear `hasNext` if a due-heap insertion fails, so jobs are retried on the next dispatch pass instead of getting stuck in a primed-but-undispatchable state.
- PSRAM task-stack flags are now honored by the scheduler service task, worker-pool executor, and dedicated-task executor when the platform supports external task stacks.
- Background next-deadline lookup now purges stale heap entries lazily and returns the actual earliest valid due job without scanning the heap.
- Completion events now validate slot index, job id, and generation directly, which keeps stale completions from touching reused slots.

## [2.0.0] - 2026-03-27
### Added
- New `ESPScheduler` v2 API with explicit `begin()` / `end()` lifecycle and `SchedulerResult<T>` return types.
- `ScheduleSpec`/`ScheduleCalculator` split so schedule validation and next-occurrence math are independent from runtime state.
- `SchedulerCore` with min-heap due tracking, centralized job ownership, generation counters, and explicit overlap handling.
- `SchedulerMode::Manual` and `SchedulerMode::Background`.
- `DispatchPolicy` and `OverlapPolicy`.
- Built-in worker-pool executor, dedicated-task executor, and `ESPWorkerExecutorAdapter`.
- Background scheduler service with one scheduler task, command queue, and event queue.
- Job-id-based `getJobInfo()` with runtime state fields for debugging.
- New v2-native examples for manual mode, background worker pool, `ESPWorker` adapter, shutdown, and v1 compatibility.
- `ESPSchedulerV1Compat` wrapper for legacy code paths.

### Changed
- Async scheduling no longer defaults to one FreeRTOS task per scheduled job.
- Background mode no longer requires `tick()`.
- Public docs now describe v2 as the primary API surface.

### Fixed
- Scheduler ownership and shutdown paths are centralized instead of being spread across per-job worker tasks.
- Async completion now flows back through the scheduler core, keeping reschedule decisions in one place.

## [1.0.2] - 2025-12-07
### Added
- Clock validity guard: inline and worker jobs stay idle until the wall clock reaches a configurable minimum (default 2020-01-01 UTC) to prevent catch-up storms when SNTP sets time after boot.
- `std::function` callback overloads for `addJob`/`addJobOnceUtc` to allow capturing lambdas.
- `std::function<void()>` overloads for `addJob`/`addJobOnceUtc` to allow no-arg lambdas.
Expand All @@ -16,32 +55,5 @@ The format follows Keep a Changelog and the project adheres to Semantic Versioni
- `isInitialized()` lifecycle state on `ESPScheduler`, including explicit teardown/re-init behavior after `deinit()`.
- Lifecycle Unity tests for teardown safety (`deinit` before use, repeated `deinit`, and re-init by scheduling again).

### Fixed
- Worker job tasks no longer capture the scheduler instance pointer, avoiding use-after-free risks during scheduler teardown.
- Worker jobs now spawn directly via FreeRTOS (`xTaskCreatePinnedToCore`) using `SchedulerTaskConfig` values.
- Scheduler-owned inline/worker job container allocations and worker context allocations now follow the scheduler PSRAM buffer policy while keeping task-stack PSRAM handling (`usePsramStack`) separate.
- `deinit()` now releases scheduler-owned runtime buffers and is fully idempotent when called multiple times.

## [1.0.1] - 2025-12-07
### Added
- `JobInfo` inspector and `getJobInfo()` helper to enumerate active inline/worker jobs with their schedules and next run time.
- `cleanup()` helper to purge finished inline/worker jobs when not driving the scheduler via `tick()`.

### Changed
- `Schedule::weeklyAtLocal()` now treats an empty weekday mask as “any day” instead of producing an empty field, and `ScheduleField::list()` documents that out-of-range values clear the field.
- Worker jobs now track `nextRunUtc` inside their context to align with the inspector API.

## [1.0.0] - 2025-12-07
### Added
- Initial ESPScheduler cron-style engine built atop ESPDate with inline and ESPWorker-backed task modes.
- Schedule helpers for daily, weekly (bitmask DOW), monthly, one-shot UTC triggers, and custom cron-like fields.
- Inline scheduler loop with `tick()` plus per-job pause/resume/cancel controls.
- Worker task mode that spawns a dedicated FreeRTOS task per job via ESPWorker with optional PSRAM stacks.
- Examples for inline and worker-driven jobs, README and metadata for Arduino/PlatformIO/ESP-IDF.
- CI + release workflows, issue/PR templates, and Unity smoke tests for cron matching.
- Expanded README with API map, cron recipes, and execution-mode guidance.
- Added focused examples covering inline one-shot, pause/resume, custom cron fields, monthly triggers, and worker-based weekly/one-shot jobs.

[Unreleased]: https://github.com/ESPToolKit/esp-scheduler/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/ESPToolKit/esp-scheduler/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/ESPToolKit/esp-scheduler/releases/tag/v1.0.0
[Unreleased]: https://github.com/ESPToolKit/esp-scheduler/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/ESPToolKit/esp-scheduler/compare/v1.0.2...v2.0.0
Loading
Loading