daily_automated
This commit is contained in:
295
trunk/Arduino/libraries/ESP8266TimeAlarms/ESP8266TimeAlarms.cpp
Normal file
295
trunk/Arduino/libraries/ESP8266TimeAlarms/ESP8266TimeAlarms.cpp
Normal 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() ;
|
||||
|
||||
241
trunk/Arduino/libraries/ESP8266TimeAlarms/ESP8266TimeAlarms.h
Normal file
241
trunk/Arduino/libraries/ESP8266TimeAlarms/ESP8266TimeAlarms.h
Normal 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 */
|
||||
143
trunk/Arduino/libraries/ESP8266TimeAlarms/README.md
Normal file
143
trunk/Arduino/libraries/ESP8266TimeAlarms/README.md
Normal 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
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
30
trunk/Arduino/libraries/ESP8266TimeAlarms/keywords.txt
Normal file
30
trunk/Arduino/libraries/ESP8266TimeAlarms/keywords.txt
Normal 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
|
||||
17
trunk/Arduino/libraries/ESP8266TimeAlarms/library.json
Normal file
17
trunk/Arduino/libraries/ESP8266TimeAlarms/library.json
Normal 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"
|
||||
}
|
||||
}
|
||||
10
trunk/Arduino/libraries/ESP8266TimeAlarms/library.properties
Normal file
10
trunk/Arduino/libraries/ESP8266TimeAlarms/library.properties
Normal 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=*
|
||||
|
||||
Reference in New Issue
Block a user