How to calculate time interval?

Hello,

I am using a DS1302 RTC module and Arduino UNO R3 with Arduino IDE 1.8.10 to set a timer to turn on and off a relay, and if there is a power cut, then when the power comes back again, as long as the operation time interval is valid, the relay should turn on.

I came up with a possible solution which involves calculating the time difference and if it is positive, then set a Boolean variable state to HIGH otherwise set to LOW to flag the operation time as valid or not. I’m not sure if that’s the best approach. But i am having trouble to calculate the time difference between the on and off times expressed in hours and minutes.

I did research and i found that a possible solution could be to use the Arduino Time library, which i never used before and it seems quite complicated: 59 - The new Arduino Time library | Prometec

For example, this would be quite easy to calculate by subtracting the hours and minutes:

// Set hour and minutes for ON and OFF
int pumpRelay_OnHour = 15;
int pumpRelay_OnMin = 26;
int pumpRelay_OffHour = 15;
int pumpRelay_OffMin = 36;

But this example would be tricky to solve:

// Set hour and minutes for ON and OFF
int pumpRelay_OnHour = 15;
int pumpRelay_OnMin = 26;
int pumpRelay_OffHour = 15;
int pumpRelay_OffMin = 12;

And this one even trickier (the relay operation time would cross over to the next day):

// Set hour and minutes for ON and OFF
int pumpRelay_OnHour = 23;
int pumpRelay_OnMin = 49;
int pumpRelay_OffHour = 1;
int pumpRelay_OffMin = 10;

Any advice or suggestion would be very appreciated.

Here is my complete sketch:

#include <virtuabotixRTC.h> // DS1302 RTC module library

// Creation of the Real Time Clock Object
virtuabotixRTC myRTC(5, 6, 7);  // Wiring of the DS1302 RTC (CLK,DAT,RST)

const int pumpRelay = 8;  // set pump relay pin
unsigned long interval = 2000;  // print RTC time every 2s
unsigned long time_now = 0;

// Set hour and minutes for ON and OFF
int pumpRelay_OnHour = 15;
int pumpRelay_OnMin = 9;
int pumpRelay_OffHour = 15;
int pumpRelay_OffMin = 10;

bool pumpRelay_status = 0;

void setup() {
  Serial.begin(9600); // open serial port and set the baud rate
  Serial.println("Automated pump relay control with RTC");
  Serial.println("**************************************");
  pinMode(pumpRelay, OUTPUT); // set digital pin pumpRelay as an output
  
  // Set the current date, and time in the following format:
  // seconds, minutes, hours, day of the week, day of the month, month, year
  myRTC.setDS1302Time(50, 8, 15, 5, 26, 1, 2020); // uncomment line, upload to reset RTC and then comment, upload.
  
  myRTC.updateTime(); // update of variables for time or accessing the individual elements.
  
  // Start printing elements as individuals                          
  Serial.print("Preset RTC Time and Date: ");   
  Serial.print(myRTC.hours);                          
  Serial.print(":");                                                                                      
  Serial.print(myRTC.minutes);                                                                            
  Serial.print(":");                                                                                      
  Serial.print(myRTC.seconds);
  Serial.print(" ");
  Serial.print(myRTC.dayofmonth);                                                                         
  Serial.print("/");                                                                                      
  Serial.print(myRTC.month);                                                                              
  Serial.print("/");                                                                                      
  Serial.println(myRTC.year);
  
  Serial.println("********************************************************");
  Serial.println("User Configuration:");
  Serial.println("--------------------------------------------------------");
  Serial.println("RTC-based Timers (Hours:Minutes)");
  Serial.print("Pump ON: ");
  Serial.print(pumpRelay_OnHour);
  Serial.print(":");
  Serial.println(pumpRelay_OnMin);
  Serial.print("Pump OFF: ");
  Serial.print(pumpRelay_OffHour);
  Serial.print(":");
  Serial.println(pumpRelay_OffMin);
  Serial.println("********************************************************");
}

void loop() {
  myRTC.updateTime(); // update of variables for time or accessing the individual elements.
  
  // Start printing RTC time elements as individuals                                                                   
  if (millis() - time_now >= interval)  // non-blocking. prints RTC time every 2 seconds.
  {
    time_now = millis();
    Serial.print("RTC Time: ");                                               
    Serial.print(myRTC.hours);                                                                              
    Serial.print(":");                                                                                      
    Serial.print(myRTC.minutes);                                                                            
    Serial.print(":");                                                                                      
    Serial.println(myRTC.seconds);
  }
  if ((myRTC.hours >= pumpRelay_OnHour && myRTC.hours <= pumpRelay_OffHour) && (myRTC.minutes >= pumpRelay_OnMin && myRTC.minutes < pumpRelay_OffMin))
  {
    if (pumpRelay_status == 0)
    {
    Serial.print("Pump activated at: ");
    Serial.print(myRTC.hours);  // display the current hour from RTC module   
    Serial.print(":");                                                                                      
    Serial.print(myRTC.minutes);  // display the current minutes from RTC module                         
    Serial.print(":");           
    Serial.println(myRTC.seconds);  // display the seconds from RTC module  
    digitalWrite(pumpRelay, HIGH);  //turns on the pump relay
    Serial.println("*** Pump relay turned ON ***");
    pumpRelay_status = 1;
    }
  }
  else
  {
    if (pumpRelay_status == 1)
    {
    Serial.print("Pump deactivated at: ");
    Serial.print(myRTC.hours);  // display the current hour from RTC module   
    Serial.print(":");                                                                                      
    Serial.print(myRTC.minutes);  // display the current minutes from RTC module                         
    Serial.print(":");           
    Serial.println(myRTC.seconds);  // display the seconds from RTC module  
    digitalWrite(pumpRelay, LOW); // turn off the pump relay
    Serial.println("*** Pump relay turned OFF ***");
    pumpRelay_status = 0;
  }
 }
}

You can get something called “ unix time “ from the DS321” and using that to calculate your time difference might be a simple route .

Google” ds3231unix time”

I'd first convert everything to a minutes time base so as not to have to deal with hours and minutes.

onMin = pumpRelay_OnHour*60 + pumpRelay_OnMin ;
offMin = pumpRelay_OffHour*60 + pumpRelay_OffMin ;

We want the pump to turn on after the on time and remain on until after the off time which would be something like:

on = (time > onMin) != (time > offMin) ;

This fails when the off time is earlier than the on time since we've rolled over to the next day. To deal with that we can change the equation above to invert the Boolean value "after the off time" if the off time is earlier than the on time, so:

on = (time > onMin) != ((time > offMin) != (onMin > offMin)) ;

Note that "!=" in the above is operating on Boolean values so it is effectively a logical "xor" operator.

  bool relayOn = false;
  if (onMinute <= offMinute)  // On before Off
    relayOn = currentMinute >= onMinute && currentMinute < offMinute;
  else // Crosses midnight, off the next day
    relayOn = currentMinute < offMinute || currentMinute >= onMinute;
  digitalWrite(RelayPin, relayOn);