Tempo is a time, calendar, sun, moon, and scheduling toolkit for ESP32.
Tempo helps you keep UTC-first time logic explicit in Arduino ESP32 projects while still providing timezone-aware local conversion, DST-aware calendar helpers, cached sun cycle data, moon phase data, and scheduled job execution.
- UTC-first -
DateTimestores absolute UTC time, while local conversion is explicit. - DST-aware - POSIX timezone strings are used for local time and recurring schedules.
- ESP32-friendly - FreeRTOS service tasks, queue-based scheduling, and result-based errors.
- Sun and moon data - sunrise, sunset, solar noon, daylight checks, moon angle, and illumination.
- Production-minded - no explicit exception-based control flow, bindable callbacks, and C++20 with embedded constraints.
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/ZekStack/tempo.git
build_flags =
-std=gnu++20
build_unflags =
-std=gnu++11Tempo is not published to Arduino Library Manager yet.
Install it by downloading the repository ZIP or cloning it into your Arduino libraries folder.
Arduino/libraries/Tempo#include <Arduino.h>
#include <Tempo.h>
Tempo tempo;
TempoScheduler scheduler;
void setup() {
Serial.begin(115200);
TempoConfig config;
config.timezone = "CET-1CEST,M3.5.0/2,M10.5.0/3";
config.latitude = 47.4979f;
config.longitude = 19.0402f;
TempoResult result = tempo.init(config);
if (!result) {
Serial.println(result.message.c_str());
return;
}
scheduler.init(tempo);
scheduler.everyMinutes(10, "sync", []() {
Serial.println("scheduled job");
});
}
void loop() {
delay(1000);
}Important
Recurring scheduler jobs wait for valid wall-clock time. Set minValidUnixSeconds for your product so jobs do not run against an unset clock.
- Tempo uses POSIX timezone strings for DST-aware local conversion. Local timezone operations are serialized because the C runtime timezone is process-global.
- Latitude and longitude are optional, but both must be configured together before using stored-location sun APIs.
sunCycleToday()lazily calculates and caches the current local date. Date-taking daylight and sunrise/sunset match APIs calculate against the supplied date.- One-shot UTC schedules remain exact; recurring schedules evaluate in local time.
- Scheduler control calls made from an inline scheduler callback return
SchedulerError::Busyrather than waiting on the scheduler service task itself.
| Example | Description |
|---|---|
BasicClock |
Initialize Tempo and print UTC/local time. |
NtpAndCallbacks |
Configure NTP and sync callbacks. |
LocalTimeAndDst |
UTC/local conversion and DST checks. |
SunMoon |
Cached sun cycle and moon phase calls. |
SchedulerBasic |
Simple interval and daily jobs. |
SchedulerCronAndDays |
Cron expressions and weekday masks. |
SchedulerSunCycle |
Sunrise/sunset scheduled jobs. |
SchedulerExecutionModes |
Inline, worker pool, and dedicated-task modes. |
Start with:
examples/BasicClockDetailed documentation is available in the docs/ folder.
| Document | Description |
|---|---|
docs/getting-started.md |
Setup and first time flow. |
docs/configuration.md |
Config options and defaults. |
docs/api.md |
Public types and methods. |
docs/examples.md |
Example guide. |
docs/troubleshooting.md |
Common issues. |
DateTime utcNow = tempo.nowUtc();
LocalDateTime localNow = tempo.nowLocal();
DateTime utc = tempo.toUtc(localNow);
TempoSunCycle sun = tempo.sunCycleToday();
TempoMoonPhase moon = tempo.moonPhase();
SchedulerJobOptions options;
options.name = "job";
options.mode = SchedulerJobMode::WorkerPool;
scheduler.schedule(TempoSchedule::dailyAt(8, 30), options, []() {});| Item | Support |
|---|---|
| Framework | Arduino ESP32 |
| Platform | espressif32 |
| Language | C++20 |
| Filesystem | none |
| PSRAM | Used for selected internal buffers when available |
| Dependencies | none |
| Exceptions | Not used for public error handling |
| Status | 0.1.0 release candidate |
MIT - see LICENSE.md.
Part of the ZekStack ESP32 library stack.