DS_CAP_TIMERS_ABS - denis-stepanov/esp-ds-system GitHub Wiki

DS_CAP_TIMERS_ABS — Absolute Timer Support

Description

This capability adds support for absolute timers; that is, timers that fire at a given time. For this to work, the controller should have enabled a notion of time.

The following methods, complementary to generic timer methods, are available:

TimerAbsolute::TimerAbsolute(const String action = "undefined", const uint8_t hour = 0,
  const uint8_t minute = 0, const uint8_t second = 0, const timer_dow_t dow = TIMER_DOW_ANY,
  const bool armed = true, const bool recurrent = true, const bool transient = false,
  const int id = -1);                                        // Constructor
uint8_t TimerAbsolute::getHour() const;                      // Return hour setting
void TimerAbsolute::setHour(const uint8_t new_hour);         // Set hour setting
uint8_t TimerAbsolute::getMinute() const;                    // Return minute setting
void TimerAbsolute::setMinute(const uint8_t new_minute);     // Set minute setting
uint8_t TimerAbsolute::getSecond() const;                    // Return second setting
void TimerAbsolute::setSecond(const uint8_t new_second);     // Set second setting
uint8_t TimerAbsolute::getDayOfWeek() const;                 // Get day of week setting
void TimerAbsolute::setDayOfWeek(const uint8_t new_dow);     // Set day of week setting
void TimerAbsolute::enableDayOfWeek(const uint8_t new_dow);  // Enable some day(s) of week
void TimerAbsolute::disableDayOfWeek(const uint8_t new_dow); // Disable some day(s) of week

One can also compare absolute timers among themselves and with a struct tm value containing absolute time.

Absolute timer precision is one second, even if the time itself can be specified more precisely. This is deliberate choice, as most of the user-visible timer actions do not need higher precision. The logic that checks if a timer should be fired is executed at 1 Hz rate (once a second). Note the Bugs below.

Day of week is defined as one of TIMER_DOW_SUNDAY, TIMER_DOW_MONDAY, TIMER_DOW_TUESDAY, TIMER_DOW_WEDNESDAY, TIMER_DOW_THURSDAY, TIMER_DOW_FRIDAY, TIMER_DOW_SATURDAY. TIMER_DOW_ANY is a default and will instruct timer to fire every day. It is possible to designate several days as follows:

TIMER_DOW_SATURDAY | TIMER_DOW_SUNDAY

or to exclude a particular day:

TIMER_DOW_ANY & ~TIMER_DOW_SUNDAY

TIMER_DOW_NONE will clear all days, effectively disabling the timer. TIMER_DOW_INVALID may be set if invalid configuration is passed to the constructor. Such timer will be ignored when processing.

The following fields are implemented:

Field Description Default Value
bool System::abs_timers_active True if absolute time-based timers should be served true
std::forward_list System::timers List of timers (empty)
void (*System::timerHandler)(const TimerAbsolute*) Timer handler nullptr

The list of timers is implemented as a forward list. To add a timer to the list, use std::forward_list methods, such as System::timers.push_front(my_timer). If you want timers to be called in the order of addition, call System::timers.reverse() after filling the list. Note that the list stores pointers to timers which must be globally accessible; it is programmer's responsibility to make sure that the timer objects are either defined statically, or allocated on a heap.

System::abs_timers_active field can be used to temporarily suspend all absolute timers at once.

Timer handler would typically look as follows:

void myTimerHandler(const TimerAbsolute* timer) {
  if (timer->getAction() == "my action 1") {
    // Do something ...
  } else
  if (timer->getAction() == "my action 2") {
    // Do something else ...
  } // else ...
}
void (*System::timerHandler)(const TimerAbsolute*) = myTimerHandler;  // Install the handler

One single handler is provided for all absolute timers. The handler will be called in the loop() context, meaning you can use all the same methods as if you would be calling this function from inside the loop(). As ESP8266 runtime is single-threaded, multiple timers firing at the same time will be processed sequentially in the order specified in the System::timers list. You are not expected to modify the timer itself from inside the handler.

The following methods are provided:

TimerAbsolute* System::getTimerAbsByID(const int id);     // Return absolute timer with a matching ID

Note that the library does not enforce ID uniqueness; if you rely on IDs, make sure they are unique. In the case there is more than one timer with a given ID, the method will return the first one found. nullptr is returned if ID does not exist.

Requires

Cooperates With

  • DS_CAP_SYS_LOG — if syslog is enabled, timer firing event will be logged;
  • DS_CAP_APP_LOG — if application log is enabled, timer firing event will be logged;
  • DS_CAP_WEB_TIMERS — if timer configuration by user is enabled, absolute timers will be offered as an option;

Conflicts With

None.

Usage

MySystem.h:

#define DS_CAP_SYS_TIME     // Enable system time
#define DS_CAP_TIMERS_ABS   // Enable timers from absolute time

#define DS_TIMEZONE TZ_Europe_Paris  // My timezone

sketch.ino:

#include "MySystem.h"

using namespace ds;

// Timer handler
void myTimerHandler(const TimerAbsolute* timer) {
    if (timer->getAction() == "lamp on") {

    // Turn the lamp on here ...
    }
}
void (*System::timerHandler)(const TimerAbsolute*) = myTimerHandler;  // Install the handler

void setup() {

   // Turn on the lamp at 18:15 every day
   System::timers.push_front(new TimerAbsolute("lamp on", 18, 15));
}

void loop() {
    System::update();
}

Mandatory Calls

System::begin() Not required
System::update() Required

Examples

Bugs

  • The implementation does not take into account system time corrections. For example, if you have a timer scheduled to run in one second from now, and NTP kicks in and advances the time by two seconds, the timer will be silently skipped. Similar problem may happen with daylight saving changes — a timer scheduled between 2 AM and 3 AM may fire twice, or not fire at all. It is thus recommended not to assign daily timers to this time interval.

Availability

Version 1.1 or later.

See Also

⚠️ **GitHub.com Fallback** ⚠️