Arduino looses Relay state with time based DS3231 after powering off

Hello,

I want my Arduino to control external lighting according to the time. Easily activate relay on certain time and turn off certain time. I’m using RinkyDink rtc library and the time has been set to DS3231.
Ds3231 is connected to SCL and SDA ports. On serial monitor when the lights are on the relay is activated and when relay state is off it displays Lights off. That way it works the best, when the POWER has not been off. After powering the arduino again, it does not activate the relay and on Serial monitor only displays the time, not the relay state or smth.

I will attach the sketch

#include <DS3231.h>

int Relay = 4;

DS3231  rtc(SDA, SCL);
Time t;

const int OnHour = 16;
const int OnMin = 45;
const int OffHour = 8;
const int OffMin = 30;

void setup() {
  Serial.begin(9600);
  rtc.begin();
  pinMode(Relay, OUTPUT);
  digitalWrite(Relay, LOW);
}

void loop() {
  t = rtc.getTime();
  Serial.print(t.hour);
  Serial.print(" hour(s), ");
  Serial.print(t.min);
  Serial.print(" minute(s)");
  Serial.println(" ");
  delay (1000);
  if(OnHour < OffHour){
    digitalWrite(Relay,HIGH);
    Serial.println("LIGHT ON");
    }
  
  if(t.hour == OnHour && t.min == OnMin){
    digitalWrite(Relay,HIGH);
    Serial.println("LIGHT ON");
    }
    
    else if(t.hour == OffHour && t.min == OffMin){
      digitalWrite(Relay,LOW);
      Serial.println("LIGHT OFF");
    }
}

You can add some code in setup() to check the RTC time against your on and off times.

As it stands, I think your code will do what you want as long as power is restored during the same hour and minute you are checking for in loop(). If time moves on into another minute before power is re-applied, then your tests won't detect this.

Use this :

totalMinutes = RTChours * 60 + RTCminutes;
If( totalMinutes >= offTime && totalMinutes < onTime)
   TurnRelayOff();
else
    TurnRelayOn()
  delay (1000);
  if(OnHour < OffHour){
    digitalWrite(Relay,HIGH);
    Serial.println("LIGHT ON");
    }

I don’t think that’s what you mean to do. OnHour and OffHour are constants. The IF condition will never be true.

One other issue is that if you match hours and minutes in the loop, and check once per second, then you'll get the serial print 60 times. So maybe add a condition to the IF statements that the relay pin isn't already there:

  if(t.hour == OnHour && t.min == OnMin && digitalRead(Relay) == LOW){
    digitalWrite(Relay,HIGH);
    Serial.println("LIGHT ON");
    }

    else if(t.hour == OffHour && t.min == OffMin && digitlRead(Relay) == HIGH){
      digitalWrite(Relay,LOW);
      Serial.println("LIGHT OFF");
    }

I agree with the others that the test for the initial state should be moved up to the setup function, and convert the times to (hours *60 + minutes) to do the testing.

If the output is defined solely by whether or not the current time is between the specified hours, then if you get a wrong state in initialisation, the problem is in the code.

Sadly, the DS3231, unlike the less accurate RTCs, does not have the dedicated BBRAM which you could conveniently use to remember the last state. :astonished:

The Arduino's own EEPROM will do that job just fine. Assuming the power is not switched off and on a couple hundred times a day... but even then the EEPROM would still last for a few years.

Paul__B:
Sadly, the DS3231, unlike the less accurate RTCs, does not have the dedicated BBRAM which you could conveniently use to remember the last state. :astonished:

Whilst what you say is true, if you only need to remember a few values/states, you may be able to use some of the alarm registers as storage during power outs.

markd833:
if you only need to remember a few values/states, you may be able to use some of the alarm registers as storage during power outs.

Ah! You thought of that too! :sunglasses:

I didn't look into that in detail. Arguably, the OP only wanted a single boolean. :grinning: