Time Alarms - Alarm getting triggered before scheduled time

Hello.
I am using the TimeAlarms lib port from Arduino and it works except that the Alarms get triggered before the time I have scheduled.
Here is my code:

#include "TimeAlarms/TimeAlarms.h"
#undef now()

SYSTEM_THREAD(ENABLED);

const int led2 = D7;

void setup()
{
  #if (PLATFORM_ID==6)  // for Photon Time issue
  while(Time.year() < 2000) Spark.process(); // wait for Time to sync
  #endif

  Time.zone(+2);
  
  pinMode(led2, OUTPUT);
  Serial.begin();
  
  

  Alarm.alarmRepeat(15, 2, 0,  ONAlarm);
  Alarm.alarmRepeat(16, 30, 0, OFFAlarm);   

  
   wd = new ApplicationWatchdog(60000, System.reset, 1536);
}

void ONAlarm()
{
    isOff = false;
    
    Particle.publish("Alarm", "ON");
    Serial.println("ON " + Time.timeStr() );
    
    digitalWrite(led2, HIGH);
    
    if(isOff == false)
    {
        Alarm.enable(lightOnAlarm);
        Alarm.enable(lightOffAlarm);
        lightOffAlarm = Alarm.timerRepeat(10, offLight);
        lightOnAlarm = Alarm.timerRepeat(20, onLight);     
       
    }
    
    Serial.println(isOff);
    

}

void OFFAlarm()
{
    isOff = true;
    
    Particle.publish("Alarm", "OFF");
    Serial.println("OFF " + Time.timeStr());
    
    Alarm.disable(lightOnAlarm);
    Alarm.disable(lightOffAlarm);
    
    digitalWrite(led2, LOW);   
}

void loop()
{

  Alarm.delay(1000);

    // RESETS THE AWDT COUNT     
    wd->checkin(); 
}

void offLight()
{
    Serial.println("OFF light TIMER " + Time.timeStr() );
    digitalWrite(led2, LOW);
}

void onLight()
{
    Serial.println("ON light TIMER " + Time.timeStr() );
    digitalWrite(led2, HIGH);
}

So TimeAlarms was ported before the current Time object in Particle was fully done. I think the time zone interaction is hurting you here–are the results you are seeing 2 hours off?

If not, how are the results wrong? Can you provide a quick example?

Yeah well the output is correct, that is the interesting part. So I am printing out the time and the time shown is correct. But as you can see I am printing Time.timeStr(); which I’m assuming doesn’t mean that Alarms have the same opinion on what the current time is… (although it knows when it should be triggered, just that it triggers too early every time as well)

So what happens is when I turn on the device, the Alarm gets triggered immediately. And as I wrote this I tried to put the OffAlarm at 13:30 (currently 10:00 here) and it still went off immediately. I also know that when the time reaches the time where the alarm should trigger, it triggers again. So if I put the Alarm at 13:30, and let the device run until then, the OffAlarm will trigger again at 13:30.

1 Like

Any solution to this then?

Hi,
I never used the lib you mention. But last time I used the time to schedule things, what got me in trouble was NOT checking it was valid before using it (as recommended in the docs, can’t find the statement now).

This is what I did at setup():

  waitFor(Time.isValid, 150000);
  if (Time.isValid())
    // show must go on

is it perhaps worth trying? Cheers

2 Likes

I tried to reproduce this just now on a Photon. I had to edit the program quit a bit to get it to compile in the web IDE. I made new bool global for isOff and commented out the watchdog stuff which has bad scope being defined in setup() not globally. I also commented out the calls to Alarm.enable() and Alarm.timerRepeat() which also did not compile. I’m sure that’s because you simplified your actual program but there isn’t much I can do with what is there.

I did not get the blue LED turning on, nor did I get the event saying the alarm is ON at startup. So this not reproducible in the fixed up code.

I guess I should ask what you are trying to do with the calls to Alarm.enable and Alarm.timerRepeat? The code has some strange stuff, like setting isOff to false and then 5 lines later saying if(isOff==false).

2 Likes

