Get relays to switch on the 1/4 hour like a clock with an RTC

Hello,

I am using a RTC and Arduino Mega to make an interactive object that has a number of relays contorlled by the Arduino. 4 of the relays will go to lights #'d 1-4 that will flash #1 then #2 then #3 then #4 at 15 minutes past the hour. Then at 30 minutes past the hour the lights will flash #1, then #2, then #3 then #4 then #1 then #2 then #3 then #4. At 45 minutes the sequence will go 3 times. At the top of the hour the sequence will go 4 times followed by all four lights imultaneously flashing on and off based on the hour. This is similar to a bell tower.

Currently I can get that to work using the Time Alarms, but this will require me writing in an alarm for every 15 minutes. I want to figure out how to code that so I don't have to repeat myself in the code so much.

That light / clock sequence will be running while I have other relays turn on fans, motors and things on a controlled program so I need the rest of the program to run while the lights are doing their clock thing.

Here is what I have so far.

Full Code:

/*-----( Import needed libraries )-----*/
#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeAlarms.h>
 
/*-----( Declare Constants and Pin Numbers )-----*/

const int relayPin1 = 30;    // Light #1           
const int relayPin2 = 31;    // Light #2            
const int relayPin3 = 32;    // Light #3            
const int relayPin4 = 33;    // Light #4            
const int relayPin5 = 2;     // Fan #1          
const int relayPin6 = 3;     // Fan #2            
const int relayPin7 = 4;     // Motor #1            
const int relayPin8 = 5;     // Motor #2      
const int relayPin9 = 6;     // Motor #3           
const int relayPin10 = 7;    // Motor #4           

/*-----( Declare objects )-----*/
RTC_DS1307 rtc;    // Create a RealTimeClock object

uint32_t syncProvider() //function which sets up the RTC as the source of external time 
{
  return rtc.now().unixtime();
}

/*-----( Declare Variables )-----*/

// Variables will change:
int relayState1 = LOW;             
int relayState2 = LOW;            
int relayState3 = LOW;             
int relayState4 = LOW;            
int relayState5 = LOW;             
int relayState6 = LOW;             
int relayState7 = LOW;             
int relayState8 = LOW;            
int relayState9 = LOW;            
int relayState10 = LOW;             
int i;
int ding;
int n;
int hr;

void setup()   /****** SETUP: RUNS ONCE ******/
{
  
  pinMode(relayPin1, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin2, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin3, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin4, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin5, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin6, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin7, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin8, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin9, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin10, OUTPUT);      // sets the digital pin as output

  digitalWrite(relayPin1, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin2, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin3, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin4, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin5, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin6, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin7, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin8, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin9, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin10, HIGH);       // Prevents relays from starting up engaged
  
  Wire.begin();
  rtc.begin();
  rtc.adjust(DateTime(__DATE__, __TIME__)); //comment this out when the RTC has been set
  setSyncProvider(syncProvider);   // the function to get the time from the RTC

  
  // Have the allarm trigger at 00, 15, 30, 45, 00, 15, 30, 45 ....
  Alarm.alarmRepeat(11,00,0,BlinkHour);
  Alarm.alarmRepeat(11,15,0,Blink15Min);
  Alarm.alarmRepeat(11,30,0,Blink30Min);
  Alarm.alarmRepeat(11,45,0,Blink45Min);
  Alarm.alarmRepeat(12,00,0,BlinkHour); 
  Alarm.alarmRepeat(12,15,0,Blink15Min);   
  // There must be a better way then typing all of these individually ....
  
  Serial.begin(57600); // Set up for Serial Monitor to be able to see this work

}//--(end setup )---

void  loop(){ 
  digitalClockDisplay(); 
  Alarm.delay(1000); // wait one second between clock display 
}

