Relays?

I have 3 relays that I want to monitor. I want to keep record when they turn on and off by days I want to know how long they stay on. Can someone help me set this up The following is the part of the code that pertains to the relays

 for (int i = 0; i < sizeof(OnHour1) / sizeof(OnHour1[0]); i++)
    for (int i = 0; i < sizeof(OnMin1) / sizeof(OnMin1[0]); i++)
      for (int i = 0; i < sizeof(OnDay1) / sizeof(OnDay1[0]); i++)
        for (int i = 0; i < sizeof(OnMonth1) / sizeof(OnMonth1[0]); i++)      //This will turn one relay on and off

          if ((now.hour() == OnHour1[i]) && (now.minute() == OnMin1[i]) && (now.day() == OnDay1[i]) && (now.month() == OnMonth1[i])) {
            mcp.digitalWrite(0, LOW);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(0, 48);
            display1.println("ON");
            display1.display();
          }
          else if ((now.hour() == OffHour1[i]) && (now.minute() == OffMin1[i]) && (now.day() == OffDay1[i]) && (now.month() == OffMonth1[i])) {
            mcp.digitalWrite(0, HIGH);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(0, 48);
            display1.println("OFF");
            display1.display();
          }

I’m not really following the logic in your for loops there. Personally I’d grab an NTP library and save a timestamp when you turn the relay on and when you turn it off subtract the on timestamp from the off timestamp to get how long it’s been on. What you do with that from there is the next question. personally I have an MQTT server that I send data to log info in a database but not everyone has that available. You could store it in flash memory on the device.

1 Like

Let me post the whole code. For some reason I was thinking I could use Cayenne.virtualWrite.
The relays will on for about 10 -15 min a couple times a day

