Relay activated by RTC

Hi!
I could use some assistance with the following project:

I'm trying to control two relays which activate a pump and some led lights. The pump is activated by moisture readings, and I have no problems getting this to work as I want it to.

However, controlling the other relay through an RTC (DS1302) has so far proven to be too difficult for me.
I've tried the TimeAlarms function (as you can see in the code below), but to no effect.

Can somebody please help me with what I am missing?

#include <DS1302.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Time.h>
#include <TimeAlarms.h> 

DS1302 rtc(6, 7, 8);

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

int moistureSensor = 0;

const int pumpPin = 2;   
const int lightPin = 4;   



void setup() {
  
  
  rtc.halt(false);
  rtc.writeProtect(false);


  Serial.begin(9600);

  
  rtc.setDOW(FRIDAY);        // Set Day-of-Week to FRIDAY
  rtc.setTime(16, 19, 30);     // Set the time to 12:00:00 (24hr format)
  rtc.setDate(6, 8, 10);   // Set the date to August 6th, 2010

    
  pinMode(pumpPin, OUTPUT);   
  pinMode(lightPin, OUTPUT);


  Alarm.alarmRepeat(16,25,0, LightOn);
  Alarm.alarmRepeat(16,26,0, LightOff);
  
  lcd.begin(16, 2);

  lcd.print(" Test ");
  lcd.setCursor(0,1);
  lcd.print("moisture sensor ");

  delay(2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("High value = dry");
  lcd.setCursor(0,1);
  lcd.print("Low value = wet");
    delay(1000);
    lcd.clear();
    lcd.print(" optimum value");
    lcd.setCursor(0,1);
    lcd.print(" > 350----650 <");
    delay(1000);
  lcd.clear(); 

 
  
}

void loop() {

    
  int sensorValue = analogRead(moistureSensor);

  lcd.setCursor(0,0);

  lcd.print(" Moisture value ");

  lcd.setCursor(0,1);
  lcd.print("");

  lcd.print(sensorValue);

  delay(2000);
  lcd.setCursor(0,1);
  lcd.clear();

  lcd.setCursor(0,1);
  lcd.print(sensorValue);
  lcd.clear();
   

  if (sensorValue >= 600)

  {
  digitalWrite(pumpPin, HIGH);
  }
  delay(3000);
  {
  digitalWrite(pumpPin, LOW);
  }
  delay(10000);

}


void LightOn() 
{
  digitalWrite(lightPin, HIGH);
  
}

void LightOff() 
{
  digitalWrite(lightPin, LOW);
}

Can somebody please help me with what I am missing?

I think you are missing two things.

First, the Arduino and Time/TimeAlarms libraries needs to know the real time you have set on the RTC. There is Time library function called setSyncProvider() which does that and keeps the Arduino continually updated with the rtc time so that the time derived from the millis() clock will not drift. You need to pass setSyncProvider() the unix time value from the rtc, and the way to do that will be determined by the rtc library.

There are several DS1302 libraries, and the exact command will be different. Some libraries integrate better than others. The library available through Arduino playground is easy to sync with the RTC. Arduino Playground - HomePage
It looks like you may be using the library from RinkyDink(Hening Karlsen) which is more coplicated to sync with the time library.

Second, use of the time alarms requires the use of a special call

Alarm.delay(milliseconds);
Alarms and Timers are only checks and their functions called when you use this delay function. You can pass 0 for minimal delay. This delay should be used instead of the normal Arduino delay(), for timely processing of alarms and timers.

Some background research on both the time library and time alarms library would be useful
http://www.pjrc.com/teensy/td_libs_TimeAlarms.html
http://www.pjrc.com/teensy/td_libs_Time.html

As a final comment, I would recommend changing your RTC to a DS3231 (or DS1307) which has more examples and more support available. The DS1302 is really off on its own.

1 Like

There really is no reason to use the TimeAlarms library. On any given pass through loop() it either is, or is not. time to do something.

bool doneTodaysTask = false;

void loop()
{
   // read the time

   if(now.hour == when.hour && now.minute == when.minute && !doneTodaysTask)
   {
      dotodaysTask();
      doneTodaysTask = true;
   }
   else
      doneTodaysTask = false;
}

Talking directly to an RTC with Wire is not super difficult. Libraries always hide things, or do things in an idiosyncratic way, or make things more complicated. The main benefit of them is to provide a consistent interface to pluggable hardware, and that's not what's going on when you are building an arduino project.

Here's a snippet from my own project. This code is called every few minutes or so by my sketch, and its job is to update a variable timeOfDaySec which holds the current time of day, accurate to one second.

SimpleClock.cpp

  Wire.beginTransmission(DS3232_I2C_ADDRESS);
  Wire.write(0); // set DS3232 register pointer
  Wire.endTransmission();
  Wire.requestFrom(DS3232_I2C_ADDRESS, 3); // request 3 bytes of data from DS3232 starting from register 00h

  // A few of these need masks because certain bits are control bits
  byte second     = bcdToDec(Wire.read());
  byte minute     = bcdToDec(Wire.read());
  byte hour       = bcdToDec(Wire.read() & 0x3f);

  timeofdaySec = ((long)hour) * 60L * 60L + ((long)minute) * 60L + (long) second;

And that is really all that is needed to read a DS3232 RTC.