Ok so what I am trying to do is to implement a schedule that activates at a certain time. There should be an On schedule and an Off schedule. During the scheduled time, the device (LED in this case) should turn on and every x hours and turn off after 60 seconds. When the Off schedule gets activated, everything should turn off and not to anything until On schedule gets activated.

The reason why I use that boolean is because the alarm doesn’t actually turn off ever, so this is my current workaround. I’m open to other suggestions if there are any.

And I’m not quite sure how it didn’t compile for you with timerRepeat and enable? That seems strange since it is a part of the library.

Regarding the watchdog, so I should define it outside of setup? Although according to the docs, we are doing it correctly.
https://docs.particle.io/reference/device-os/firmware/#application-watchdog

OK that’s a better idea of what you are trying to do.

The code with the timerRepeat etc. does not compile because you have used variables (lightOnAlarm and lightOffAlarm) before they are defined. In the code you posted, you assign them after trying to use them. Even so, every time your code goes throw ONAlarm() with ifOff set to false, it creates two new timers with variables allocated on the stack, so eventually you run out of timers.

The timerRepeat calls set up calls to offLight and onLight every 10 and 20 seconds repeatedly without stopping. I don’t think this is what you want to do here anyway.

For the watchdog, you missed this line in the example:

// EXAMPLE USAGE
// Global variable to hold the watchdog object pointer
ApplicationWatchdog *wd;

How did you compile this code to test it?

Ah ok I see.

So the variables lightOnAlarm and lighOffAlarm are declared with an AlarmID_t object. This was so that I can disable them later when the OffAlarm gets triggered. What would the best way be then to achieve what I want?
And yes that timer solution is awful currently but it was only for testing purposes anyway until I figure out the Alarm issue.

Regarding the watchdog, I have that global variable for the watchdog, just forgot to add it here. I will add the updated code.

And actually @gusgonnet 's solution seems to have kind of worked regarding the trigger of the Alarms. They trigger when they should. The only issue now is that if the device gets restarted after the time an alarm has been triggered, the alarm will not be activated. So if the alarm is set for 09:00 and the next alarm is at 16:00 and during that time the device restarts for some reason, the first alarm will not be activated. Any ideas on how to fix that?

#include "TimeAlarms/TimeAlarms.h"
#undef now()

SYSTEM_THREAD(ENABLED);

const int led2 = D7;
ApplicationWatchdog *wd;

AlarmID_t lightOffAlarm;
AlarmID_t lightOnAlarm;
boolean isOff;

void setup()
{
  #if (PLATFORM_ID==12)  // for Photon Time issue
  while(Time.year() < 2000) Spark.process(); // wait for Time to sync
  #endif
  
  waitFor(Time.isValid, 150000);
  if (Time.isValid()) {
      
  

  //Particle.syncTime();
  Time.zone(+2);
  

  pinMode(led2, OUTPUT);
  Serial.begin();
  
  

  Alarm.alarmRepeat(10, 16, 0,  ONAlarm);
  Alarm.alarmRepeat(10, 20, 0, OFFAlarm);   

  }
  wd = new ApplicationWatchdog(60000, System.reset, 1536);
}

void ONAlarm()
{
    isOff = false;
    
    Particle.publish("Alarm", "ON");
    Serial.println("ON " + Time.timeStr() );
    
    digitalWrite(led2, HIGH);
    
    if(isOff == false)
    {
        Alarm.enable(lightOnAlarm);
        Alarm.enable(lightOffAlarm);
        lightOffAlarm = Alarm.timerRepeat(10, offLight);
        lightOnAlarm = Alarm.timerRepeat(20, onLight);     
       
    }
    
    Serial.println(isOff);
    

}

void OFFAlarm()
{
    isOff = true;
    
    Particle.publish("Alarm", "OFF");
    Serial.println("OFF " + Time.timeStr());
    
    Alarm.disable(lightOnAlarm);
    Alarm.disable(lightOffAlarm);
    
    digitalWrite(led2, LOW);   
}

void loop()
{

  Alarm.delay(1000);

    // RESETS THE AWDT COUNT     
    wd->checkin(); 
}

