WeeklyAlarm is a timer to trigger daily at the same time. It has been designed to be used like a numeric thermostat scheduler.
**Only with board taht dont include POSIX time
A lightweight Arduino library for scheduling weekly recurring alarms, inspired by programmable thermostats. Each alarm fires on selected days of the week at a specific time, with support for multiple callbacks, lambdas, and functors.
| Platform | Time Source |
|---|---|
| STM32 / newlib (Opta, Portenta, etc.) | POSIX time.h — use set_time(epoch) to set time |
| AVR / classic Arduino | Paul Stoffregen's Time library — use setTime(epoch) |
The correct time backend is selected automatically at compile time via __NEWLIB__ detection. No configuration needed.
lib_deps =
WeeklyAlarm
# Only needed on non-newlib platforms (AVR, etc.):
paulstoffregen/TimeDownload and install via Sketch → Include Library → Add .ZIP Library.
#include "WeeklyAlarm.h"
WeeklyAlarm myAlarm;
void onAlarm() {
Serial.println("Alarm fired!");
}
void setup() {
Serial.begin(9600);
set_time(epoch); // or setTime(epoch) on AVR — set your RTC/NTP time first
myAlarm
.add(onAlarm)
.set(7, 30) // 07:30
.dayEnable(dowMonday, dowWednesday, dowFriday)
.alarmOn();
}
void loop() {
WeeklyAlarm::handler();
}WeeklyAlarm myAlarm;Creates a new alarm instance. No alarm is active until add(), set(), dayEnable(), and alarmOn() are called.
Attaches a callback to the alarm. Must be called before set() or alarmOn().
Accepts any callable: function pointer, functor, or lambda (with or without capture).
// Function pointer
myAlarm.add(myFunction);
// Lambda without capture
myAlarm.add([]() { digitalWrite(LED, HIGH); });
// Lambda with capture
int value = 42;
myAlarm.add([value]() { Serial.println(value); });Returns *this for chaining.
Sets the time of day the alarm will fire.
myAlarm.set(7, 30); // 07:30
myAlarm.set(22, 0); // 22:00Must be called after add() and before alarmOn(). Returns *this for chaining.
Enables one or more days of the week for this alarm.
myAlarm.dayEnable(dowMonday);
myAlarm.dayEnable(dowMonday, dowWednesday, dowFriday);
myAlarm.dayEnable(dowSaturday, dowSunday);Available day constants:
| Constant | Value |
|---|---|
dowSunday |
1 |
dowMonday |
2 |
dowTuesday |
3 |
dowWednesday |
4 |
dowThursday |
5 |
dowFriday |
6 |
dowSaturday |
7 |
Returns *this for chaining.
Disables one or more days of the week.
myAlarm.dayDisable(dowSaturday, dowSunday);Returns *this for chaining.
Toggles one or more days on/off.
myAlarm.dayToggle(dowMonday);Returns *this for chaining.
Enables the alarm and inserts it into the sorted active alarm list. set() and at least one dayEnable() must be called first.
myAlarm.alarmOn();Calling alarmOn() before set() will print an error and return without enabling.
Disables the alarm and removes it from the active list. All day and time settings are preserved.
myAlarm.alarmOff();Toggles the alarm on or off.
myAlarm.alarmToggle();Removes the alarm from the active list and frees its memory. The WeeklyAlarm instance can be reused by calling add() again.
myAlarm.remove();Returns true if the alarm is currently enabled.
if (myAlarm.isEnable()) { ... }Returns true if the specified day is enabled for this alarm.
if (myAlarm.isDayEnable(dowMonday)) { ... }Returns the raw day-enable bitmask. Bits 1–7 correspond to Sunday–Saturday. Bit 0 is the alarm enable flag.
uint8_t mask = myAlarm.getDaysEnable();Returns the alarm's scheduled time of day as a WA_TimeElements structure.
WA_TimeElements t = myAlarm.getTime();
uint8_t hour = t.WA_HOUR;
uint8_t minute = t.WA_MINUTE;WA_TimeElements is a platform-transparent typedef — struct tm on newlib/STM32, TimeElements on AVR/TimeLib. Use the WA_ field macros for portable member access.
Returns a JSON string representation of the alarm's current settings.
Serial.println(myAlarm.toJSON());
// {"Settings":{"Switch":true,"Days Enabled":{"Sunday":false,"Monday":true,...},"hour":7,"minute":30}}Prints a human-readable description of the alarm's next scheduled time to a Stream (Serial, etc.).
myAlarm.prettyPrintAlarm(Serial);
// 07:30 Monday 1/1/2025Main dispatch function. Call this from loop() — it is self-throttling via the sorted alarm list and has negligible overhead when no alarm is due.
void loop() {
WeeklyAlarm::handler();
}Internally, alarms are maintained in a sorted linked list ordered by next fire time. The handler checks only the head of the list — if the head is not due, it returns immediately (O(1)). When an alarm fires, its callback is called, its next target time is computed, and it is re-inserted at the correct sorted position. Multiple alarms due at the same time are each fired on successive loop() passes to avoid stalling other tasks.
Prints a human-readable time_t value to a Stream.
WeeklyAlarm::prettyPrintTime(time_t, Serial);
// 07:30 Monday 1/1/2025myAlarm
.add([]() { setHeating(21.0f); })
.set(7, 0)
.dayEnable(dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday)
.alarmOn();Each WeeklyAlarm instance manages one time-value pair. Use multiple instances for complex schedules:
WeeklyAlarm morningAlarm;
WeeklyAlarm eveningAlarm;
WeeklyAlarm weekendAlarm;
morningAlarm.add([]() { setpoint(21.0f); }).set(7, 0).dayEnable(dowMonday, dowFriday).alarmOn();
eveningAlarm.add([]() { setpoint(18.0f); }).set(18, 0).dayEnable(dowMonday, dowFriday).alarmOn();
weekendAlarm.add([]() { setpoint(20.0f); }).set(9, 0).dayEnable(dowSaturday, dowSunday).alarmOn();All instances share the same sorted list and are dispatched by the single WeeklyAlarm::handler() call.
- Time must be set (via RTC, NTP, or BACnet TimeSynchronization) before calling
alarmOn(). - Alarm resolution is one minute — sub-minute precision is not supported.
- The library does not manage time synchronization. Use
set_time()(STM32) orsetTime()(AVR/TimeLib) from your sketch or a sync provider. - On STM32 platforms, the POSIX
timeDayOfWeek_tenum is provided by the library. On other platforms it comes from TimeLib.
MIT License — see source file header for full text.