// functions to be called when an alarm triggers:
void Blink4Times(){
     Serial.println("Alarm: - turn lights on and off in sequence at 15 minutes");  
     // if the LED is off turn it on and vice-versa:
     digitalWrite(relayPin1, LOW); 
     Alarm.delay(1000); // wait one second between clock display
     digitalWrite(relayPin1, HIGH); 
     digitalWrite(relayPin2, LOW); 
     Alarm.delay(1000); // wait one second between clock display
     digitalWrite(relayPin2, HIGH); 
     digitalWrite(relayPin3, LOW); 
     Alarm.delay(1000); // wait one second between clock display
     digitalWrite(relayPin3, HIGH); 
     digitalWrite(relayPin4, LOW); 
     Alarm.delay(1000); // wait one second between clock display
     digitalWrite(relayPin4, HIGH); 
     Alarm.delay(3000); // wait one second between clock display
}

void Blink15Min(){
  // Code to get some value of "n"
   n=1;
   for (i = 0; i < n; i++) {
     Blink4Times();
   Serial.print(n);  // Do "something"
 }
}
 
void Blink30Min(){
  // Code to get some value of "n"
   n=2;
   for (i = 0; i < n; i++) {
     Blink4Times();
   Serial.print(n);  // Do "something"
 }
}
 
 void Blink45Min(){
  // Code to get some value of "n"
   n=3;
   for (i = 0; i < n; i++) {
     Blink4Times();
   Serial.print(n);  // Do "something"
 }
 }
 
  void BlinkHour(){
  // Code to get some value of "n"
   n=4;
   for (i = 0; i < n; i++) {
     Blink4Times();
   Serial.print(n);  // Do "something"
 }
  // Code to get some value of "n"
   hr=(hour());
   for (i = 0; i < hr; i++) {
     BlinkAll();
   Serial.print(n);  // Do "something"
   }
 
 }

void BlinkAll (){
     digitalWrite(relayPin1, LOW); 
     digitalWrite(relayPin2, LOW);
     digitalWrite(relayPin3, LOW);
     digitalWrite(relayPin4, LOW);
     Alarm.delay(1000); // wait one second between clock display
     digitalWrite(relayPin1, HIGH);
     digitalWrite(relayPin2, HIGH);
     digitalWrite(relayPin3, HIGH);
     digitalWrite(relayPin4, HIGH);
     Alarm.delay(1000); // wait one second between clock display
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); 
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Seemingly redundant hand written 15 minute alarms

  // Have the allarm trigger at 00, 15, 30, 45, 00, 15, 30, 45 ....
  Alarm.alarmRepeat(11,00,0,BlinkHour);
  Alarm.alarmRepeat(11,15,0,Blink15Min);
  Alarm.alarmRepeat(11,30,0,Blink30Min);
  Alarm.alarmRepeat(11,45,0,Blink45Min);
  Alarm.alarmRepeat(12,00,0,BlinkHour); 
  Alarm.alarmRepeat(12,15,0,Blink15Min);   
  // There must be a better way then typing all of these individually ....

minutes%15 == 0 ?

Use the suggestion made by AWOL to do something every 15 minutes but note that

I can get that to work using the Time Alarms, but this will require me writing in an alarm for every 15 minutes

Is not actually true. You could use the Alarm.timerRepeat() function to trigger an event every 15 minutes.

AWOL:
minutes%15 == 0 ?

So you mean something like this? I am not sure I understand. Can you explain? Thank you.

Alarm.alarmRepeat(minutes%15 == 0);

UKHeliBob:
but note that is not actually true. You could use the Alarm.timerRepeat() function to trigger an event every 15 minutes.

Yes, I know that I can use the Timer.Repeat to make it go every 15 minutes but how do I make it go every 15 minutes and stay in sync with the top of the hour?

Does this work? Then I would find out if it is 15 min, 30 min 45 min or top of the hour?

// Have the allarm trigger at 00, 15, 30, 45, 00, 15, 30, 45 ....
  Alarm.alarmRepeat(11,00,0,Set15MinRepeat);

void Set15MinRepeat(){
  Alarm.timerRepeat(15, Blink4Times);  
}
// 

void Blink15Min(){
  // Find out if 15, 30, 45 or 00to get some value of "n"
int whattime;

if minute() = 15 then whattime = 1;
else if minute() = 30 then whattime = 2:
else if minute() = 45 then whattime = 3:
else if minute() = 00 then whattime = 4:   

n=whattime;

   for (i = 0; i < n; i++) {
     Blink4Times();
   Serial.print(n);  // Do "something"
 }
}

