To be able to schedule an action for given time and also repeat

Hi,

I am trying to set up a scheduler on Photon to, let’s say, turn on a motor everyday for 15 min and then turn it off.

I have looked at TimeAlarms lib. But it makes the pin high for one minute and thats it.

What if I want to let the pin stay high for 60 min?

Can please someone help me?

Thanks in advance.

At a first cut, the following may be of use for what you intend to do:

  1. Time functions (http://docs.particle.io/core/firmware/#libraries-time). These functions provide various aspects of the current time such as day/hour/minute/second etc. Photon gets the current time by syncing up with the cloud. For example, you can use Time.hour() to get hour of the curent hour in 24 hour format. Time.minute() gives the minutes of the current time.

  2. You can use delay of 60000 milliseconds between turning the motor on and off.

  3. After the motor is turned off, you can use delay to sleep for 23 hours or use variants of System.sleep functions. Please see http://docs.particle.io/core/firmware/#system-system-sleep

If the requirement is more clear, a better approach can be provided.

There are some good suggestions of @TheVelozGroup, especially the “sleep” one - unless you want to do other things in the mean time :wink:
But as he said, more info may lead to more helpful feedback.

About the TimeAlarms it mostly comes down to what you do in your alarm handlers.
If you have one ON-Alarm and one OFF-Alarm and control the pin propperly, you should well be able to achieve what you want.

Show us your (boiled down) code, maybe we can spot the issue.

1 Like

Hi @coolio

I wrote some code for an aquarium controller for a user in this thread--you could adapt from there:

3 Likes

First of all, thank you all for your response!

Let me state my requirements:
Eventually, I want to have a phone App which will be making web requests to the functions in photon device and user can choose to do the following:

  1. User from phone app can request to run the motor one time only and at a certain time. e.g. run it today at 5:30 pm for 60 min.
  2. OR user can choose to schedule to run the motor on Monday, Wednesday, Friday at 5:30 am for 60 min.
  3. OR user can choose to run the motor on Weekends only at 5:30pm for 60 min.
  4. If motor is currently running at scheduled time, user should be able to check if motor is running.
  5. User can also choose to turn the motor off in the middle of scheduled time or cancel for today.

Now, I am still playing with the basic functions in Photon. I am currently using D7 LED to test instead of a Motor.

I tried to turn LED ON by putting the code in loop function like this:
void TurnItOn(int hour, int min, int sec, int tillHour, int tillMin){

if(Time.hour() == hour && Time.minute()==min){

 digitalWrite(led2, HIGH);  
}
else if(Time.hour()==tillHour && Time.minute() == tillMin){
     digitalWrite(led2, LOW);  
    
}
else{
    digitalWrite(led, HIGH);
    }

}

But I want to run a function based on user’s input instead of running a particular code in loop function.
From my reading, I have gained the following knowledge:

  1. I have to syc up with cloud time everyday once.
  2. I have to run code in loop for connecting to wifi
  3. I have to save the user options in EEPROM and motor status.

But I am not able to figure out how to schedule for weekdays/weekends and read status.
Any help will be greatly appreciated.

Thanks.

For the weekday/weekend problem you could use ... guess what ... Time.weekday()

Instead of relying on the hour/minute combo, I'd suggest to go for a mathematical approach and check if your time falls into the range between Time.hour()*60 + Time.minute() and Time.hour()*60 + Time.minute() + duration. The advantage is that this won't fail if you should happen to miss this very minute (e.g. blocking program due to loss of connection).
But I'd still give TimeAlarms a go.

If you want to read the status you've got several possibilities - just three of them

  1. Have a status flag to set the state and make it visible as Spark.variable()
  2. Instead of memorizing the state, you could read it from your pin with digitalRead(led2)
  3. If you don't trust 2. you could actually measure the output state of the pin with another INPUT pin.

I don't quite get your point here

2 Likes

Thank you so much for your response!

I tried to give TimeAlarms a try again after reseting the firmware on my Photon and starting on a clean slate…
I used Blink an LED as a starter added the TimeAlarms function to jus see the D7 LED turn on…

Here is my code:

// This #include statement was automatically added by the Spark IDE.
#include "TimeAlarms/TimeAlarms.h"

// This #include statement was automatically added by the Spark IDE.

// ------------
// Blink an LED
// ------------

/*-------------

We've heavily commented this code for you. If you're a pro, feel free to ignore it.

Comments start with two slashes or are blocked off by a slash and a star.
You can read them, but your device can't.
It's like a secret message just for you.

Every program based on Wiring (programming language used by Arduino, and Particle devices) has two essential parts:
setup - runs once at the beginning of your program
loop - runs continuously over and over

You'll see how we use these in a second. 

This program will blink an led on and off every second.
It blinks the D7 LED on your Particle device. If you have an LED wired to D0, it will blink that LED as well.

-------------*/


// First, we're going to make some variables.
// This is our "shorthand" that we'll use throughout the program:

int led1 = D0; // Instead of writing D0 over and over again, we'll write led1
// You'll need to wire an LED to this one to see it blink.

int led2 = D7; // Instead of writing D7 over and over again, we'll write led2
// This one is the little blue LED on your board. On the Photon it is next to D7, and on the Core it is next to the USB jack.

// Having declared these variables, let's move on to the setup function.
// The setup function is a standard part of any microcontroller program.
// It runs only once when the device boots up or is reset.

void setup() {

  // We are going to tell our device that D0 and D7 (which we named led1 and led2 respectively) are going to be output
  // (That means that we will be sending voltage to them, rather than monitoring voltage that comes from them)

  // It's important you do this here, inside the setup() function rather than outside it or in the loop function.

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  
  Time.zone(-4);
  Time.setTime(1413034662);
  Alarm.alarmRepeat(11,35,0, MorningAlarm);
  Alarm.timerRepeat(15, Repeats);

}

// Next we have the loop function, the other essential part of a microcontroller program.
// This routine gets repeated over and over, as quickly as possible and as many times as possible, after the setup function is called.
// Note: Code that blocks for too long (like more than 5 seconds), can make weird things happen (like dropping the network connection).  The built-in delay function shown below safely interleaves required background activity, so arbitrarily long delays can safely be done if you need them.

void loop() {
   
  // To blink the LED, first we'll turn it on...
 // digitalWrite(led1, HIGH);
 // digitalWrite(led2, HIGH);

  // We'll leave it on for 1 second...
  //delay(1000);

  // Then we'll turn it off...
 // digitalWrite(led1, LOW);
 // digitalWrite(led2, LOW);

  // Wait 1 second...
 // delay(1000);

  // And repeat!
}
void MorningAlarm(){
    digitalWrite(led2, HIGH);   
}

void Repeats(){
    digitalWrite(led2, HIGH);
}

But It didn’t do anything…nothing at all…

I don’t know what I am doing wrong in using TimeAlarms on my Photon…

Thanks.

P.S. I have to run code in loop for connecting to wifi : I meant to say that loop function will have a code snippet to check wifi connectivity.

Try this

#include "TimeAlarms/TimeAlarms.h"

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

  int hh = Time.hour();        // to test for next minute
  int mm = Time.minute();

  pinMode(led2, OUTPUT);

  mm++;            // set for next minute
  Alarm.alarmRepeat(hh  , mm, 0,  ONAlarm);
  mm += 5;         // set for five min later
  hh += (mm / 60); // take care of mm/hh overflows
  mm %= 60;
  hh %= 24;
  Alarm.alarmRepeat(hh, mm, 0, OFFAlarm); 
}

void ONAlarm()
{
    digitalWrite(led2, HIGH);   
}

void OFFAlarm()
{
    digitalWrite(led2, LOW);   
}

void loop()
{
  Alarm.delay(1000);
}

But maybe we want to consult @bko to confirm TimerAlarms do work on Photon.

Hi @ScruffR and @coolio

TimeAlarms do work on Photon with two caveats:

  • I believe you need to change the #include in the provided example–this is minor.

  • On Photon the real-time clock is not set from the cloud for several seconds on start up.

The leads to a big jump in time making alarms that you set up before the chip got the correct time go off since the time is now past them and they have not gone off yet. The work-around is to wait in setup() until the Time.now() returns a reasonable value.

I have been waiting 10 seconds before continuing in my code, is there a better way?

@ScruffR and @bko

Thank you…

@ScruffR I used your code and it didn’t turn the LED on…

There is something with the TimeAlarms lib that Alarm.alarmRepeat is not triggering at all…

I debugged it using serial for checking the time…Time is coming along correct and matches my local time…

ScruffR, did this work for you???

@bko,

[quote=“bko, post:9, topic:12546”]
I believe you need to change the #include in the provided example–this is minor.
[/quote] - I didn;t get it…My lib path is correct though.

[quote=“bko, post:9, topic:12546”]
On Photon the real-time clock is not set from the cloud for several seconds on start up.
[/quote] - You are right…it does take some time and it considered in my code.