void offLight()
{
    Serial.println("OFF light TIMER " + Time.timeStr() );
    digitalWrite(led2, LOW);
}

void onLight()
{
    Serial.println("ON light TIMER " + Time.timeStr() );
    digitalWrite(led2, HIGH);
}

So for the reboot problem, I would look at using a retained variable to store if you are in the alarm on section or not. Then is setup() or the first time through loop() you would turn it back on and make sure your program’s state is correct setting isOff as required.

I’m not sure the Alarm.enable() calls are doing what you really want the first time around the cycle. The global variables for lightOff/OnAlarm are initialized to zero, so you are enabling the first defined alarm (which looks like the one that calls ONAlarm in setup). That likely doesn’t hurt anything, but it could.

I think I would create all four alarms in setup() and disable them, then just enable when needed. If you are worried about the alarm going off in setup(), I would add a global variable to protect against that which you can clear at end of setup().

1 Like

Good point, I will try that. I’m assuming that alarm and timer use the same object so I can use AlarmID for both to be able to store them in a variable?

How would you solve the issue of a repeating timer during a scheduled time? So if I want to have the LED to periodically turn on for x seconds and then off (while the OnAlarm is activated).

Yes, the type alarm type in library is an alias for uint8_t and is used for all timers and alarms.

I would setup four global variables

AlarmID_t startTimer;
AlarmID_t endTimer;
AlarmID_t lightOffAlarm;
AlarmID_t lightOnAlarm;
bool firstTime = true;
void setup() {
//...
  startTimer = Alarm.alarmRepeat(...);
  endTimer = Alarm.alarmRepeat(...);
  lightOffAlarm = Alarm.timerRepeat(...);
  Alarm.disable(lightOffAlarm);
  lightOnAlarm = Alarm.timerRepeat(...)
  Alarm.disable(lightOnAlarm);
  firstTime = false;
}

You then use firstTime as a guard for the code that might go off before you are ready.

Then in the functions called by the alarms, you just enable and disable lightOnAlarm and lightOffAlarm.

There are lots of other ways to solve this including doing the 20 sec on 30 sec off in loop() itself while calling Alarm.delay() and using your boolean flag to control if you are in the alarm window or not.

1 Like

Hi again.

Thank you for the solution. It works great. The only issue left is the reboot thing, I can’t seem to figure it out. I don’t really know how to trigger the Alarm manually if the device reboots during the schedule window and still keep the normal scheduled time as well. I tried a thing where I check if the current time is bigger than the Alarm trigger time and trigger the alarm if it is. But that won’t work the way I want it.

Care to elaborate on your idea?

@bko touched on it briefly - by setting a retained variable, as a flag, before you reset. Try changing:

wd = new ApplicationWatchdog(60000, System.reset, 1536);

to

wd = new ApplicationWatchdog(60000, watchdogHandler, 1536);

and add this routine to your code. Modify it to save a retained variable flag:

void watchdogHandler() {
  // Do as little as possible in this function, preferably just
  // calling System.reset().
  // Do not attempt to Particle.publish(), use Cellular.command()
  // or similar functions. You can save data to a retained variable
  // here safely so you know the watchdog triggered when you 
  // restart.
  // In 2.0.0 and later, RESET_NO_WAIT prevents notifying the cloud of a pending reset
  System.reset(RESET_NO_WAIT);
}
2 Likes

I don’t get it. What retained variable flag should be saved in the watchdog?

You want to set the retained variable (let say to true) when you are in the alarm time region and clear it (false) when you stop the alarm time.

Then in setup when you reboot, you do all the same setup and right at the end check the retained variable and if it is set (true) you call the alarm start function ONAlarm.

Oh ofcourse… Worked beautifully. Thank you guys.

