daily_automated

This commit is contained in:
topicchi
2023-03-17 11:59:21 +00:00
parent 252ecca9cf
commit e2f276193e
4496 changed files with 1178007 additions and 0 deletions

View File

@@ -0,0 +1,295 @@
/*
TimeAlarms.cpp - Arduino Time alarms for use with Time library
Copyright (c) 2008-2011 Michael Margolis.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
*/
/*
2 July 2011 - replaced alarm types implied from alarm value with enums to make trigger logic more robust
- this fixes bug in repeating weekly alarms - thanks to Vincent Valdy and draythomp for testing
*/
#include "ESP8266TimeAlarms.h"
#define IS_ONESHOT true // constants used in arguments to create method
#define IS_REPEAT false
//**************************************************************
//* Alarm Class Constructor
AlarmClass::AlarmClass()
{
Mode.isEnabled = Mode.isOneShot = 0;
Mode.alarmType = dtNotAllocated;
value = nextTrigger = 0;
onTickHandler = NULL; // prevent a callback until this pointer is explicitly set
}
//**************************************************************
//* Private Methods
void AlarmClass::updateNextTrigger()
{
if (Mode.isEnabled) {
time_t now = time(nullptr);
if (dtIsAlarm(Mode.alarmType) && nextTrigger <= now) {
// update alarm if next trigger is not yet in the future
if (Mode.alarmType == dtExplicitAlarm) {
// is the value a specific date and time in the future
nextTrigger = value; // yes, trigger on this value
} else if (Mode.alarmType == dtDailyAlarm) {
//if this is a daily alarm
if (value + previousMidnight(now) <= now) {
// if time has passed then set for tomorrow
nextTrigger = value + nextMidnight(now);
} else {
// set the date to today and add the time given in value
nextTrigger = value + previousMidnight(now);
}
} else if (Mode.alarmType == dtWeeklyAlarm) {
// if this is a weekly alarm
if ((value + previousSunday(now)) <= now) {
// if day has passed then set for the next week.
nextTrigger = value + nextSunday(now);
} else {
// set the date to this week today and add the time given in value
nextTrigger = value + previousSunday(now);
}
} else {
// its not a recognized alarm type - this should not happen
Mode.isEnabled = false; // Disable the alarm
}
}
if (Mode.alarmType == dtTimer) {
// its a timer
nextTrigger = now + value; // add the value to previous time (this ensures delay always at least Value seconds)
}
}
}
//**************************************************************
//* Time Alarms Public Methods
TimeAlarmsClass::TimeAlarmsClass()
{
isServicing = false;
for(uint8_t id = 0; id < dtNBR_ALARMS; id++) {
free(id); // ensure all Alarms are cleared and available for allocation
}
}
void TimeAlarmsClass::enable(AlarmID_t ID)
{
if (isAllocated(ID)) {
if (( !(dtUseAbsoluteValue(Alarm[ID].Mode.alarmType) && (Alarm[ID].value == 0)) ) && (Alarm[ID].onTickHandler != NULL)) {
// only enable if value is non zero and a tick handler has been set
// (is not NULL, value is non zero ONLY for dtTimer & dtExplicitAlarm
// (the rest can have 0 to account for midnight))
Alarm[ID].Mode.isEnabled = true;
Alarm[ID].updateNextTrigger(); // trigger is updated whenever this is called, even if already enabled
} else {
Alarm[ID].Mode.isEnabled = false;
}
}
}
void TimeAlarmsClass::disable(AlarmID_t ID)
{
if (isAllocated(ID)) {
Alarm[ID].Mode.isEnabled = false;
}
}
// write the given value to the given alarm
void TimeAlarmsClass::write(AlarmID_t ID, time_t value)
{
if (isAllocated(ID)) {
Alarm[ID].value = value; //note: we don't check value as we do it in enable()
Alarm[ID].nextTrigger = 0; // clear out previous trigger time (see issue #12)
enable(ID); // update trigger time
}
}
// return the value for the given alarm ID
time_t TimeAlarmsClass::read(AlarmID_t ID)
{
if (isAllocated(ID)) {
return Alarm[ID].value ;
} else {
return dtINVALID_TIME;
}
}
// return the alarm type for the given alarm ID
dtAlarmPeriod_t TimeAlarmsClass::readType(AlarmID_t ID)
{
if (isAllocated(ID)) {
return (dtAlarmPeriod_t)Alarm[ID].Mode.alarmType ;
} else {
return dtNotAllocated;
}
}
void TimeAlarmsClass::free(AlarmID_t ID)
{
if (isAllocated(ID)) {
Alarm[ID].Mode.isEnabled = false;
Alarm[ID].Mode.alarmType = dtNotAllocated;
Alarm[ID].onTickHandler = NULL;
Alarm[ID].value = 0;
Alarm[ID].nextTrigger = 0;
}
}
// returns the number of allocated timers
uint8_t TimeAlarmsClass::count()
{
uint8_t c = 0;
for(uint8_t id = 0; id < dtNBR_ALARMS; id++) {
if (isAllocated(id)) c++;
}
return c;
}
// returns true only if id is allocated and the type is a time based alarm, returns false if not allocated or if its a timer
bool TimeAlarmsClass::isAlarm(AlarmID_t ID)
{
return( isAllocated(ID) && dtIsAlarm(Alarm[ID].Mode.alarmType) );
}
// returns true if this id is allocated
bool TimeAlarmsClass::isAllocated(AlarmID_t ID)
{
return (ID < dtNBR_ALARMS && Alarm[ID].Mode.alarmType != dtNotAllocated);
}
// returns the currently triggered alarm id
// returns dtINVALID_ALARM_ID if not invoked from within an alarm handler
AlarmID_t TimeAlarmsClass::getTriggeredAlarmId()
{
if (isServicing) {
return servicedAlarmId; // new private data member used instead of local loop variable i in serviceAlarms();
} else {
return dtINVALID_ALARM_ID; // valid ids only available when servicing a callback
}
}
// following functions are not Alarm ID specific.
void TimeAlarmsClass::delay(unsigned long ms)
{
unsigned long start = millis();
while (millis() - start <= ms) {
serviceAlarms();
}
}
void TimeAlarmsClass::waitForDigits( uint8_t Digits, dtUnits_t Units)
{
while (Digits != getDigitsNow(Units)) {
serviceAlarms();
}
}
void TimeAlarmsClass::waitForRollover( dtUnits_t Units)
{
// if its just rolled over than wait for another rollover
while (getDigitsNow(Units) == 0) {
serviceAlarms();
}
waitForDigits(0, Units);
}
uint8_t TimeAlarmsClass::getDigitsNow( dtUnits_t Units)
{
time_t now = time(nullptr);
struct tm *NOW = localtime(&now);
if (Units == dtSecond) return NOW->tm_sec;
if (Units == dtMinute) return NOW->tm_min;
if (Units == dtHour) return NOW->tm_hour;
if (Units == dtDay) return NOW->tm_wday;
return 255; // This should never happen
}
//returns isServicing
bool TimeAlarmsClass::getIsServicing()
{
return isServicing;
}
//***********************************************************
//* Private Methods
void TimeAlarmsClass::serviceAlarms()
{
if (!isServicing) {
time_t now = time(nullptr);
isServicing = true;
for (servicedAlarmId = 0; servicedAlarmId < dtNBR_ALARMS; servicedAlarmId++) {
if (Alarm[servicedAlarmId].Mode.isEnabled && (now >= Alarm[servicedAlarmId].nextTrigger)) {
OnTick_t TickHandler = Alarm[servicedAlarmId].onTickHandler;
if (Alarm[servicedAlarmId].Mode.isOneShot) {
free(servicedAlarmId); // free the ID if mode is OnShot
} else {
Alarm[servicedAlarmId].updateNextTrigger();
}
if (TickHandler != NULL) {
TickHandler(); // call the handler
}
}
}
isServicing = false;
}
}
// returns the absolute time of the next scheduled alarm, or 0 if none
time_t TimeAlarmsClass::getNextTrigger()
{
time_t nextTrigger = (time_t)0xffffffff; // the max time value
for (uint8_t id = 0; id < dtNBR_ALARMS; id++) {
if (isAllocated(id)) {
if (Alarm[id].nextTrigger < nextTrigger) {
nextTrigger = Alarm[id].nextTrigger;
}
}
}
return nextTrigger == (time_t)0xffffffff ? 0 : nextTrigger;
}
// attempt to create an alarm and return true if successful
AlarmID_t TimeAlarmsClass::create(time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType)
{
time_t now = time(nullptr);
if ( ! ( (dtIsAlarm(alarmType) && now < SECS_PER_YEAR) || (dtUseAbsoluteValue(alarmType) && (value == 0)) ) ) {
// only create alarm ids if the time is at least Jan 1 1971
for (uint8_t id = 0; id < dtNBR_ALARMS; id++) {
if (Alarm[id].Mode.alarmType == dtNotAllocated) {
// here if there is an Alarm id that is not allocated
Alarm[id].onTickHandler = onTickHandler;
Alarm[id].Mode.isOneShot = isOneShot;
Alarm[id].Mode.alarmType = alarmType;
Alarm[id].value = value;
enable(id);
return id; // alarm created ok
}
}
}
return dtINVALID_ALARM_ID; // no IDs available or time is invalid
}
// make one instance for the user to use
TimeAlarmsClass Alarm = TimeAlarmsClass() ;

View File

@@ -0,0 +1,241 @@
// TimeAlarms.h - Arduino Time alarms header for use with Time library
#ifndef TimeAlarms_h
#define TimeAlarms_h
#include <Arduino.h>
#include <time.h>
#if !defined(dtNBR_ALARMS )
#if defined(__AVR__)
#define dtNBR_ALARMS 6 // max is 255
#elif defined(ESP8266)
#define dtNBR_ALARMS 20 // for esp8266 chip - max is 255
#else
#define dtNBR_ALARMS 12 // assume non-AVR has more memory
#endif
#endif
#define USE_SPECIALIST_METHODS // define this for testing
typedef enum {
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
} timeDayOfWeek_t;
#define SECS_PER_MIN ((time_t)(60UL))
#define SECS_PER_HOUR ((time_t)(3600UL))
#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL))
#define DAYS_PER_WEEK ((time_t)(7UL))
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK))
#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years
#define secs_per_year(y) ((time_t)(SECS_PER_DAY * year_lengths[isleap(y)]))
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
/* Useful Macros for getting elapsed time */
#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN)
#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN)
#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR)
#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday
#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970
#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight
// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971
// Always set the correct time before settting alarms
#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day
#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // note that week starts on day 1
#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time
#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time
static const int year_lengths[2] = {
365,
366
} ;
typedef enum {
dtMillisecond,
dtSecond,
dtMinute,
dtHour,
dtDay
} dtUnits_t;
typedef struct {
uint8_t alarmType :4 ; // enumeration of daily/weekly (in future:
// biweekly/semimonthly/monthly/annual)
// note that the current API only supports daily
// or weekly alarm periods
uint8_t isEnabled :1 ; // the timer is only actioned if isEnabled is true
uint8_t isOneShot :1 ; // the timer will be de-allocated after trigger is processed
} AlarmMode_t;
// new time based alarms should be added just before dtLastAlarmType
typedef enum {
dtNotAllocated,
dtTimer,
dtExplicitAlarm,
dtDailyAlarm,
dtWeeklyAlarm,
dtLastAlarmType
} dtAlarmPeriod_t ; // in future: dtBiweekly, dtMonthly, dtAnnual
// macro to return true if the given type is a time based alarm, false if timer or not allocated
#define dtIsAlarm(_type_) (_type_ >= dtExplicitAlarm && _type_ < dtLastAlarmType)
#define dtUseAbsoluteValue(_type_) (_type_ == dtTimer || _type_ == dtExplicitAlarm)
typedef uint8_t AlarmID_t;
typedef AlarmID_t AlarmId; // Arduino friendly name
#define dtINVALID_ALARM_ID 255
#define dtINVALID_TIME (time_t)(-1)
//#define AlarmHMS(_hr_, _min_, _sec_) (_hr_ * SECS_PER_HOUR + _min_ * SECS_PER_MIN + _sec_)
//Hack to get timezone and stuff working
#ifdef ARDUINO_ARCH_ESP8266
#include <functional>
typedef std::function<void()> OnTick_t;
#else
typedef void (*OnTick_t)(); // alarm callback function typedef
#endif
// class defining an alarm instance, only used by dtAlarmsClass
class AlarmClass
{
public:
AlarmClass();
OnTick_t onTickHandler;
void updateNextTrigger();
time_t value;
time_t nextTrigger;
AlarmMode_t Mode;
};
// class containing the collection of alarms
class TimeAlarmsClass
{
private:
AlarmClass Alarm[dtNBR_ALARMS];
void serviceAlarms();
uint8_t isServicing;
uint8_t servicedAlarmId; // the alarm currently being serviced
AlarmID_t create(time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType);
public:
TimeAlarmsClass();
//Translate Alarm time from localtime in to epochtime this will handle timezone things
int AlarmHMS(int H, int M, int S) {
time_t t1,t2;
struct tm tma;
time(&t1);
localtime_r(&t1, &tma);
tma.tm_hour = H;
tma.tm_min = M;
tma.tm_sec = S;
t2 = mktime(&tma);
return t2-previousMidnight(t1);
}
// functions to create alarms and timers
// trigger once at the given time in the future
AlarmID_t triggerOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtExplicitAlarm);
}
// trigger once at given time of day
AlarmID_t alarmOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0 || value > SECS_PER_DAY) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtDailyAlarm);
}
AlarmID_t alarmOnce(const int H, const int M, const int S, OnTick_t onTickHandler) {
return alarmOnce(AlarmHMS(H,M,S), onTickHandler);
}
// trigger once on a given day and time
AlarmID_t alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler) {
time_t value = (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S);
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtWeeklyAlarm);
}
// trigger daily at given time of day
AlarmID_t alarmRepeat(time_t value, OnTick_t onTickHandler) {
if (value > SECS_PER_DAY) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtDailyAlarm);
}
AlarmID_t alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler) {
return alarmRepeat(AlarmHMS(H,M,S), onTickHandler);
}
// trigger weekly at a specific day and time
AlarmID_t alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler) {
time_t value = (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S);
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtWeeklyAlarm);
}
// trigger once after the given number of seconds
AlarmID_t timerOnce(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, true, dtTimer);
}
AlarmID_t timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler) {
return timerOnce(AlarmHMS(H,M,S), onTickHandler);
}
// trigger at a regular interval
AlarmID_t timerRepeat(time_t value, OnTick_t onTickHandler) {
if (value <= 0) return dtINVALID_ALARM_ID;
return create(value, onTickHandler, false, dtTimer);
}
AlarmID_t timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler) {
return timerRepeat(AlarmHMS(H,M,S), onTickHandler);
}
void delay(unsigned long ms);
// utility methods
uint8_t getDigitsNow( dtUnits_t Units); // returns the current digit value for the given time unit
void waitForDigits( uint8_t Digits, dtUnits_t Units);
void waitForRollover(dtUnits_t Units);
// low level methods
void enable(AlarmID_t ID); // enable the alarm to trigger
void disable(AlarmID_t ID); // prevent the alarm from triggering
AlarmID_t getTriggeredAlarmId(); // returns the currently triggered alarm id
bool getIsServicing(); // returns isServicing
void write(AlarmID_t ID, time_t value); // write the value (and enable) the alarm with the given ID
time_t read(AlarmID_t ID); // return the value for the given timer
dtAlarmPeriod_t readType(AlarmID_t ID); // return the alarm type for the given alarm ID
void free(AlarmID_t ID); // free the id to allow its reuse
#ifndef USE_SPECIALIST_METHODS
private: // the following methods are for testing and are not documented as part of the standard library
#endif
uint8_t count(); // returns the number of allocated timers
time_t getNextTrigger(); // returns the time of the next scheduled alarm
bool isAllocated(AlarmID_t ID); // returns true if this id is allocated
bool isAlarm(AlarmID_t ID); // returns true if id is for a time based alarm, false if its a timer or not allocated
};
extern TimeAlarmsClass Alarm; // make an instance for the user
/*==============================================================================
* MACROS
*============================================================================*/
/* public */
#define waitUntilThisSecond(_val_) waitForDigits( _val_, dtSecond)
#define waitUntilThisMinute(_val_) waitForDigits( _val_, dtMinute)
#define waitUntilThisHour(_val_) waitForDigits( _val_, dtHour)
#define waitUntilThisDay(_val_) waitForDigits( _val_, dtDay)
#define waitMinuteRollover() waitForRollover(dtSecond)
#define waitHourRollover() waitForRollover(dtMinute)
#define waitDayRollover() waitForRollover(dtHour)
#endif /* TimeAlarms_h */

