How to do calculations involving time. As in time(now) + 5 minutes

Just getting started with Arduino so please don't overwhelm me.

I'm realizing with delay the loop stops. Is there a way of doing math calculations involving time?

My application is I'm trying to write home automation code som when a button is pressed a light is tuned on and will turn off 5 minutes from when in was pressed. I could use delay, but that halts the loop and other buttons which control other lights won't respond.

I guess I could write code to use (mins) + 5 but realize the code would become complicated if the button was pressed 55 past the hour. Now I would have to do special cases because the mins would wrap around to 0.

I'm hoping there is a time command or would it bea function to convert current time (Year, month, day, hour, min) to an interger. That way I would just do simple math on time. Something like

turnOff = currentTime + 5
If turnOff => currentTime //turn off the light relay

Or is there a better way of doing this?

Thanks

You should Read this article about doing multiple things at the same time

http://forum.arduino.cc/index.php?topic=223286.0

I had this same worry too! Don't fear, there's a special time library that will help you out!

Download
I'm assuming you know how to install libraries!

Then, as you say, using this library, your code will be:

#include "Time.h"

//Check if the light needs to turn on
if (LightTrigger == true) {
  //Turn on the light

  //Set timeout
  TurnOff = now()+5; //5 seconds from now (Use long, not int for this value)
}

//Check if the light needs to turn off
if (now() > TurnOff) {
  //Turn off the light
}

So, now() returns the current time in seconds (make sure you use long, not int for this value).

