New library for Scheduling Time Based Tasks

I suggest that you simplify the task by adding something like this function to show you the alarm time.

void  setAlarmp(int onhour,int onmin,int onsec )
{  
  Serial.println("The alarm will be set to:");
  Serial.println(onhour);
  Serial.println(onmin);
  Serial.println (onsec);
  Alarm.alarmRepeat(onhour,onmin,onsec, MorningAlarm);
}

If you can get the correct values displayed then the alarm should be set accordingly. If the values are not correct then you need to fix your sketch logic.

Managed to sort it out, just needed a break from it.

Heres the code

#include <Time.h>
#include <TimeAlarms.h>

void setup()
{
  Serial.begin(9600);    
  setTime(8,29,55,1,1,10); // set time to 8:29:40am Jan 1 2010
}
void  loop()
{  
  int onhour =8;
  int onmin = 30;
  int onsec = 0;
 
  void  setAlarm(int onhour,int onmin,int onsec );
{
  Serial.println("The alarm will be set to:");
  Serial.println(onhour);
  Serial.println(onmin);
  Serial.println (onsec);
  Alarm.alarmRepeat(onhour,onmin,onsec, MorningAlarm);
}
digitalClockDisplay();
  Alarm.delay (1000);
}
void MorningAlarm()
  {
     Serial.println("Alarm: - turn lights off");  
  }
 void digitalClockDisplay()
{
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}
void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Thanks for the help

Hi,
How can I pass a variable together with the function pointer?
Like this:
Alarm.alarmRepeat(onhour,onmin,onsec, MorningAlarm(1));

Thanks,
RI

hi newhobby, the previous library, DateTimeAlarms, passed a variable (an alarm identifier) when the alarm function was called and you can look at the source code to see how that was done: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1217881285/15

But the new library was simplified to make it easier to use – if you need to do something specific for each alarm type, you can have each using a separate function.

Perhaps if you explain the task you want to perform I can suggest a way to achieve this without the need for passing variables in the alarm function.

Hi mem,
I saw the previous library, but it was using an internal variable to be passed to the external function. I need an external variable to be passed to an external function.
What I'm trying to accomplish is scheduling of relays.
So, I have the parameters of the tasks being read from EEPROM and then created on setup().
Something like this:

  NumTasks=8;
  for (int a=0;a<NumTasks;a++)
  {
    EEPROM_readAnything(100,Task);
    Alarm.alarmRepeat(Task.OnTime, MorningAlarm(Task.RelayID));
  }

Would there be way to pass the function MorningAlarm the Task.RelayID that's being triggered?

You could add a field in the alarm class, something like:
class AlarmClass
{
private:
public:
AlarmClass();
OnTick_t onTickHandler;
void updateNextTrigger();
time_t value;
time_t nextTrigger;
AlarmMode_t Mode;
int tag; // new field
};

And set the value of tag in the alarm creation function. You would then use a similar callback to the one in the old library, but pass the tag instead of the alarm id.

But the disadvantage of this is that it adds one or two bytes of ram to every alarm, even if the tag is not used.

Bear in mind that your code fragment has 8 tasks but the default number of alarms is 6.
If you need 8 alarms and have not increased the value of dtNBR_ALARMS , you can do this in TimeAlarms.h

Could this be used to leave one state, and then return to it at current time?
I'm trying to get my LED's to dim throughout the day. But I have a couple of other states that I'd like to cycle through. If I can use your code to keep track of my Day program, dim in, clouds, etc, if I leave that section to cycle through the other sections, will it return to current time of the day program? If that makes sense at all.
Say if I my day program is going. I want to turn the white on, then 3 hours later return to the day program, 3 hours down the sketch, not where I left it.
The reason I ask, is it seems I could use this to schedule the different sections of day based on time without using a RTC. Thanks for your help.

hey again,