View File

@@ -0,0 +1,143 @@
TimeAlarms for ESP arduino version 2.4.0 using newlibc time
The ESP8266TimeAlarm is no longer dependen on the Time library
Tasks scheduled at a particular time of day are called Alarms,
tasks scheduled after an interval of time has elapsed are called Timers.
These tasks can be created to continuously repeat or to occur once only.
Here is how you create an alarm to trigger a task repeatedly at a particular time of day:
Alarm.alarmRepeat(8,30,0, MorningAlarm);
This would call the function MorningAlarm() at 8:30 am every day.
If you want the alarm to trigger only once you can use the alarmOnce method:
Alarm.alarmOnce(8,30,0, MorningAlarm);
This calls a MorningAlarm() function in a sketch once only (when the time is next 8:30am)
Alarms can be specified to trigger a task repeatedly at a particular day of week and time of day:
Alarm.alarmRepeat(dowMonday, 9,15,0, MondayMorningAlarm);
This would call the function WeeklyAlarm() at 9:15am every Monday.
If you want the alarm to trigger once only on a particular day and time you can do this:
Alarm.alarmOnce(dowMonday, 9,15,0, MondayMorningAlarm);
This would call the function MondayMorning() Alarm on the next Monday at 9:15am.
Timers trigger tasks that occur after a specified interval of time has passed.
The timer interval can be specified in seconds, or in hour, minutes and seconds.
Alarm.timerRepeat(15, Repeats); // timer task every 15 seconds
This calls the Repeats() function in your sketch every 15 seconds.
If you want a timer to trigger once only, you can use the timerOnce method:
Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds
This calls the onceOnly() function in a sketch 10 seconds after the timer is created.
If you want to trigger once at a specified date and time you can use the trigger Once() method:
Alarm. triggerOnce(time_t value, explicitAlarm); // value specifies a date and time
(See the makeTime() method in the Time library to convert dates and times into time_t)
Your sketch should call the Alarm.delay() function instead of the Arduino delay() function when
using the Alarms library. The timeliness of triggers depends on sketch delays using this function.
Alarm.delay( period); // Similar to Arduino delay - pauses the program for the period (in milliseconds).
Functional reference:
// functions to create alarms and timers
Alarm.triggerOnce(value, AlarmFunction);
Description: Call user provided AlarmFunction once at the date and time of the given value
See the Ttime library for more on time_t values
Alarm.alarmRepeat(Hour, Minute, Second, AlarmFunction);
Description: Calls user provided AlarmFunction every day at the given Hour, Minute and Second.
Alarm.alarmRepeat(value, AlarmFunction);
Description: Calls user provided AlarmFunction every day at the time indicated by the given value
Alarm.alarmRepeat(DayOfWeek, Hour, Minute, Second, AlarmFunction);
Description: Calls user provided AlarmFunction every week on the given DayOfWeek, Hour, Minute and Second.
Alarm.alarmOnce(Hour, Minute, Second, AlarmFunction);
Description: Calls user provided AlarmFunction once when the Arduino time next reaches the given Hour, Minute and Second.
Alarm.alarmOnce(value, AlarmFunction);
Description: Calls user provided AlarmFunction once at the next time indicated by the given value
Alarm.alarmOnce(DayOfWeek, Hour, Minute, Second, AlarmFunction);
Description: Calls user provided AlarmFunction once only on the next DayOfWeek, Hour, Minute and Second.
Alarm.timerRepeat(Period, TimerFunction);
Description: Continuously calls user provided TimerFunction after the given period in seconds has elapsed.
Alarm.timerRepeat(Hour, Minute, Second, TimerFunction);
Description: As timerRepeat above, but period is the number of seconds in the given Hour, Minute and Second parameters
Alarm.timerOnce(Period, TimerFunction);
Description: Calls user provided TimerFunction once only after the given period in seconds has elapsed.
Alarm.timerOnce(Hour, Minute, Second, TimerFunction);
Description: As timerOnce above, but period is the number of seconds in the given Hour, Minute and Second parameters
Alarm.delay( period)
Description: Similar to Arduino delay - pauses the program for the period (in miliseconds) specified.
Call this function rather than the Arduino delay function when using the Alarms library.
The timeliness of the triggers depends on sketch delays using this function.
Low level functions not usually required for typical applications:
disable( ID); - prevent the alarm associated with the given ID from triggering
enable(ID); - enable the alarm
write(ID, value); - write the value (and enable) the alarm for the given ID
read(ID); - return the value for the given ID
readType(ID); - return the alarm type for the given alarm ID
getTriggeredAlarmId(); - returns the currently triggered alarm id, only valid in an alarm callback
FAQ
Q: What hardware and software is needed to use this library?
A: This library requires the Time library. No internal or external hardware is used by the Alarm library.
Q: Why must I use Alarm.delay() instead of delay()?
A: Task scheduling is handled in the Alarm.delay function.
Tasks are monitored and triggered from within the Alarm.delay call so Alarm.delay should be called
whenever a delay is required in your sketch.
If your sketch waits on an external event (for example, a sensor change),
make sure you repeatedly call Alarm.delay while checking the sensor.
You can call Alarm.delay(0) if you need to service the scheduler without a delay.
Q: Are there any restrictions on the code in a task handler function?
A: No. The scheduler does not use interrupts so your task handling function is no
different from other functions you create in your sketch.
Q: What are the shortest and longest intervals that can be scheduled?
A: Time intervals can range from 1 second to years.
(If you need timer intervals shorter than 1 second then the TimedAction library
by Alexander Brevig may be more suitable, see: http://www.arduino.cc/playground/Code/TimedAction)
Q: How are scheduled tasks affected if the system time is changed?
A: Tasks are scheduled for specific times designated by the system clock.
If the system time is reset to a later time (for example one hour ahead) then all
alarms and timers will occur one hour later.
If the system time is set backwards (for example one hour back) then the alarms and timers will occur an hour earlier.
If the time is reset before the time a task was scheduled, then the task will be triggered on the next service (the next call to Alarm.delay).
This is the expected behaviour for Alarms – tasks scheduled for a specific time of day will trigger at that time, but the affect on timers may not be intuitive. If a timer is scheduled to trigger in 5 minutes time and the clock is set ahead by one hour, that timer will not trigger until one hour and 5 minutes has elapsed.
Q: What is the valid range of times supported by these libraries?
A: The time library is intended to handle times from Jan 1 1970 through Jan 19 2038.
The Alarms library expects dates to be on or after Jan1 1971 so clocks should no be set earlier than this if using Alarms.
(The functions to create alarms will return an error if an earlier date is given).
Q: How many alarms can be created?
A: Up to six alarms can be scheduled.
The number of alarms can be changed in the TimeAlarms header file (set by the constant dtNBR_ALARMS,
note that the RAM used equals dtNBR_ALARMS * 11)
onceOnly Alarms and Timers are freed when they are triggered so another onceOnly alarm can be set to trigger again.
There is no limit to the number of times a onceOnly alarm can be reset.
The following fragment gives one example of how a timerOnce task can be rescheduled:
Alarm.timerOnce(random(10), randomTimer); // trigger after random number of seconds
void randomTimer(){
int period = random(2,10); // get a new random period
Alarm.timerOnce(period, randomTimer); // trigger for another random period
}

View File

@@ -0,0 +1,103 @@
/*
* TimeAlarmExample.ino
*
* This example calls alarm functions at 8:30 am and at 5:45 pm (17:45)
* and simulates turning lights on at night and off in the morning
* A weekly timer is set for Saturdays at 8:30:30
*
* A timer is called every 15 seconds
* Another timer is called once only after 10 seconds
*
* At startup the time is set using sntp via configTime
*/
// Questions? Ask them here:
// http://forum.arduino.cc/index.php?topic=66054.0
#include <ESP8266TimeAlarms.h>
#include "WifiConfig.h"
#include <ESP8266WiFi.h>
#ifndef WIFI_CONFIG_H
#define YOUR_WIFI_SSID "...."
#define YOUR_WIFI_PASSWD "..."
#endif // !WIFI_CONFIG_H
AlarmId id;
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.begin(YOUR_WIFI_SSID, YOUR_WIFI_PASSWD);
configTime(0, 0, "0.se.pool.ntp.org");
//Europe/Stockholm": "CET-1CEST,M3.5.0,M10.5.0/3"
//Get JSON of Olson to TZ string using this code https://github.com/pgurenko/tzinfo
setenv("TZ", "CET-1CEST,M3.5.0/2,M10.5.0/3", 1);
tzset();
Serial.print("Clock before sync: ");
digitalClockDisplay();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.print("Clock after Wifi: ");
// create the alarms, to trigger at specific times
Alarm.alarmRepeat(8,30,0, MorningAlarm); // 8:30am every day
Alarm.alarmRepeat(17,45,0,EveningAlarm); // 5:45pm every day
Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm); // 8:30:30 every Saturday
// create timers, to trigger relative to when they're created
Alarm.timerRepeat(15, Repeats); // timer for every 15 seconds
id = Alarm.timerRepeat(2, Repeats2); // timer for every 2 seconds
Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds
}
void loop() {
digitalClockDisplay();
Alarm.delay(1000); // wait one second between clock display
}
// functions to be called when an alarm triggers:
void MorningAlarm() {
Serial.println("Alarm: - turn lights off");
}
void EveningAlarm() {
Serial.println("Alarm: - turn lights on");
}
void WeeklyAlarm() {
Serial.println("Alarm: - its Monday Morning");
}
void ExplicitAlarm() {
Serial.println("Alarm: - this triggers only at the given date and time");
}
void Repeats() {
Serial.println("15 second timer");
}
void Repeats2() {
Serial.println("2 second timer");
}
void OnceOnly() {
Serial.println("This timer only triggers once, stop the 2 second timer");
// use Alarm.free() to disable a timer and recycle its memory.
Alarm.free(id);
// optional, but safest to "forget" the ID after memory recycled
id = dtINVALID_ALARM_ID;
// you can also use Alarm.disable() to turn the timer off, but keep
// it in memory, to turn back on later with Alarm.enable().
}
void digitalClockDisplay() {
time_t tnow = time(nullptr);
Serial.println(ctime(&tnow));
}

