Using RTC to trigger relays at certain times of day

Hi,

I'm trying to build an automated greenhouse with the help of an RTC to trigger actions at certain times. I'm using a DS3231 with the DS1307 library and relays so thats why the HIGHs and LOWs are inverted.

What I want the program to do :

1 . Make a LightPin LOW if time is between a certain interval, regardless if the unit should be reset or lose power. What happens now with LightPin is that it turns on at the right time, but if the unit loses power the pin will not go LOW until the RTC is at the starting time again.

  1. Make AirPin LOW for 15 minutes every other hour and HumPin LOW for 15 minutes every hour.

For goal 1 I've tried using while instead of if, but to no success.

And for goal 2 I realise that it could be done with a lot of "if" statements for the specific times but there has got to be a better way to do this. I've thought about using an integer with the value of the current HOUR/2 to see if the value is even in order to only trigger every other hour, and if it is even then digitalWrite LOW.

USING WHILE FOR GOAL 1

   while (now.hour() >= 8 & now.hour() <= 18 & now.minute() == 00 & now.second() == 00)
    {
      digitalWrite(LightPin, LOW);
    }

COMPLETE SKETCH

#include <Wire.h>
#include "RTClib.h"
#include <DHT.h>;
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

RTC_DS1307 rtc;

int LightPin = 5;
int AirPin = 6;
int HumPin = 7;

#define DHTPIN 2     
#define DHTTYPE DHT22   
DHT dht(DHTPIN, DHTTYPE); 


float hum;  
float temp; 


void setup() {

  Serial.begin(9600);
  
  lcd.begin();
  Wire.begin();
  dht.begin();
  rtc.begin();
  lcd.backlight();

  if (! rtc.isrunning())
  {
    lcd.println("RTC is NOT running!");
  }
  
   pinMode (AirPin, OUTPUT);
    pinMode (LightPin, OUTPUT);
    pinMode (HumPin, OUTPUT);
}

void loop() {

  hum = dht.readHumidity();
    temp = dht.readTemperature();

    
  DateTime now = rtc.now();

 lcd.setCursor(0, 0);
    lcd.print("Humi: ");
    lcd.print(hum);
    lcd.print(" %");
    lcd.setCursor(0,1);
    lcd.print("Temp: ");
    lcd.print(temp);
    lcd.print(" C ");


    if (now.hour() == 8 & now.minute() == 00 & now.second() == 00) 
    {
      digitalWrite(LightPin, LOW);
    }

    else if (now.hour() == 20 & now.minute() == 00 & now.second() == 00)
    {
      digitalWrite(LightPin, HIGH);
    }    

       if (now.minute() == 15 & now.second() == 0) 
    {
      digitalWrite(HumPin, LOW);
    }

     else if (now.minute() == 30 & now.second() == 0) 
    {
      digitalWrite(HumPin, HIGH);
    }
       if (now.minute() == 45 & now.second() == 0)
    {
      digitalWrite(AirPin, LOW);
    }

     else if (now.minute() == 00 & now.second() == 0)
    {
      digitalWrite(AirPin, HIGH);
    }    }

Is there anyone here who could point me in the right direction?

I'm still an arduino beginner, so any help and criticism is welcome.

Thanks in advance

If I understand correctly as your logic is inverted so you want a Pin to stay HIGH if you loose power? When you have no power you can't really maintain 5V...

BTW you should Use && instead of & in

while (now.hour() == 8 & now.minute() == 00 & now.second() == 00)
    {

What you have works in your case but not a good practice to confuse the 2

For an interval you'll need a way of comparing hours/mins/seconds values against each other,
ie write a function that looks like:

boolean less_than (int h1, int m1, int s1, int h2, int m2, int s2)
{
  ...
}

Then you can code like

  if (less_than (10, 30, 0, hours, mins, seconds) && less_than (hours, mins, seconds, 11, 45, 0))
    digitalWrite (pin, HIGH) ;
  else
    digitalWrite (pin, LOW) ;

For a hourly repeating interval its easier, you can ignore the hours (pass zero everywhere for hours):

  if (less_than (0, 30, 0, 0, mins, seconds) && less_than (0, mins, seconds, 0, 45, 0))
    digitalWrite (pin, HIGH) ;
  else
    digitalWrite (pin, LOW) ;

or even simpler:

  digitalWrite (pin, mins >= 30 && mins <= 45) ;

For every other hour, just add something like && (hour & 1) == 0

J-M-L:
If I understand correctly as your logic is inverted so you want a Pin to stay HIGH if you loose power? When you have no power you can't really maintain 5V...

BTW you should Use && instead of & in

while (now.hour() == 8 & now.minute() == 00 & now.second() == 00)

{




What you have works in your case but not a good practice to confuse the 2

Hi, thanks for the reply.

It doesn't have to stay high, it just has to write LOW when the arduino is back on. It doesn't do so in this case because the statement doesn't seem to trigger the pin when it has passed the starting hour...

Thanks for the tip!

If your arduino reboots it will execute setup() again once - so put the check in the setup() - not with == but check if within the 2 bounds as suggested by MarkT (if you want to do it only once) otherwise constantly update the pin in the loop by checking intervals instead of unique value

MarkT:
TEXT

I'm gonna see if I can make it work using your tips, but it might take me a while to get working (if I get it to work).

I'll get back to you, thanks!

Bunch of ifs can be managed as switch-case

MarkT:
For an interval you'll need a way of comparing hours/mins/seconds values against each other,
ie write a function that looks like:

boolean less_than (int h1, int m1, int s1, int h2, int m2, int s2)

{
 ...
}



Then you can code like


if (less_than (10, 30, 0, hours, mins, seconds) && less_than (hours, mins, seconds, 11, 45, 0))
   digitalWrite (pin, HIGH) ;
 else
   digitalWrite (pin, LOW) ;




For a hourly repeating interval its easier, you can ignore the hours (pass zero everywhere for hours):


if (less_than (0, 30, 0, 0, mins, seconds) && less_than (0, mins, seconds, 0, 45, 0))
   digitalWrite (pin, HIGH) ;
 else
   digitalWrite (pin, LOW) ;



or even simpler:


digitalWrite (pin, mins >= 30 && mins <= 45) ;



For every other hour, just add something like `&& (hour & 1) == 0`

Hi again,

I'm having trouble incorporating this into my sketch, would you mind showing me an example with the DS1307 library? I'm not just sure how to work this with the RTC. I'm seeing how it could work with other integers and values, but will it work with the RTC functions?

Should I declare int h1 = now.hour() and if so, how do I declare the h2 to compare it to?

Also, with the every other hour function, how does it work?

&& (hour & 1) == 0

As you can probably tell, I'm still pretty new to arduino and especially the RTC.

Thanks a lot for the help, I really appreciate it.