2

I have an Arduino Uno with a motor shield, as well as a DS1307 RTC that I am using to control 2 pumps.

Ideally I would like to set a start time (startHour + startMinute) and end time (endHour + endMinute) for each pump.

I have had luck using if statements to control my timer like below (adapted from Iain Foulds):

byte startHour=8
byte startMinute=15
byte endHour= 14
byte endMinute= 20

byte startHour2=22
byte startMinute2=30
byte endHour2= 2
byte endMinute2= 45

void loop() {
  byte checkStartTime1() {
    DateTime now = RTC.now();
    // Read in what our current datestamp is from RTC
    if (now.hour() == startHour && now.minute() == startMinute) {
      validStart1 = 1;
    } else {
      validStart1 = 0;
    }
    return validStart1;
    // Return the status for powering up
  } 
}

But my concern is that this only checks for equivalency at the moment, and if I lost power when my start time came up my pump would not come on. So I was hoping to set up an if statement that can deal with ">=" as opposed to just "==".

Which I can use if I only deal with the hour section:

if (now.hour() >= startHour && <= endHour)

But things get complicated when I try to add in minutes to the control structure. I end up with a series of nested for loops that do not work.

I'm hoping someone can help me write an if statement (or switch case) that can accommodate hours and minutes. So that any time between 8:15-14:20

validStart1=1

and anytime other time

validStart1=0