So, here is my code so far:

  // This #include statement was automatically added by the Spark IDE.

#include "TimeAlarms/TimeAlarms.h"


// ------------
// Blink an LED
// ------------

/*-------------

We've heavily commented this code for you. If you're a pro, feel free to ignore it.

Comments start with two slashes or are blocked off by a slash and a star.
You can read them, but your device can't.
It's like a secret message just for you.

Every program based on Wiring (programming language used by Arduino, and Particle devices) has two essential parts:
setup - runs once at the beginning of your program
loop - runs continuously over and over

You'll see how we use these in a second. 

This program will blink an led on and off every second.
It blinks the D7 LED on your Particle device. If you have an LED wired to D0, it will blink that LED as well.

-------------*/


// First, we're going to make some variables.
// This is our "shorthand" that we'll use throughout the program:

int led1 = D0; // Instead of writing D0 over and over again, we'll write led1
// You'll need to wire an LED to this one to see it blink.

int led2 = D7; // Instead of writing D7 over and over again, we'll write led2
// This one is the little blue LED on your board. On the Photon it is next to D7, and on the Core it is next to the USB jack.

// Having declared these variables, let's move on to the setup function.
// The setup function is a standard part of any microcontroller program.
// It runs only once when the device boots up or is reset.

void setup() {

  // We are going to tell our device that D0 and D7 (which we named led1 and led2 respectively) are going to be output
  // (That means that we will be sending voltage to them, rather than monitoring voltage that comes from them)

  // It's important you do this here, inside the setup() function rather than outside it or in the loop function.
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  
  Time.zone(-4);
  Time.setTime(1434669071);
  Serial.println(Time.timeStr());
  delay(10000);
   Serial.println(Time.timeStr());
   Serial.println("after the second print");
  Alarm.alarmRepeat(19,40,0, Alarmit);

 Serial.println(Time.timeStr());

}

// Next we have the loop function, the other essential part of a microcontroller program.
// This routine gets repeated over and over, as quickly as possible and as many times as possible, after the setup function is called.
// Note: Code that blocks for too long (like more than 5 seconds), can make weird things happen (like dropping the network connection).  The built-in delay function shown below safely interleaves required background activity, so arbitrarily long delays can safely be done if you need them.

void loop() {
   // Serial.println(Time.timeStr());

   
  // To blink the LED, first we'll turn it on...
 // digitalWrite(led1, HIGH);
 // digitalWrite(led2, HIGH);

  // We'll leave it on for 1 second...
  //delay(1000);

  // Then we'll turn it off...
 // digitalWrite(led1, LOW);
 // digitalWrite(led2, LOW);

  // Wait 1 second...
 // delay(1000);

  // And repeat!
}
void Alarmit(){
    digitalWrite(led2, HIGH);  
   Serial.println("Alarm");   
}

void Repeats(){
    Serial.println("hello");
    digitalWrite(led2, HIGH);
}

Random thought: could you try putting Alarm.delay(1000); in your loop and see if that makes a difference?

3 Likes

Jordy @Moors7 is exactly right above. The way time alarms works is that you must call the special delay method in order for the alarms to be triggered.

3 Likes

@coolio, I have edited my code above to care for the delayed time sync and also added the loop() - that was missing before - with the crucial Alarm.delay() line in it.

1 Like

Hi @tjp

The initial value seems to be negative so I have been doing this in setup():

    while( Time.now() < 10000) {
        Spark.process();
    }

I am hoping this can be improved eventually.

1 Like

That’s awesome! Thanks!

Thank you so much @ScruffR @bko and @Moors7, It worked!

Finally, I am good to go onto my next adventure.

You guys are amazing!

3 Likes

I tried it , too and looks like Photon doesn’t like Time.now()…It fails at compilation.

Hi @coolio

I think this may be a library problem from my port of TimeAlarms since I ran into this the other night too.

Try adding this after all include statements:

#include <whatever here>
#undef now()

1 Like

@bko: Yup, That did it…
Its working fine now…

Thank you.

1 Like