how do I make it go every 15 minutes and stay in sync with the top of the hour?

If that is a worry then set a simple alarm to happen at the first time required and have one of the actions triggered by the alarm set the next one and so on.

However, it is much simpler not to use TimeAlarms and use what AWOL suggested, but not like you did.
Something like this

if ( (minute() % 15) == 0)
{
  //code to do what you want every 15 minutes
}

UKHeliBob:
However, it is much simpler not to use TimeAlarms and use what AWOL suggested, but not like you did.

Since you said that it would be easier with AWOL's suggestion I am trying that like this below

void  loop() {
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display

  if ( (minute() % 15) == 0)
  {
    Blink15Min();
  }
}

void Blink15Min() {
  if (minute() == 15)
{ 
  n = 1;
}
else if (minute() == 30)
{
  n = 2;
} 
else if (minute() == 45)
{
  n = 3;
}  
else if (minute() == 0)
{
  n = 4;
  BlinkHour();
} 
for (i = 0; i < n; i++) {
  Blink4Times();
  }
}

void BlinkHour() {
  hr = (hour());
  for (i = 0; i < hr; i++) {
    BlinkAll();
  }
}

Now the problem is that at 15 minutes it goes through the blink cycle multiple times before it turns to 16. I only want it to run once.

Do I set a hasrun variable? and then reset it in the 30 min section while setting a hasrun for the 30 min?

void Blink15Min() {
  if (minute() == 15 && 15hasrun == false)
{ 
  n = 1;
  15hasrun = true;
  00hasrun = false;
}
else if (minute() == 30 && 30hasrun == false)
{
  n = 2;
  30hasrun = true;
  15hasrun = false;

} 
else if (minute() == 45 && 45hasrun == false)
{
  n = 3;
  45hasrun = true;
  30hasrun = false;

}  
else if (minute() == 0 && 00hasrun == false)
{
  n = 4;
  00hasrun = true;
  45hasrun = false;
  BlinkHour();
} 
for (i = 0; i < n; i++) {
  Blink4Times();
  Serial.print(n);  // Do "something"
  }
}

void BlinkHour() {
  hr = (hour());
  for (i = 0; i < hr; i++) {
    BlinkAll();
    Serial.print(n);  // Do "something"
  }
}

Do I set a hasrun variable? and then reset it in the 30 min section while setting a hasrun for the 30 min?

That sounds about right.

UKHeliBob:
That sounds about right.

Took a bit to figure out how to do that but it seems to work now. I also subtracted 12 from the pm clock hour in order to count the right number of blinks on the hour.

I think the

Alarm.delay(1000);

is stopping the program so I will have to find another way to pause in between blinks but should be able to use the mills interval.

Here is the current working code. Probably a better way to do it but this is what I have for now. Thanks for the help.

/*-----( Import needed libraries )-----*/
#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeAlarms.h>

/*-----( Declare Constants and Pin Numbers )-----*/

const int relayPin1 = 30;    // Light #1
const int relayPin2 = 31;    // Light #2
const int relayPin3 = 32;    // Light #3
const int relayPin4 = 33;    // Light #4
const int relayPin5 = 2;     // Fan #1
const int relayPin6 = 3;     // Fan #2
const int relayPin7 = 4;     // Motor #1
const int relayPin8 = 5;     // Motor #2
const int relayPin9 = 6;     // Motor #3
const int relayPin10 = 7;    // Motor #4

/*-----( Declare objects )-----*/
RTC_DS1307 rtc;    // Create a RealTimeClock object

uint32_t syncProvider() //function which sets up the RTC as the source of external time
{
  return rtc.now().unixtime();
}

/*-----( Declare Variables )-----*/

int relayState1 = LOW;
int relayState2 = LOW;
int relayState3 = LOW;
int relayState4 = LOW;
int relayState5 = LOW;
int relayState6 = LOW;
int relayState7 = LOW;
int relayState8 = LOW;
int relayState9 = LOW;
int relayState10 = LOW;
int i;
int ding;
int n;
int hr;
int has15run = 0;
int has30run = 0;
int has45run = 0;
int has00run = 0;