And please note the addition of the second set for this timer (StartHour2)- which I threw as my second pump will need to deal with the switch over past midnight.

  • May I know how to change this code working for midnight time range? As an example, 23.30 to 01.30. byte startHour=8 byte startMinute=15 byte endHour= 14 byte endMinute= 20 void loop() { DateTime now = RTC.now(); // Read in what our current datestamp is from RTC if ( ( (now.hour()==startHour && now.minute()>= startMinute) || (now.hour()>startHour) && ( (now.hour()==endHour && now.minute()< endMinute) || (now.hour()<endHour) ) { validStart1 = 1; } else { validStart1 = 0; // } – SMD Aug 20 '18 at 18:01
3

I had a similar problem when i tried to control some heating source here at home.This was how I made my steps to get it working. First I will assume you are using the library time.h and DS1307RTC.h (check here for info: https://www.pjrc.com/teensy/td_libs_Time.html).

Assuming that you will need 3 variables of the type tmElements_t. tm will store your current time( the one you get from DS1307). The other two are auxiliary for defining time you start and time you stop the pump. In similar way, you will need 3 variables of type time_t for the same reasons. time_t variables store a the timestamps since 01/01/1970 (Unix epoch) which are easier to work with but tmElements structures are more human friendly.

tmElements_t tm, tm_hour_start, tm_hour_end;
time_t now, t_hour_start, t_hour_end;

Now in your loop you need to get the current time from rtc:

time_t now = RTC.get();

after, use the breaktime funtion to convert the timestamp value to tmElements struture:

breakTime(now, tm);

Next step is to copy contents of tm to the other auxiliary structures, use the memcpy function:

memcpy(&tm_hour_start, &tm, sizeof(tm));
memcpy(&tm_hour_end, &tm, sizeof(tm));

after, change the the auxiliaries vars to meet your correct schedule of start and stop (are seconds important? if so, do similar way):

tm_hour_start.Hour = startHour;
tm_hour_start.Minute = startMinute;
tm_hour_start.Second = 0;
tm_hour_end.Hour = endHour;
tm_hour_end.Minute = endMinute;
tm_hour_end.Second = 0;

Ok, we have the more human friendly start and end structures, lets get the timestamps from them. To do soo we use the makeTime function that converts tmElements_t structures to time_t:

t_hour_start = makeTime(tm_hour_start);
t_hour_end = makeTime(tm_hour_end);

All you need to do now, is check if your current timestamp (now) is between this newly created timestamps:

if ((t_hour_start <= now) && (now <= t_hour_end)){
   //do something is soo...
}else{
   // do something if not...
}

Extra tip: In case your stop hour goes past midnight, add one more day to the timestamp:

if (startHour > endHour) //past midnight correction
   t_hour_end = t_hour_end + SECS_PER_DAY;

clean code:

#include <time.h>
#include <DS1307RTC.h>
#include <stdio.h>
// other includes etc...

byte startHour=8
byte startMinute=15
byte endHour= 14
byte endMinute= 20

tmElements_t tm, tm_hour_start, tm_hour_end;
time_t now, t_hour_start, t_hour_end;

// setup function and other needed things...    

void loop(){
  //get current timestamp
  time_t now = RTC.get();
  // make current date and time structure
  breakTime(now, tm);
  // make auxiliary structures to be more human editable and friendly
  memcpy(&tm_hour_start, &tm, sizeof(tm));
  memcpy(&tm_hour_end, &tm, sizeof(tm));
  // change auxiliary structures to meet your start and end schedule 
  tm_hour_start.Hour = startHour;
  tm_hour_start.Minute = startMinute;
  tm_hour_start.Second = 0;
  tm_hour_end.Hour = endHour;
  tm_hour_end.Minute = endMinute;
  tm_hour_end.Second = 0;
  // reverse process to get timestamps
  t_hour_start = makeTime(tm_hour_start);
  t_hour_end = makeTime(tm_hour_end);
  // check if end time is past midnight and correct if needed
  if (startHour > endHour) //past midnight correction
       t_hour_end = t_hour_end + SECS_PER_DAY;

  //final part   
  if ((t_hour_start <= now) && (now <= t_hour_end)){
          //do something is soo...
  }else{
          // do something if not...
  }

}

EDIT: to correct the thing about midnight checks spotted in comments. New code:

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <stdio.h>
// other includes etc...

byte startHour = 8;
byte startMinute = 15;
byte endHour = 14;
byte endMinute = 20;

tmElements_t tm, tm_hour_start, tm_hour_end;
time_t now_, t_hour_start, t_hour_end;
boolean update_tm = 1;



// setup function and other needed things...    
void setup(){};

void loop(){
  //get current timestamp
  time_t now_ = RTC.get();
  // make current date and time structure
  breakTime(now_, tm);
  // make auxiliary structures to be more human editable and friendly
  if(update_tm){
    memcpy(&tm_hour_start, &tm, sizeof(tm));
    memcpy(&tm_hour_end, &tm, sizeof(tm));
    // change auxiliary structures to meet your start and end schedule 
    tm_hour_start.Hour = startHour;
    tm_hour_start.Minute = startMinute;
    tm_hour_start.Second = 0;
    tm_hour_end.Hour = endHour;
    tm_hour_end.Minute = endMinute;
    tm_hour_end.Second = 0;
    // reverse process to get timestamps
    t_hour_start = makeTime(tm_hour_start);
    t_hour_end = makeTime(tm_hour_end);

    // check if end time is past midnight and correct if needed
    if (startHour > endHour) //past midnight correction
      t_hour_end = t_hour_end + SECS_PER_DAY;
  }
  //final part   
  if ((t_hour_start <= now_) && (now_ <= t_hour_end)){
    /* if we got a valid schedule, don't change the tm_hour structures and the 
    respective t_hour_start and t_hour_end timestamps. They should be updated 
    after exiting the valid schedule */
    if(update_tm)  
      update_tm = 0;

    //do something is soo...
  }else{
    if(update_tm == 0)  
      update_tm = 1;
    // do something if not...
  }

}
  • Thanks so much for such a well thought out, well explained, and well complemented code. But I do seem to be having an issue with the midnight correction. When I use the above code, when the clock strikes midnight my pumps stop. There seems to be some funky math going on when at midnight, so I even tried (SECS_PER_DAY*2) to make sure I'm well into the next day. But my pump is still shutting down at midnight. But other than this issue, the code works well – Vinterwoo Nov 6 '15 at 1:55
  • try to replace SEC_PER_DAY with the real number (24hours * 3600 sec per hour = 86400) to see if there is no buggy problem with that macro or something. The macro itself is defined in time.h (github.com/PaulStoffregen/Time/blob/master/Time.h). Have you printed time_t variables t_hour_start, t_hour_end and now? Are they correct? – brtiberio Nov 8 '15 at 12:13
  • @Vinterwoo ignore my last comment, I think I figured it out, however I can not test it at the moment. I think the problem is we are constantly refreshing the 'tmElements_t' structures of 'tm_hour_start' and in 'tm_hour_end'. Once we past over midnight, this structures also will change and cause the failure (because the 'tm_hour_start.day' will reflect the change over new day). Once we get a valid start, we must fix this structures until turn off hour is passed. Check the edit – brtiberio Nov 8 '15 at 15:02
2

What you need to do is convert the time into some standard single number and then compare those numbers.

A popular method is to calculate the number of seconds since an epoch. An epoch is an arbitrary point in time that you measure time since. Microsoft chose 01/01/0000 for their epoch - Unix chose 01/01/1970.

The Time.h library contains functions for manipulating time values - one of the functions in it can convert a full date and time specification into the number of seconds since 01/01/1970 (Unix epoch). If you want ideas then look at the source code for that.

A similar approach can be used to just work on the hours and minutes within a day. One hour is 60 minutes, so you can create a number that is the number of hours multiplied by 60 plus the number of minutes in the current hour. That will give you the number of minutes since midnight. You can even add in the seconds if you want even more accuracy.

Once you have that single value it's very easy to compare it with a >=.

2

Gerben, thanks for your code. I took it and added seconds to the check, and tidied up a few typos. This isn't as sophisticated as other methods, but might be good for beginners to follow logic. hope it helps

#include <TimeLib.h>
#include <Wire.h>
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

int openHH = 9;
int openMM = 10;
int openSS = 0;
int closeHH = 9;
int closeMM = 40;
int closeSS = 0;

bool isOpenTime()
{  
  time_t t = now(); // Read in what our current datestamp is from RTC
//  DateTime now = RTC.now();  // if using timeRTC lib, i think

  int nowHH = hour(t); int nowMM = minute(t); int nowSS = second(t);  // put into local variables for easier read

  if (( 
        (nowHH>openHH)                        // check hours first
        || ((nowHH==openHH) && (nowMM>openMM))             // check minutes if in same hour
        || ((nowHH==openHH) && (nowMM==openMM) && (nowSS>=openSS))    // check seconds if in same hour & minute
      ) 
      &&                                  // both conditions must be valid
      (
        (nowHH<closeHH)                       // check hours first
        || ((nowHH==closeHH) && (nowMM<closeMM)))             // check minutes if in same hour
        || ((nowHH==closeHH) && (nowMM==closeMM) && (nowSS<=closeSS)) // check seconds if in same hour & minute
      ) 
  { return true; } else { return false; }
}

  // usage 
  if (isOpenTime) {
    // ... do something, eg open door
  } else {
    // ... do something, eg close door
  }
1
byte startHour=8
byte startMinute=15
byte endHour= 14
byte endMinute= 20

byte startHour2=22
byte startMinute2=30
byte endHour2= 2
byte endMinute2= 45

void loop()
{
  DateTime now = RTC.now();  // Read in what our current datestamp is from RTC

  if (
    ( (now.hour()==startHour && now.minute()>= startMinute) || (now.hour()>startHour)
    && ( (now.hour()==endHour && now.minute()< endMinute) || (now.hour()<endHour) ) {
    validStart1 = 1;  

  } else {
    validStart1 = 0;  // 
  }

return validStart1; // Return the status for powering up
 } 
}
0

Use the time in number of seconds total.

ontime=((sethour*60)+(setmin*60)+setsec);
offtime=((ofsethour*60)+(ofsetmin*60)+ofsetsec);
currenttime=((t.hour*60)+(t.min*60)+(t.sec);
if ((currenttime>ontime)&&(currenttime<offtime));
  {
  pumpon();
  }
else
  {
  pumpoff();
  }
delay(1000);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.