View File

@@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map For TimeAlarms
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
AlarmId LITERAL2
#######################################
# Methods and Functions (KEYWORD2)
#######################################
TimeAlarms KEYWORD2
triggerOnce KEYWORD2
alarmRepeat KEYWORD2
alarmOnce KEYWORD2
timerRepeat KEYWORD2
timerOnce KEYWORD2
enable KEYWORD2
disable KEYWORD2
free KEYWORD2
delay KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
Alarm KEYWORD1
#######################################
# Constants (LITERAL1)
#######################################
dtINVALID_ALARM_ID LITERAL1
dtINVALID_TIME LITERAL1

View File

@@ -0,0 +1,17 @@
{
"name": "ESP8266TimeAlarms",
"frameworks": ["Arduino"],
"keywords": "Time, alarm, schedule, date, hour, minute, second, day, week, month, year",
"description": "ESP8266 v2.4.0+ Schedule alarms to occur at specific times",
"url": "http://playground.arduino.cc/Code/Time",
"authors":
{
"name": "Michael Margolis",
"name": "Jonas Hagberg"
},
"repository":
{
"type": "git",
"url": "https://github.com/jhagberg/ESP8266TimeAlarms"
}
}

View File

@@ -0,0 +1,10 @@
name=ESP8266TimeAlarms
version=1.5
author=Michael Margolis
maintainer=Paul Stoffregen
sentence=Perform tasks at specific times or after specific intervals.
paragraph=The Alarm library is a companion to the Time library that makes it easy to perform tasks at specific times or after specific intervals. Tasks scheduled at a particular time of day are called Alarms, tasks scheduled after an interval of time has elapsed are called Timers. These tasks can be created to continuously repeat or to occur once only.
category=Timing
url=http://playground.arduino.cc/code/time
architectures=*