void setup()   /****** SETUP: RUNS ONCE ******/
{

  pinMode(relayPin1, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin2, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin3, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin4, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin5, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin6, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin7, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin8, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin9, OUTPUT);      // sets the digital pin as output
  pinMode(relayPin10, OUTPUT);      // sets the digital pin as output

  digitalWrite(relayPin1, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin2, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin3, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin4, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin5, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin6, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin7, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin8, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin9, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(relayPin10, HIGH);       // Prevents relays from starting up engaged
  
  Serial.begin(57600); // Set up for Serial Monitor to be able to see this work
  Wire.begin();
  rtc.begin();
  // rtc.adjust(DateTime(__DATE__, __TIME__)); //comment this out when the RTC has been set
  setSyncProvider(syncProvider);   // the function to get the time from the RTC

}//--(end setup )---

void  loop() {
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
  blinkClock();
  nightLights();
}

void Blink4Times() {
  Serial.println("Alarm: - turn lights on and off in sequence at 15 minutes");
  turnOffLights (); // Make sure lights turn of before blinking in case on at night
  Alarm.delay(1000);
  digitalWrite(relayPin1, LOW);
  Alarm.delay(1000); 
  digitalWrite(relayPin1, HIGH);
  digitalWrite(relayPin2, LOW);
  Alarm.delay(1000); 
  digitalWrite(relayPin2, HIGH);
  digitalWrite(relayPin3, LOW);
  Alarm.delay(1000);
  digitalWrite(relayPin3, HIGH);
  digitalWrite(relayPin4, LOW);
  Alarm.delay(1000); 
  digitalWrite(relayPin4, HIGH);
  Alarm.delay(2000);  
}

void turnOffLights () {
  digitalWrite(relayPin1, HIGH); // Make sure all lights are off
  digitalWrite(relayPin2, HIGH); // Make sure all lights are off
  digitalWrite(relayPin3, HIGH); // Make sure all lights are off
  digitalWrite(relayPin4, HIGH); // Make sure all lights are off
}

void turnOnLights () {
  digitalWrite(relayPin1, LOW); // Make sure all lights are on
  digitalWrite(relayPin2, LOW); // Make sure all lights are on
  digitalWrite(relayPin3, LOW); // Make sure all lights are on
  digitalWrite(relayPin4, LOW); // Make sure all lights are on
}

void Blink15Min() {
  if (minute() == 15 && has15run == 0) { 
  n = 1;
  blinkCount();
  has15run = 1;
  has00run = 0;
  }
  else if (minute() == 30 && has30run == 0) {
  n = 2;
  blinkCount();
  has30run = 1;
  has15run = 0;
  } 
  else if (minute() == 45 && has45run == 0) {
  n = 3;
  blinkCount();
  has45run = 1;
  has30run = 0;
  }  
  else if (minute() == 0 && has00run == 0) {
  n = 4;
  blinkCount();
  blinkHour();
  has00run = 1;
  has45run = 0;
  } 
}

void blinkCount() {
for (i = 0; i < n; i++) {
  Blink4Times();
  Serial.print(n);  // Do "something"
  }
}

void blinkHour() {
  hr = (hour());
  if (hr > 12) {
    hr == hr - 12;
  }  
  for (i = 0; i < hr; i++) {
    blinkAll();
    Serial.print(n);  // Do "something"
  }
}

void blinkAll () {
  turnOnLights ();
  Alarm.delay(2000); // wait one second between clock display
  turnOffLights ();
  Alarm.delay(1000); // wait one second between clock display
}

void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

void printDigits(int digits) {
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void blinkClock() {
    if ( (minute() % 15) == 0) {
    Blink15Min();
    }
}

void nightLights() {
  if ( hour() > 19 && hour() < 24) {
      turnOnLights ();
  }
  else if ( hour() > 0 && hour() < 5) {
      turnOnLights ();
  }  
  else {
      turnOffLights ();
  }  
}

You don't seem to be using TimeAlarms at all so no need to #include the library. For the same reason you do not need to use Alarm.delay() and changing to millis() timing is an excellent idea.