void setup()
{
  setTime(8,29,0,1,1,10); // set time to 8:29:00am Jan 1 2010
  // create the alarms 
  Alarm.alarmRepeat(8,30,0, MorningAlarm);  // 8:30am every day
  }

void  loop(){  
  control()



  Alarm.delay(0); // check if there is alarm
}

If my control() function contain some Alarm.delay() intruction, it will call the MorningAlarm() during control()
It may disturb control() ?

Can I use delay() only in the control() to avoid call the alarm function ?

@stolken, yes, alarms will not trigger if you do not call Alarm.delay (or another TimeAlarms library function that handles alarm servicing)

If an alarm is ready to trigger it will wait until the next call to Alarm.delay before calling the handler function

@LEDjunky I must have missed your previous post, if you still need help then post your question again.

If you are asking if you can schedule a function to be called at a particular time of day or after a specified interval, then yes you can do that with the TimeAlarms library. You can inspect and manipulative your application state variables in the alarm handler functions, indeed there are no special restrictions on what you can do in an alarm handler. Its just like any normal function you create in a sketch, but the function is only called when an alarm you create is triggered.

Thanks :wink:

Can alarms be reset? Let say, can I change specific alarm from 8 o'clock to 9.

Thank you all!!

Hi largich

The older version of this library (Arduino Playground - DateTime) used an explicit alarm id that provided the facility to change the value of any alarm. The Alarm ID was removed from the interface after feedback saying that this complexity made the interface more difficult for most users.

The new library still has a low level function that can change the value of an alarm but to use this you would need to figure out the correct alarm ID. This is easy if you have only one alarm – the ID will always be 0 (alarm IDs are allocated sequentially from 0).

So, if your sketch only sets a single alarm you can do something like the following.
It changes the alarm time based on the state of digital pin 2 at the time when the alarm is triggered.
Alarm.write can be called at any time to change the alarm time.

#include <Time.h>
#include <TimeAlarms.h>


AlarmID_t myAlarm = 0;  // this will be the ID for the first allocated alarm


time_t earlyAlarmTime = AlarmHMS(7,30,0) ; // 7:30 am
time_t lateAlarmTime = AlarmHMS(9,0,0) ;  // 9 am


void setup()
{
 
  setTime(8,29,40,1,1,10); // set time to 7:29:40am Jan 1 2010 
  Alarm.alarmRepeat(earlyAlarmTime, alarmEvent); // set the alarm time
 
}

void alarmEvent()
{
  Serial.println("Alarm");    
  // set a new alarm time based on the state of digital pin 2 
  if( digitalRead(2) == LOW)  
     Alarm.write(myAlarm , earlyAlarmTime);
  else  
     Alarm.write(myAlarm , lateAlarmTime);
}


void loop()
{

}

Thank you for fast response. I am setting new alarm times, but sadly I have trubles with fireing the events. If I change the time for the repeat timer from 7:30 to 7:31 (I chage it in the function call at 7:30) the second alarm doesn't trigger at 7:31.
Calling the function time_t read(AlarmID_t ID);
reveales that the new time is set.

Can you direct me, where could be the problem.
I know have to go trough the library code :slight_smile:

If you want to change the time for the next alarm in the alarm event handler then you can do this using alarmOnce instead of alarmRepeat.

#include <Time.h>
#include <TimeAlarms.h>

void setup()
{
  Serial.begin(9600);
  setTime(8,29,40,1,1,10); // set time to 7:29:40am Jan 1 2010 
  Alarm.alarmOnce(AlarmHMS(7,30,0), alarmEvent); // set the first alarm time to 7:30 am 
}

void alarmEvent()
{
  Serial.println("Alarm");    
  // set a new alarm time based on the state of digital pin 2 
  if( digitalRead(2) == LOW)  
     Alarm.alarmOnce(now() + 60, alarmEvent); // set the next alarm to trigger in one minute 
  else  
     Alarm.alarmOnce(now() + 120, alarmEvent); // set the next alarm to trigger in two minutes 
}


void loop()
{
}