/*-----( Import needed libraries for Oled )-----*/
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include "Adafruit_MCP23017.h"
#include <SPI.h>
#include <DHT.h>
#include <DHT_U.h>
#include <Wire.h>
#include "RTClib.h"
#include "DHT.h"
#define DHTPIN 2     // what digital pin we're connected to
#define DHTTYPE DHT11   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
#define OLED_RESET 0
Adafruit_MCP23017 mcp;
Adafruit_SSD1306 display1(OLED_RESET);
Adafruit_SSD1306 display2(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
/*-----( Import needed libraries for RTC )-----*/
/*-----( Declare Constants and Pin Numbers )-----*/
// Not needed: RTC Lib expects connections as above

/*-----( Declare objects )-----*/
RTC_DS1307 rtc;    // Create a RealTimeClock object
int OnMin1 [] = {17, 18, 19, 20};
int OnHour1 [] = {17, 18, 19, 20}; //= {2, 4, 8, 3, 6};       //[]= {17,18,19,20};//Array multi hour
int OnDay1  [] = {17, 18, 19, 20};
int OnMonth1  [] = {1, 5, 6, 6};
int OnYear1  [] = {2018.2019};

int OffMin1 [] = {17, 18, 19, 20};
int OffHour1  [] = {17, 18, 19, 20};
int OffDay1   [] = {8, 18, 19, 20};
int OffMonth1  [] = {1, 5, 6, 7};
int OffYear1   [] = {2018, 2019,};

int OnMin2 [] = {17, 18, 19, 20};
int OnHour2 [] = {17, 18, 19, 20}; //= {2, 4, 8, 3, 6};       //[]= {17,18,19,20};//Array multi hour
int OnDay2  [] = {17, 18, 19, 20};
int OnMonth2  [] = {1, 5, 6, 6};
int OnYear2  [] = {2018.2019};

int OffMin2 [] = {17, 18, 19, 20};
int OffHour2  [] = {17, 18, 19, 20};
int OffDay2   [] = {8, 18, 19, 20};
int OffMonth2  [] = {1, 5, 6, 7};
int OffYear2   [] = {2018, 2019,};

int OnMin3 [] = {17, 18, 19, 20};
int OnHour3 [] = {17, 18, 19, 20}; //= {2, 4, 8, 3, 6};       //[]= {17,18,19,20};//Array multi hour
int OnDay3 [] = {17, 18, 19, 20};
int OnMonth3  [] = {1, 5, 6, 6};
int OnYear3 [] = {2018.2019};

int OffMin3 [] = {17, 18, 19, 20};
int OffHour3  [] = {17, 18, 19, 20};
int OffDay3  [] = {8, 18, 19, 20};
int OffMonth3  [] = {1, 5, 6, 7};
int OffYear3  [] = {2018, 2019,};
// This example shows how to connect to Cayenne using an ESP8266 and send/receive sample data.
// Make sure you install the ESP8266 Board Package via the Arduino IDE Board Manager and select the correct ESP8266 board before compiling. 

//#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

// WiFi network info.
char ssid[] = "xxx";
char wifiPassword[] = "xxx";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "";
char password[] = "";
char clientID[] = "";

unsigned long lastMillis = 0;


/*-----( Declare Variables )-----*/
// NONE because the library handles this...

void setup()   /****** SETUP: RUNS ONCE ******/
{
  mcp.begin(); 0x20;    // use default address 0
  Serial.begin(9600);
  display1.begin(SSD1306_SWITCHCAPVCC, 0x3D);// initialize with the I2C addr 0x3C (for the 128x64)
  display2.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  dht.begin();
  display1.display();
  display2.display();
  delay(2000);
  Wire.begin();
  rtc.begin(); // Start the RTC library code
  Cayenne.begin(username, password, clientID, ssid, wifiPassword);
  mcp.pinMode(0, OUTPUT);
  mcp.pinMode(1, OUTPUT);
  mcp.pinMode(2, OUTPUT);
  mcp.pinMode(3, OUTPUT);
  mcp.digitalWrite(0, HIGH);
  mcp.digitalWrite(1, HIGH);
  mcp.digitalWrite(2, HIGH);
  mcp.digitalWrite(3, HIGH);


  /*----( SET the date and time.  Comment OUT these lines after setting )----*/
  // Put these "//" in front of the line you do NOT want to use
  // following line sets the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // May 21, 2015 at 6pm you would call: (use 24 hour time)
  //rtc.adjust(DateTime(2018, 1, 2, 15, 17, 0));




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


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  DateTime now = rtc.now();  // Read data from the RTC Chip
  Cayenne.loop();

  display1.clearDisplay();
  // text display tests
  display1.setTextSize(2);
  display1.setTextColor(WHITE);
  display1.setCursor(4, 0);
  display1.print(now.year(), DEC); //
  display1.print('*');
  display1.print(now.month(), DEC);
  display1.print('*');
  display1.print(now.day(), DEC);
  display1.print('*');
  display1.setTextSize(2);
  display1.setTextColor(WHITE);
  display1.setCursor(10, 16);
  display1.print(now.hour(), DEC);
  display1.print(':');
  display1.print(now.minute(), DEC);
  display1.print(':');
  display1.print(now.second(), DEC);
  display1.println();
  display1.setTextSize(2);
  display1.setTextColor(WHITE);
  display1.setCursor(0, 32);
  display1.println("Z1- Z2- Z3");
  display1.display();
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  byte h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  byte t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  byte f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  // Compute heat index in Fahrenheit (the default)
  byte hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  byte hic = dht.computeHeatIndex(t, h, false);
  display2.clearDisplay();
  // text display tests
  display2.setTextSize(2);
  display2.setTextColor(WHITE);
  display2.setCursor(0, 0);
  display2.print("Humid ");
  display2.print(h);
  display2.print("%");
  display2.setTextSize(2);
  display2.setTextColor(WHITE);
  display2.setCursor(0, 16);
  display2.print("Temp  ");
  display2.print(f);
  display2.print("F");
  display2.setTextSize(2);
  display2.setTextColor(WHITE);
  display2.setCursor(0, 32);
  display2.print("Heat Index");
  display2.setTextSize(2);
  display2.setTextColor(WHITE);
  display2.setCursor(50, 48);
  display2.print(hif);
  display2.println("F");
  display2.display();
  
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  //Serial.print(t);
  //Serial.print(" *C ");
  Serial.print(f);
  Serial.print(" *F\t");
  Serial.print("Heat index: ");
  //Serial.print(hic);
  //Serial.print(" *C ");
  Serial.print(hif);
  Serial.println(" *F");
  delay(500);

  Serial.print(now.year(), DEC); //
  Serial.print('-');
  Serial.print(now.month(), DEC);
  Serial.print('-');
  Serial.print(now.day(), DEC);
  Serial.print('  ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.println();

  delay(500);//Relay 0
  for (int i = 0; i < sizeof(OnHour1) / sizeof(OnHour1[0]); i++)
    for (int i = 0; i < sizeof(OnMin1) / sizeof(OnMin1[0]); i++)
      for (int i = 0; i < sizeof(OnDay1) / sizeof(OnDay1[0]); i++)
        for (int i = 0; i < sizeof(OnMonth1) / sizeof(OnMonth1[0]); i++)      //This will turn one relay on and off

          if ((now.hour() == OnHour1[i]) && (now.minute() == OnMin1[i]) && (now.day() == OnDay1[i]) && (now.month() == OnMonth1[i])) {
            mcp.digitalWrite(0, LOW);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(0, 48);
            display1.println("ON");
            display1.display();
          }
          else if ((now.hour() == OffHour1[i]) && (now.minute() == OffMin1[i]) && (now.day() == OffDay1[i]) && (now.month() == OffMonth1[i])) {
            mcp.digitalWrite(0, HIGH);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(0, 48);
            display1.println("OFF");
            display1.display();
          }
  // Relay 1
  for (int i = 0; i < sizeof(OnHour2) / sizeof(OnHour2[0]); i++)
    for (int i = 0; i < sizeof(OnMin2) / sizeof(OnMin2[0]); i++)
      for (int i = 0; i < sizeof(OnDay2) / sizeof(OnDay2[0]); i++)
        for (int i = 0; i < sizeof(OnMonth2) / sizeof(OnMonth2[0]); i++)      //This will turn one relay on and off

          if ((now.hour() == OnHour2[i]) && (now.minute() == OnMin2[i]) && (now.day() == OnDay2[i]) && (now.month() == OnMonth2[i])) {
            mcp.digitalWrite(1, LOW);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(50, 48);
            display1.println("ON");
            display1.display();
          }
          else if ((now.hour() == OffHour1[i]) && (now.minute() == OffMin1[i]) && (now.day() == OffDay1[i]) && (now.month() == OffMonth1[i])) {
            mcp.digitalWrite(1, HIGH);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(50, 48);
            display1.println("OFF");
            display1.display();
          }

  for (int i = 0; i < sizeof(OnHour3) / sizeof(OnHour3[0]); i++)
    for (int i = 0; i < sizeof(OnMin3) / sizeof(OnMin3[0]); i++)
      for (int i = 0; i < sizeof(OnDay3) / sizeof(OnDay3[0]); i++)
        for (int i = 0; i < sizeof(OnMonth3) / sizeof(OnMonth3[0]); i++)      //This will turn one relay on and off

          if ((now.hour() == OnHour3[i]) && (now.minute() == OnMin3[i]) && (now.day() == OnDay3[i]) && (now.month() == OnMonth3[i])) {
            mcp.digitalWrite(2, LOW);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(100, 48);
            display1.println("ON");
            display1.display();
          }
          else if ((now.hour() == OffHour3[i]) && (now.minute() == OffMin3[i]) && (now.day() == OffDay3[i]) && (now.month() == OffMonth3[i])) {
            mcp.digitalWrite(2, HIGH);
            display1.setTextSize(2);
            display1.setTextColor(WHITE);
            display1.setCursor(100, 48);
            display1.println("OFF");
            display1.display();
          }
 //Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
 if (millis() - lastMillis > 10000) {
    lastMillis = millis();
    //Write data to Cayenne here. This example just sends the current uptime in milliseconds.
    Cayenne.virtualWrite(0, lastMillis);
    //Some examples of other functions you can use to send data.
    //Cayenne.celsiusWrite(1, 22.0);
    //Cayenne.luxWrite(2, 700);
    //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);         


}
//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
//CAYENNE_IN_DEFAULT()

  //CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

//--(end main loop )---

/*-----( Declare User-written Functions )-----*/
//NONE

//*********( THE END )***********

Sorry, I’m still not following it. I can’t test right now but from what I’m gathering in for (int i = 0; i < sizeof(OnHour1) / sizeof(OnHour1[0]); i++) sizeof(OnHour1) is 4 and sizeof(OnHour1[0]) is 1, right? I think there’s a better way to achieve this without for loops using time.

I have had a lot of discussion on the for loops. One think I wanted is to be able run multiply days hours or whatever. Also tried not to stop the code anywhere. I admit I am a new to coding so I am always open to listen to someone else. The code compiles and works like it should. I know nested loops are not good but it only has a few values in each loop.

If I get some time this weekend I’ll see if I can come up with something. In the meantime here is a time library. I think the best way to do the schedule part is probably with a for loop. Some pseudo code:

for each value in hour array
  if current hour = current hour in array
    if current minute > start minute && current minute < end minute
      turn on relay
      set timestamp
    else
      turn off relay
      set timestamp
      subtract start from end and get the amount of time it was on

This assumes you are starting and stopping the same minute for each hour.

Edit:
Just saw you have an RTC attached. You can use that for time.

Ok, so this makes a bit more sense to me after thinking about it. Start with the largest unit of measure first and work your way down and then add in break statements so you’re not continuing to check when you don’t need to. I didn’t test this so might need some tweaks. Might need to add some additional logic to the else statements now that I think about it.

for (int i = 0; i < sizeof(OnMonth1); i++){
	if (CurrentMonth == OnMonth1[i]){
		for (int j = 0; j < sizeof(OnDay1); j++){
			if (CurrentDay == OnDay1[j]){
				for (int k = 0; k < sizeof(OnHour1); k++){
					if (CurrentHour == OnHour1[k]){
						for (int l = 0; l < sizeof(OnMin1) / sizeof(OnMin1[0]); l++){
							if (CurrentMin == OnMin1[l]){
								//do your relay on stuff here
								//save start timestamp to variable
								break;
							}
							else{
								//do your relay off stuff here
								//save stop timestamp to variable and subtract start from stop to get total on time
							}
						}
						break;
					}
					else{
						//do your relay off stuff here
						//save stop timestamp to variable and subtract start from stop to get total on time
					}
				}
				break;
			}
			else{
				//do your relay off stuff here
				//save stop timestamp to variable and subtract start from stop to get total on time
			}
		}
		break;
	}
	else{
		//do your relay off stuff here
		//save stop timestamp to variable and subtract start from stop to get total on time
	}
}

I am trying to use your code in hopes of being able to call different times in the day to turn these relays on. Few errors in the code Also can you explain timestamp to variable
delay(500);//Relay 0
// put your main code here, to run repeatedly:
for (int i = 0; i < sizeof(OnMonth1); i++) {
if (now.month == OnMonth1) {
for (int i = 0; i < sizeof(OnDay1); i++) {
if (now.day == OnDay1) {
for (int i = 0; i < sizeof(OnHour1); i++) {
if (now.hour == OnHour1) {
for (int l = 0; i < sizeof(OnMin1) / sizeof(OnMin1[0]); i++) {
if (now.minute == OnMin1) {
mcp.digitalWrite(0, LOW);
display1.setTextSize(2);
display1.setTextColor(WHITE);
display1.setCursor(0, 48);
display1.println(“ON”);
display1.display();
Serial.print(“RELAY 1 ON”);
//save start timestamp to variable
break;
}
else {
mcp.digitalWrite(0, HIGH);
display1.setTextSize(2);
display1.setTextColor(WHITE);
display1.setCursor(0, 48);
display1.println(“OFF”);
display1.display();
Serial.print(“RELAY 1 OFF”);
}//do your relay off stuff here
//save stop timestamp to variable and subtract start from stop to get total on time
}
}
break;
}

Yeah, I didn’t test the code other than just looking at it so probably are things that need fixed. What are the errors you are getting? The timestamp variable is just a timestamp taken from your RTC.

This is the workable code. I have been testing it and the timer works. Like I said I want to know when those relays come on. So then I can set up some triggers to text me``#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include “Adafruit_MCP23017.h”
#include <SPI.h>
#include <DHT.h>
#include <DHT_U.h>
#include <Wire.h>
#include “RTClib.h”
#include “DHT.h”
#define DHTPIN 2 // what digital pin we’re connected to
#define DHTTYPE DHT11 // DHT 22 (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);
#define OLED_RESET 0
Adafruit_MCP23017 mcp;
Adafruit_SSD1306 display1(OLED_RESET);
Adafruit_SSD1306 display2(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error(“Height incorrect, please fix Adafruit_SSD1306.h!”);
#endif
/-----( Import needed libraries for RTC )-----/
/-----( Declare Constants and Pin Numbers )-----/
// Not needed: RTC Lib expects connections as above

/-----( Declare objects )-----/
RTC_DS1307 rtc; // Create a RealTimeClock object
int OnMin1;
int OnHour1;
int OnDay1;
int OnMonth1;
//int OnYear1 // = {2018.2019};

int OffMin1;
int OffHour1;
int OffDay1;
int OffMonth1;
//int OffYear1 // = {2018, 2019,};

int OnMin2;
int OnHour2; //= {17,18,19,20};//Array multi hour
int OnDay2;
int OnMonth2;
//int //OnYear2 = {2018.2019};

int OffMin2;
int OffHour2;
int OffDay2;
int OffMonth2;
//int OffYear2 = {2018, 2019,};

int OnMin3;
int OnHour3; //= {17,18,19,20};//Array multi hour
int OnDay3;
int OnMonth3;
//int //OnYear3 = {2018.2019};

int OffMin3;
int OffHour3;
int OffDay3;
int OffMonth3;
//int OffYear3 = {2018, 2019,};

/-----( Declare Variables )-----/
// NONE because the library handles this…

void setup() /****** SETUP: RUNS ONCE ******/
{
mcp.begin(); 0x20; // use default address 0
Serial.begin(9600);
display1.begin(SSD1306_SWITCHCAPVCC, 0x3D);// initialize with the I2C addr 0x3C (for the 128x64)
display2.begin(SSD1306_SWITCHCAPVCC, 0x3C);
dht.begin();
display1.display();
display2.display();
delay(2000);
Wire.begin();
rtc.begin(); // Start the RTC library code
mcp.pinMode(0, OUTPUT);
mcp.pinMode(1, OUTPUT);
mcp.pinMode(2, OUTPUT);
mcp.pinMode(3, OUTPUT);
mcp.digitalWrite(0, HIGH);
mcp.digitalWrite(1, HIGH);
mcp.digitalWrite(2, HIGH);
mcp.digitalWrite(3, HIGH);

/----( SET the date and time. Comment OUT these lines after setting )----/
// Put these “//” in front of the line you do NOT want to use
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(DATE), F(TIME)));
// This line sets the RTC with an explicit date & time, for example to set
// May 21, 2015 at 6pm you would call: (use 24 hour time)
//rtc.adjust(DateTime(2018, 1, 2, 15, 17, 0));

}//–(end setup )—

void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
DateTime now = rtc.now(); // Read data from the RTC Chip

display1.clearDisplay();
// text display tests
display1.setTextSize(2);
display1.setTextColor(WHITE);
display1.setCursor(0, 0);
display1.print(now.year(), DEC); //
display1.print(‘.’);
display1.print(now.month(), DEC);
display1.print(‘.’);
display1.print(now.day(), DEC);
//display1.print(‘*’);
display1.setTextSize(2);
display1.setTextColor(WHITE);
display1.setCursor(10, 16);
display1.print(now.hour(), DEC);
display1.print(‘:’);
display1.print(now.minute(), DEC);
display1.print(‘:’);
display1.print(now.second(), DEC);
display1.println();
display1.setTextSize(2);
display1.setTextColor(WHITE);
display1.setCursor(0, 32);
display1.println(“Z1- Z2- Z3”);
display1.display();
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds ‘old’ (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);

// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(“Failed to read from DHT sensor!”);
return;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, h);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(t, h, false);
display2.clearDisplay();
// text display tests
display2.setTextSize(2);
display2.setTextColor(WHITE);
display2.setCursor(0, 0);
display2.print(“Humi “);
display2.print(h);
//display2.print(”%”);
display2.setTextSize(2);
display2.setTextColor(WHITE);
display2.setCursor(0, 16);
display2.print("Temp ");
display2.print(f);
display2.print(“F”);
display2.setTextSize(2);
display2.setTextColor(WHITE);
display2.setCursor(0, 32);
display2.print(“Heat Index”);
display2.setTextSize(2);
display2.setTextColor(WHITE);
display2.setCursor(36, 48);
display2.print(hif);
display2.println(“F”);
display2.display();
//Serial.print(“Humidity: “);
//Serial.print(h);
//Serial.print(” %\t”);
//Serial.print(“Temperature: “);
//Serial.print(t);
//Serial.print(” *C “);
//Serial.print(f);
//Serial.print(” *F\t”);
//Serial.print(“Heat index: “);
//Serial.print(hic);
//Serial.print(” *C “);
//Serial.print(hif);
//Serial.println(” *F”);
delay(500);

//Serial.print(now.year(), DEC); //
//Serial.print(‘-’);
//Serial.print(now.month(), DEC);
//Serial.print(‘-’);
//Serial.print(now.day(), DEC);
//Serial.print(’ ‘);
//Serial.print(now.hour(), DEC);
//Serial.print(’:‘);
//Serial.print(now.minute(), DEC);
//Serial.print(’:');
//Serial.print(now.second(), DEC);
//Serial.println();

int OnMin1 = {20, 21, 22, 23, 24};
int OnHour1 = {21}; //= {2, 4, 8, 3, 6}; //= {17,18,19,20};//Array multi hour
int OnDay1 = {01}; //OnHour1 = 3; //= {17,18,19,20};//Array multi hour
int OnMonth1 = {2};
//int OnYear1 // = {2018.2019};

int OffMin1 = {25};
int OffHour1 = {21};
int OffDay1 = {1, 2};
int OffMonth1 = {2};
//int OffYear1 // = {2018, 2019,};

delay(500);//Relay 0
for (int i = 0; i < sizeof(OnHour1) / sizeof(OnHour1[0]); i++)
for (int j = 0; j < sizeof(OnMin1) / sizeof(OnMin1[0]); j++)
for (int k = 0; k < sizeof(OnDay1) / sizeof(OnDay1[0]); k++)
for (int l = 0; l < sizeof(OnMonth1) / sizeof(OnMonth1[0]); l++) //This will turn one relay on and off

      if ((now.hour() == OnHour1[i]) && (now.minute() == OnMin1[j]) && (now.day() == OnDay1[k]) && (now.month() == OnMonth1[l])) {
        mcp.digitalWrite(0, LOW);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(0, 48);
        display1.println("ON");
        display1.display();
        Serial.print("RELAY 1 ON");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }

      else if ((now.hour() == OffHour1[i]) && (now.minute() == OffMin1[j]) && (now.day() == OffDay1[k]) && (now.month() == OffMonth1[l])) {
        mcp.digitalWrite(0, HIGH);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(0, 48);
        display1.println("OFF");
        display1.display();
        Serial.print("RELAY 1 OFF");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }

int OnMin2 = {30, 31};
int OnHour2 = {21}; //= {2, 4, 8, 3, 6}; //= {17,18,19,20};//Array multi hour
int OnDay2 = {1, 2}; //OnHour1 = 3; //= {17,18,19,20};//Array multi hour
int OnMonth2 = {2};
//int OnYear2 // = {2018.2019};

int OffMin2 = {32};
int OffHour2 = {21};
int OffDay2 = {1, 2};
int OffMonth2 = {2};
//int OffYear2 // = {2018, 2019,};

// Relay 1
for (int i = 0; i < sizeof(OnHour2) / sizeof(OnHour2[0]); i++)
for (int j = 0; j < sizeof(OnMin2) / sizeof(OnMin2[0]); j++)
for (int k = 0; k < sizeof(OnDay2) / sizeof(OnDay2[0]); k++)
for (int l = 0; l < sizeof(OnMonth2) / sizeof(OnMonth2[0]); l++) //This will turn one relay on and off

      if ((now.hour() == OnHour2[i]) && (now.minute() == OnMin2[j]) && (now.day() == OnDay2[k]) && (now.month() == OnMonth2[l])) {
        mcp.digitalWrite(1, LOW);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(50, 48);
        display1.println("ON");
        display1.display();
        Serial.print("RELAY 2 ON");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }
      else if ((now.hour() == OffHour2[i]) && (now.minute() == OffMin2[j]) && (now.day() == OffDay2[k]) && (now.month() == OffMonth2[l])) {
        mcp.digitalWrite(1, HIGH);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(50, 48);
        display1.println("OFF");
        display1.display();
        Serial.print("RELAY 2 OFF");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }

int OnMin3 = {47, 48};
int OnHour3 = {21}; //= {2, 4, 8, 3, 6}; //= {17,18,19,20};//Array multi hour
int OnDay3 = {1, 2}; //OnHour1 = 3; //= {17,18,19,20};//Array multi hour
int OnMonth3 = {2};
//int OnYear3 // = {2018.2019};

int OffMin3 = {50};
int OffHour3 = {21};
int OffDay3 = {1, 2};
int OffMonth3 = {2};
//int OffYear3 // = {2018, 2019,};

for (int i = 0; i < sizeof(OnHour3) / sizeof(OnHour3[0]); i++)
for (int j = 0; j < sizeof(OnMin3) / sizeof(OnMin3[0]); j++)
for (int k = 0; k < sizeof(OnDay3) / sizeof(OnDay3[0]); k++)
for (int l = 0; l < sizeof(OnMonth3) / sizeof(OnMonth3[0]); l++) //This will turn one relay on and off

      if ((now.hour() == OnHour3[i]) && (now.minute() == OnMin3[j]) && (now.day() == OnDay3[k]) && (now.month() == OnMonth3[l])) {
        mcp.digitalWrite(2, LOW);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(50, 48);
        display1.println("ON");
        display1.display();
        Serial.print("RELAY 3 ON");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }
      else if ((now.hour() == OffHour3[i]) && (now.minute() == OffMin3[j]) && (now.day() == OffDay3[k]) && (now.month() == OffMonth3[l])) {
        mcp.digitalWrite(2, HIGH);
        display1.setTextSize(1);
        display1.setTextColor(WHITE);
        display1.setCursor(100, 48);
        display1.println("OFF");
        display1.display();
        Serial.print("RELAY 3 OFF");
        Serial.print(now.month(), DEC);
        Serial.print('-');
        Serial.print(now.day(), DEC);
        Serial.print('  ');
        Serial.print(now.hour(), DEC);
        Serial.print(':');
        Serial.print(now.minute(), DEC);
        Serial.print(':');
        Serial.print(now.second(), DEC);
        Serial.println();
      }

}

//–(end main loop )—

/-----( Declare User-written Functions )-----/
//NONE

//( THE END )**

`

use "Cayenne.virtualWrite(1, 1, “digital_sensor”, “d”); " in your code to turn a two state widget on when the relay is on.
then you can set the trigger to this widget (but right now triggers have some bug and wont work).

Can you feed a sample of the output of the relay back to an input of the device to monitor it that way? You would have a no fail status indication. Then add triggers as shramiksalgaonkar suggested or graph it.