However it overspills after like 20 days or something, so if you don't actually need the time for this project, you just need it for measurement, add: if (day() > 20) { setTime(0);}
Otherwise, at say 20 days and 1 second, the value returned is back to 0 again.
If you triggered the light on the 19th day, the time stored will be a huge number, and 0 will be smaller than it (so the light won't turn on anymore).

Sorry about that, some poor research on my part now() actually returns a time_t value - a signed 32 bit value (which overflows at 2147483647). That's 68 years before it overflows. It's pretty much guaranteed you'll have a power cycle in that time. All my sources are included where relevant. No more mistakes!

Here's some further documentation too:
Github page (Official documentation)
Arduino writeup (This is more user friendly)

Thank you. I reviewed the post but I guess I'm not understanding. It appear the a author is using the millisecond command. It's my understanding the milliseconds count up from power on and will wrap every 60-70 days so I'm left with the same problem as when the minutes wrap at :59 back to :00.

Is there no way to conver the current time to an interger to do simple math calculations?

You posted a split second after I did, so you may not have seen my reply :3

Doug101:
Just getting started with Arduino so please don't overwhelm me.

I'm realizing with delay the loop stops. Is there a way of doing math calculations involving time?

My application is I'm trying to write home automation code som when a button is pressed a light is tuned on and will turn off 5 minutes from when in was pressed. I could use delay, but that halts the loop and other buttons which control other lights won't respond.

Have you looked at Blink Without Delay?

Even with a longer time interval, the principle is the same. Five minutes is 300000 (three hundred thousand) milliseconds.

Doug101:
It's my understanding the milliseconds count up from power on and will wrap every 60-70 days so I'm left with the same problem as when the minutes wrap at :59 back to :00.

It is only a problem if you want to measure an interval greater than 49 days. For 5 minutes or 5 days it works fine if you use 'unsigned long' values and subtract to measure intervals:

unsigned long StartTime = millis();
const unsigned long Interval = 5UL*60UL*1000UL;  // 5 minutes in milliseconds
//const unsigned long Interval = 5UL*24UL*60UL*60UL*1000UL;  // 5 days in milliseconds
void loop() {
    unsigned long currentTime = millis();
    if (currentTime - StartTime >= Interval) {  // Using '>=' here avoids the problem of missing the exact millisecond
        // Do the stuff that happens every Interval
        StartTime += Interval;  // Adding here avoids loosing milliseconds if the loop is slow
    }
}

Kounipo:
So, now() returns the current time in seconds (make sure you use long, not int for this value). However it overspills after like 20 days or something, so if you don't actually need the time for this project, you just need it for measurement, add:

if (day() > 20) {

setTime(0);
}

now() returns an unsigned long which will roll over in about 136 YEARS.
The 'day()' function returns the current day of the month so of course it rolls over to 1 on the first of the month.

I think I understand libraries, if not should be able to figure it out.

I read through that time library. If I use the now() and it's getting close to the 20 day spillage (I thought it was 60 or 70 days) then don't I have to do the same test to see if the turn off time will fall in the exception time?

Or maybe I thinking about this like a human and not like a machine? If now() is say one second away form wrapping will the calculation of now() + 5 seconds be the same value as now() in 5 seconds? A human would think not, but maybe a machine would?

If I install a real time clock module or sync with a NTP server would that chage things?

Seems to me if Arduino uses time from 1970 it would be an interger and we could do simple math calculations using it.

johnwasser:
now() returns an unsigned long which will roll over in about 136 YEARS.

Sadly, the UNIX designers chose a signed long, which has only half the range.

Hope they don't screw up my pension calculations. :frowning:

AWOL:
Sadly, the UNIX designers chose a signed long, which has only half the range.

Hope they don't screw up my pension calculations. :frowning:

That is so weird! I read somewhere that it only lasted 20-30 days. Maybe it was for a different library, maybe it said 49 days. I guess I shouldn't trust everything I read online. I'll cross out the dodgy info in my post :o

Does that mean it wraps to -2147483648 instead of 0 then? Not that it would ever get to that value but yeah...

Kounipo:
That is so weird! I read somewhere that it only lasted 20-30 days. Maybe it was for a different library, maybe it said 49 days. I guess I shouldn't trust everything I read online. I'll cross out the dodgy info in my post :o

Does that mean it wraps to -2147483648 instead of 0 then? Not that it would ever get to that value but yeah...

I think you may be confusing the UNIX "time_t" which represents a number of seconds, and the value returned by Arduino's "millis() function which will wrap after 49 days after the particular Arduino's reset, and represents an arbitrary number of milliseconds.

Doug101:
If it's getting close to the 20 day spillage then don't I have to do the same test to see if the turn off time will fall in the exception time?

Alright so according to this article, the spill would wrap around. If this is the case, then yes, there'd be a problem.

For simplicity, let's say the spillage happens upon 60 seconds, and the current second is 58. If you stored now()+5, you'd get 63, which would loop around to 3.

The next check would be:

if (58 > 3)

which would return true, even though there's still 5 more seconds until the real trigger.

The solution to this problem would be to make sure your maximum time addition (in this case, 5 seconds) is subtracted from the real overspill number.

So if the time is larger than 55 seconds (and the light isn't currently on), reset it to 0 again. That way if the button is pressed on 54, it will continue to 59 without fear of a spill. Next iteration, the time will be reset to 0 again, and the problem is avoided.

Also it would have to be 54 seconds not 55, because it would go from 59 straight to 0.

But you don't need to worry about that, I made a mistake! See my amended post!

Doug101:
If I install a real time clock module or sync with a NTP server would that chage things?

It wouldn't change the spill issue (that you don't need to worry about), in fact it would make it worse.

When you power up your arduino, the date starts at 1970, so you've got until 2038 before the wrap. If you sync it to a time holder, it will fast forward the date to the current year, meaning you've got far less time before that date.

AWOL:
I think you may be confusing the UNIX "time_t" which represents a number of seconds, and the value returned by Arduino's "millis() function which will wrap after 49 days after the particular Arduino's reset, and represents an arbitrary number of milliseconds.

Yes I believe I was. I'm no longer confused now, and I've corrected my initial post so any other readers coming through here won't be confused either ^^

Would someone here please explain to the OP how the subtraction trick in Blink Without Delay works?

odometer:
Would someone here please explain to the OP how the subtraction trick in Blink Without Delay works?

It uses exactly the same premise as what's posted here already :3

May be out of line, but if you are only concerned for having your routine run for a set amount of time, does it matter what day, hour, year it is? Unless you are wanting to prevent certain things from executing if its daytime outside..then i understand the need for the time and calculation.

if all you care about is running the lights for 5 minutes then i would think keep it simple and use the millis().

I use that for instances where i dont care what time of day it is.. but for one of my projects i need the time so that i could control my relays after hours..

cubangt:
does it matter what day, hour, year it is? if all you care about is running the lights for 5 minutes then i would think keep it simple and use the millis().

now() is exactly the same as millis(), except it uses a much more manageable scale of numbers. It also overflows after 68 years, which is better than 49 days.

The only downside to using time.h, is that it's an additional library, which means it's using extra storage. But if you can spare it, I think the convenience is worth it.

Hate to be the person who asks the question and be the one who doesn't get the answers, but I am. (Remember I'm still new to a lot of this so I'm still on the steep part of the learning curve.)

Am I correct in assuming if I use a RTC or NTP server for time there is no way to do simple time math calculations?

Like turnoffTime = timeNow + 5 minutes or turnoffTime = timeNow + 5 hours

I could live with a hiccup/bug that happens every 68 years, but not one that happens on 5 minutes every hour or every 20 or 60 days.

Really am appreciating all of the help - I am learning from your posts. +1

Doug101:
Hate to be the person who asks the question and be the one who doesn't get the answers

That's these forums are for!

Doug101:
Am I correct in assuming if I use a RTC or NTP server for time there is no way to do simple time math calculations?

No, you're not correct. Whether you connect to a server, use a timekeeper device or just leave the date at 1970, it makes no difference to the calculations you can perform.

Doug101:
turnoffTime = timeNow + 5 minutes or turnoffTime = timeNow + 5 hours

You can do this regardless of what time system you use.

The bottom line is:

If you use the built in millis() function, there's a small chance your light will turn off too early once every 49 days.
If you use time.h's now() function, there's a minuscule chance your grandchildren will see a light turn off too early once in their lifetime.

If you reset the time before either spill, there won't be any early darknesses at all.

Doug101:
Am I correct in assuming if I use a RTC or NTP server for time there is no way to do simple time math calculations?

No, that would not be correct.

Doug101:
Like turnoffTime = timeNow + 5 minutes or turnoffTime = timeNow + 5 hours

If

turnoffTime = timeNow  + 5 * minutes;

and

turnoffTime = timeNow  + 5 * hours;

are close enough then you can make your calculations look like that:

#include "TimeLib.h"
const unsigned long seconds = 1;
const unsigned long minutes = 60 * seconds;
const unsigned long hours = minutes * 60;
const unsigned long days = hours * 24;
const unsigned long weeks = days * 7;

unsigned long timeNow, turnoffTime;

timeNow = now();
turnoffTime = timeNow + 5 * minutes;
turnoffTime = timeNow + 5 * hours;
turnoffTime = timeNow + 23 * hours + 56 * minutes + 4 * seconds;