One question tho. Why would I need to do this in the watchdogHandler? I feel like it is not triggering always (and maybe because I’m not 100% sure when the watchdog gets triggered. But this is my current solution, please let me know if it’s awful.

SYSTEM_THREAD(ENABLED);

const int led2 = D7;
ApplicationWatchdog *wd;

// TIME SYNC
#define ONE_DAY_MILLIS (24 * 60 * 60 * 1000)
unsigned long lastSync = millis();

AlarmID_t lightOffAlarm;
AlarmID_t lightOnAlarm;
AlarmID_t startTimer;
AlarmID_t endTimer;
bool firstTime = true;
bool inScheduleWindow;
int startHH = 10;
int startMM = 13;
int endHH = 14;
int endMM = 48;

void setup()
{
  #if (PLATFORM_ID==12)  // for Photon Time issue
  while(Time.year() < 2000) Spark.process(); // wait for Time to sync
  #endif

  waitFor(Time.isValid, 150000);
  if (Time.isValid()) {
            
      Time.zone(+2);
      pinMode(led2, OUTPUT);
      Serial.begin();

      lightOnAlarm = Alarm.alarmRepeat(startHH, startMM, 0, ONAlarm);
      lightOffAlarm = Alarm.alarmRepeat(endHH, endMM, 0, OFFAlarm);
      startTimer = Alarm.timerRepeat(10, offLight);
      Alarm.disable(startTimer);
      endTimer = Alarm.timerRepeat(20, onLight);
      Alarm.disable(endTimer);
      firstTime = false; 
      wd = new ApplicationWatchdog(60000, watchdogHandler, 1536);
      
      if (Time.hour() >= startHH && Time.minute() >= startMM && Time.hour() <= endHH && Time.minute() <= endMM) {
          ONAlarm();
      } else {
          OFFAlarm();
      }
  }

}

void ONAlarm()
{
    Particle.publish("Alarm", "ON");
    Serial.println("ON " + Time.timeStr() );
    Alarm.enable(startTimer);
    Alarm.enable(endTimer);
    //digitalWrite(led2, HIGH);
    
}

void OFFAlarm()
{
    Particle.publish("Alarm", "OFF");
    Serial.println("OFF " + Time.timeStr());
    
    Alarm.disable(startTimer);
    Alarm.disable(endTimer);
    
    digitalWrite(led2, LOW);   
}

void loop()
{
    
    if (millis() - lastSync > ONE_DAY_MILLIS) 
    {
        Particle.syncTime();
        lastSync = millis();
    }  

    Alarm.delay(1000);
    
    // RESETS THE AWDT COUNT     
    wd->checkin(); 
}

void offLight()
{
    Serial.println("OFF light TIMER " + Time.timeStr() );
    digitalWrite(led2, LOW);
}

void onLight()
{
    Serial.println("ON light TIMER " + Time.timeStr() );
    digitalWrite(led2, HIGH);
}


void watchdogHandler()
{

    System.reset(RESET_NO_WAIT);
}

(The code below was compiled for Photon but not run. Sorry, I don’t have access to one right now.)
Well, there are other ways. One way would be to create a reset handler. I use this tool found in contributions by others in the forum, docs or libraries for cases when mains/battery/network could be unavailable at any time between graceful System.reset() and successful startup. You could use it to set your retained variable(s) before reset then act on them after reboot. If you anticipate a total loss of power then you could store values in EEPROM.
Also, I use the last statement for gen3. It may be useful for you but I am not sure of that. :wink:

void reset_Handler() {//small amount of time before System.reset begins
  // turn off the crankenspitzen        all digital pins may lose power momentarily anyway so shut it down for real

  digitalWrite(output_Pin, device_State_OFF); // force motors, pumps, heaters, etc. to  OFF
}

void setup() {  
  // register the reset handler
  System.on(reset, reset_Handler);    

  // This allows a graceful shutdown on System.reset()
  Particle.setDisconnectOptions(CloudDisconnectOptions().graceful(true).timeout(5s));
  ...
}
1 Like

The watchdog “goes off” (i.e. calls the handler and then reboots) when your code is screwed up and hangs or the cloud connection hangs you (doesn’t happen much anymore), etc. It is the last chance to set things up for a good restart.

You don’t need the watchdog handler but it makes your system have a robust recovery from unpredictable failures.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.