But perhaps you want to do something else, can you say more about what your application needs to do.

Thanks for the swift replies.

I am making lights on/off project, where user can change the time settings (on-off) trough lcd user menu. I can make a workaround. I can check every minute if I need to turn the lights on or off, but it would be cleaner if i have an alarm for setting it on and one for setting it off.

Thank you for your help.

You could try something like this:

#include <Time.h>
#include <TimeAlarms.h>


AlarmID_t onAlarm = 0;  // this will be the ID for the first allocated alarm
AlarmID_t offAlarm = 1; // ID for the seconds alarm

time_t onTime = AlarmHMS(7,30,0) ; // 7:30 am
time_t offTime = AlarmHMS(10,0,0) ;  // 10 am


void setup()
{
  Serial.begin(9600);
  setTime(7,29,40,1,1,10); // set time to 7:29:40am Jan 1 2010
  Alarm.alarmRepeat(onTime, onAlarmEvent); // set the on alarm time
  Alarm.alarmRepeat(offTime, offAlarmEvent); // set the off alarm time

}

void onAlarmEvent()
{
  Serial.println("Alarm On");

}

void offAlarmEvent()
{
  Serial.println("Alarm Off");

}

void loop()
{
  // add your code here to get a new on time
   time_t newOnTime = now() + 60;  // this should be replaced with a call to the LCD menu to get the time
   Alarm.write(onAlarm , newOnTime);
   Alarm.enable(onAlarm); // this will reschedule the alarm
   
   // code here to get a new off time
   time_t newOffTime = now() + 70;
   Alarm.write(offAlarm , newOffTime);
   Alarm.enable(offAlarm); // this will reschedule the alarm

   Alarm.delay(120000); // wait two minutes
}

Great :D. That Alarm.enable is what was missing. I misunderstood the readme file, I guess.

You're the man!!! Thanks.

I had a closer look at the library source and realized that the alarm ID is returned when the alarm is created so you can use this ensure that the correct ID is used when writing new values. Here is the updated code:

#include <Time.h>
#include <TimeAlarms.h>

AlarmID_t onAlarm ;  // the ID for the alarms will be assigned when the alarm is created in setup
AlarmID_t offAlarm;

time_t onTime = AlarmHMS(7,30,0) ; // 7:30 am
time_t offTime = AlarmHMS(10,0,0) ;  // 10 am

void setup()
{
  Serial.begin(9600);
  setTime(7,29,40,1,1,10); // set time to 7:29:40am Jan 1 2010
  onAlarm = Alarm.alarmRepeat(onTime, onAlarmEvent); // set the on alarm time
  offAlarm = Alarm.alarmRepeat(offTime, offAlarmEvent); // set the off alarm time
}

void onAlarmEvent()
{
  Serial.println("Alarm On");
}

void offAlarmEvent()
{
  Serial.println("Alarm Off");
}

void loop()
{
  // add your code here to get a new on time
   time_t newOnTime = now() + 60;  // this should be replaced with a call to the LCD menu to get the time
   Alarm.write(onAlarm , newOnTime);
   Alarm.enable(onAlarm); // this will reschedule the alarm
   
   // code here to get a new off time
   time_t newOffTime = now() + 70;
   Alarm.write(offAlarm , newOffTime);
   Alarm.enable(offAlarm); // this will reschedule the alarm
}

Thanks again. I also updated write(...) function in my alarms library. A reset the nexTriger time property to something small so every time the alarm gets updated is also updates the next trigger time. Useful also if you change the clock time. With the write function you can also reset the alarms/timers.

// write the given value to the given alarm
void TimeAlarmsClass::write(AlarmID_t ID, time_t value)
{
  if(ID < dtNBR_ALARMS && Alarm[ID].Mode.isAllocated){
    Alarm[ID].value = value;
    Alarm[ID].nextTrigger=1; //new row
    enable(ID);
  }
}

Testing this solution was succesful (for now).

Regards.