I'm making a project using an Arduino Nano, DS3231 RTC module and a 4 channel 5V Relay module. I want to run some appliances when a certain time is set with the relays. Everything is hooked up and the hardware setup works fine. My problem is with the programming side. I've set the time and the serial monitor confirms that the RTC works ok. Then I changed the program to set the timer to work when relay wants to trigger ( 18:00 to ON and 23:00 to OFF ). The RTC keeps memory of it times. The relay works ON when 18:00 Trigger On and at 23:00 hours, the relay goes OFF. But the weird thing is that after half an hour the relay goes back to ON. I don't know why.
my code is
//SPECIFIC TIME TRIGGER RELAY
#include <DS3231.h>
int RelayA = 12; // Pin Number for Relay
int RelayB = 11; // Pin Number for Relay
int RelayC = 10; // Pin Number for Relay
int RelayD = 9; // Pin Number for Relay
DS3231 rtc(SDA, SCL);
Time t;
const int OnHour = 18; //SET TIME TO ON RELAY (24 HOUR FORMAT)
const int OffHour = 23; //SET TIME TO OFF RELAY
void setup() {
Serial.begin(115200);
rtc.begin();
pinMode(RelayA, OUTPUT); // Set Pinmode of OUTPUT
pinMode(RelayB, OUTPUT); // Set Pinmode of OUTPUT
pinMode(RelayC, OUTPUT); // Set Pinmode of OUTPUT
pinMode(RelayD, OUTPUT); // Set Pinmode of OUTPUT
digitalWrite(RelayA, HIGH); // High triggers OFF
digitalWrite(RelayB, HIGH); // High triggers OFF
digitalWrite(RelayC, HIGH); // High triggers OFF
digitalWrite(RelayD, HIGH); // High triggers OFF
}
void loop() {
t = rtc.getTime();
Serial.println(rtc.getTimeStr());
delay (1000);
if(t.hour >= OnHour && t.hour <= OffHour) // If 18:00 >= & 23:00<= then Relay is ON
{
digitalWrite(RelayA,LOW);
digitalWrite(RelayB,LOW);
digitalWrite(RelayC,LOW);
digitalWrite(RelayD,LOW);
Serial.println("LIGHT ON");
}
else // Else Relay if OFF
{
digitalWrite(RelayA,HIGH);
digitalWrite(RelayB,HIGH);
digitalWrite(RelayC,HIGH);
digitalWrite(RelayD,HIGH);
Serial.println("LIGHT OFF");
}
}
The library is Library: DS3231 from Rinky-Dink Electronics
Either way, the logic is primitive. There's no need to do the digitalWrite() calls on every pass through loop. The hour only changes once per hour, you're calling digitalWrite() 3600 times per hour. Instead of checking when the hour IS some value, check when it BECOMES that value. The concept is similar to that in the StateChangeDetection example that's built into the Arduino IDE.
Something like:
void loop() {
t = rtc.getTime();
static uint8_t previousHour {t.hour};
Serial.println(rtc.getTimeStr());
delay (1000);
uint8_t currentHour {t.hour};
if (currentHour != previousHour) {
previousHour = currentHour;
if (currentHour == OnHour) {
// Turn on Relays here
} else if (currentHour == Off Hour) {
// Turn off Relays here
}
}
}
The only way I see the happening is if you get a bad response from the RTC. Unfortunately there is not much error checking on the I2C. What time did Arduino print before the relay turned on again?
as the condition for eveything to be ON. The '<=' means this runs from OnHour through OffHour.
Yet you say it turned off at 23:00. I read it as turning off at 0:00.
That's one thing, maybe you were reporting it wrong or I am reading the code wrong or you changed it since. No matter.
But you also report that "after half an hour the relay goes back to ON." I am sure there is nothing in the code that would make anything happen other than very near to exactly on the hour, whatever the hour may turn out to be.
Since it now works but didn't, and I do not believe @ahsrabrifat's change is meaningful other than fixing running through the 23rd hour rather than stopping at that time, we are compelled (!) to look elsewhere, rather than guess and move on.
You haven't posted a schematic or any pictures. Perhaps there is a loose connection or a marginal power supply issue or... a few things that are not the code.
Pro tip: whilst testing, use seconds not hours and fix the logic to, say, be on from 10 seconds to 42 seconds. This will make finding or seeing faults much quicker. How much quicker, Mr. Spock?
I looked at the code from @gfvalvo and I don't know will this work in case of a power outage. Like example, if I had a power outage at 19:00 and gets power back at 20:00, will this still work? I used that > and < in case of power outage.
I think that's right. If you see only the hour change as an opportunity to turn on, or off, the stuff it will not handle a power outrage.
You could create more code somewhere to know and handle this, or leave the logic you arrived at.
If turning on something that is already on, or off something already off offends or is not a good idea because of whatever it is you are turning on and off, that can be handled very simple.
Of course there is no reason and no harm writing HIGH to a bit that is already. But if turning stuff on meant some kind of startup that should only be done once, you can track it with a boolean variable like
bool stuffBeOn;
And later to turn something on but not again write
if (!stuffBeOn) {
// code to start and turn on something
stuffBeOn = true;
}
and obvsly I hope to turn stuff off
if (stuffBeOn) {
// code to shut down and turn off something
stuffBeOn = false;
}
Don't miss the '!' logical negation operator in the turning on if condition: "If the thing is not on, turn it on and remember that you did."
Print the time out inside the if statement clauses that the turn the relays on / off. That will tell you why execution entered the clause.
As already mentioned, that is properly handled in the setup() function which will run once (and only once) after power up.
Your loop code is more properly handled using the state changed detection model as I've stated. The way you have it doesn't lend itself to adding new features. Also, you should ditch the delay() statement in favor of a millis() timer to handle periodic tasked. That will make your code non-blocking and again more conducive to moving beyond its current, primitive functionality.
#include <DS3231.h>
int RelayA = 12; // Pin Number for Relay A
int RelayB = 11; // Pin Number for Relay B
int RelayC = 10; // Pin Number for Relay C
int RelayD = 9; // Pin Number for Relay D
DS3231 rtc(SDA, SCL);
Time t;
const int OnHour = 18; // Time to turn ON relays (24-hour format)
const int OffHour = 23; // Time to turn OFF relays (24-hour format)
int lastHour = -1; // Variable to store the previous hour to detect change
bool relayState = false; // Track relay state: false = OFF, true = ON
void setup() {
Serial.begin(115200);
rtc.begin();
// Initialize each relay pin and set them to OFF (HIGH for active-high relays)
pinMode(RelayA, OUTPUT);
pinMode(RelayB, OUTPUT);
pinMode(RelayC, OUTPUT);
pinMode(RelayD, OUTPUT);
// Set all relays to OFF initially (HIGH means OFF for active-high relays)
digitalWrite(RelayA, HIGH);
digitalWrite(RelayB, HIGH);
digitalWrite(RelayC, HIGH);
digitalWrite(RelayD, HIGH);
// Check the current time immediately after power-up
t = rtc.getTime();
// If the current time is within the ON period (18:00 to before 23:00), turn the relays ON
if (t.hour >= OnHour && t.hour < OffHour) {
digitalWrite(RelayA, LOW);
digitalWrite(RelayB, LOW);
digitalWrite(RelayC, LOW);
digitalWrite(RelayD, LOW);
Serial.println("LIGHT ON");
relayState = true; // Set relay state to ON
} else {
// If the current time is outside the ON period, keep the relays OFF
Serial.println("LIGHT OFF");
relayState = false; // Set relay state to OFF
}
}
void loop() {
t = rtc.getTime();
// Check if the hour has changed
if (t.hour != lastHour) {
// Update the last hour to the current hour
lastHour = t.hour;
// Check if the current time is within the ON period (18:00 to before 23:00)
if (t.hour >= OnHour && t.hour < OffHour && !relayState) {
// Turn ON all relays (set to LOW to trigger the relays ON)
digitalWrite(RelayA, LOW);
digitalWrite(RelayB, LOW);
digitalWrite(RelayC, LOW);
digitalWrite(RelayD, LOW);
Serial.println("LIGHT ON");
relayState = true; // Update the state to ON
}
// Check if the current time is outside the ON period (after 23:00 or before 18:00)
else if ((t.hour >= OffHour || t.hour < OnHour) && relayState) {
// Turn OFF all relays (set to HIGH to trigger the relays OFF)
digitalWrite(RelayA, HIGH);
digitalWrite(RelayB, HIGH);
digitalWrite(RelayC, HIGH);
digitalWrite(RelayD, HIGH);
Serial.println("LIGHT OFF");
relayState = false; // Update the state to OFF
}
}
delay(1000); // Check the time every second, but only update on hour change
}