Inconsistent Relay Behaviour

Hey All,

Thanks to all of you on here who are able to take the time to help me out. I am running into an issue where random relays trigger on at start up. I’m almost certain the issue is code based as this was never an issue a few versions ago. Any ideas?

// ---------------------------Blynk Definitions--------------=--------------- //
// ========================================================================== //
#define BLYNK_PRINT Serial
// Template ID, Device Name and Auth Token are provided by the Blynk.Cloud
// See the Device Info tab, or Template settings
#define BLYNK_TEMPLATE_ID "TMPL6ZVLd7iQ"
#define BLYNK_DEVICE_NAME "Ceiling Prototype 02"
#define BLYNK_AUTH_TOKEN "wR-atNg26VP6gOIKTjL0He1rBTOmOJPN"

// Comment this out to disable prints and save space
//#define BLYNK_PRINT Serial

// -----------------------Include Network Libraries-------------------------- //
// ========================================================================== //
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

// ----------------------Network Security Credentials------------------------- //
// ========================================================================== //
char auth[] = BLYNK_AUTH_TOKEN;

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Maple People";
char pass[] = "maplepeople";


// ----------------------Include BME680 Library/Defs------------------------- //
// ========================================================================== //
#include "bsec.h"

// Helper functions declarations
void checkIaqSensorStatus(void);
void errLeds(void);

// Create an object of the class Bsec
Bsec iaqSensor;

String output;

// ----------------------Include Usage Libraries/Defs------------------------ //
// ========================================================================== //
#include "EmonLib.h" 

EnergyMonitor emon;
#define vCalibration 114
#define currCalibration 19

float kWh = 0;
unsigned long lastmillis = millis();




// -----------------------Include RGBW Libraries/Defs------------------------ //
// ========================================================================== //

#include <Adafruit_NeoPixel.h>

#define LED_PIN 12
#define LED_COUNT 260

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

// Variables to store the values from the sliders
int redValue, greenValue, blueValue, whiteBrightness, warmCool;

// ----------------------------Pin Definitions------------------------------- //
// ========================================================================== //
#include <Adafruit_MCP23X17.h>
#include <Wire.h>
const uint8_t I2C_ADDRESS = 0x08;

Adafruit_MCP23X17 mcp;


// Define component pins
const int MainLight = 14;
#define SmokeSense 13
#define PIR 35
#define DoorLock 15
#define AirFresh1 5
#define AirFresh2 1
#define H_Coil 14
#define Pump 2
#define Fan_L 3
#define Fan_H 13
#define Comp 12 
#define MaintL 4
#define MaintR 11


bool heatState = false;
bool coolState = false;
bool fanState = false;
bool dehumidState = false;
int automaticTempMode = 0;
int automaticHumMode = 0;

int temperatureSetpoint = 19;
int humiditySetpoint = 40;


int Brightness = 0;  // how bright the LED is

// setting PWM properties
const int freq = 5000;
const int LEDC_CHANNEL = 0;
const int resolution = 8;

// Create a variable to track the state of the LED
bool ledState = false;

// Create a variable to track the time when motion was last detected
unsigned long lastMotionTime = 0;


// Set the interval at which the LED should turn off if no motion is detected (in milliseconds)
const unsigned long LED_OFF_INTERVAL = 30 * 60 * 1000; // 3 minutes



  BlynkTimer timer;



void controlTemperature() {
  if (automaticTempMode == 1) {

      float currentTemperature = iaqSensor.temperature;

      if (currentTemperature < temperatureSetpoint - 0) {
        mcp.digitalWrite(H_Coil, LOW);
        mcp.digitalWrite(Fan_H, LOW);
        mcp.digitalWrite(Comp, HIGH);
      } else if (currentTemperature > temperatureSetpoint + 0) {
        mcp.digitalWrite(H_Coil, HIGH);
        mcp.digitalWrite(Fan_H, LOW);
        mcp.digitalWrite(Comp, LOW);
      } else {
    }
  }
}

void controlHumidity() {
  if (automaticHumMode == 1) {
      float currentHumidity = iaqSensor.humidity;

      if (currentHumidity < humiditySetpoint - 0) {
        mcp.digitalWrite(Pump, LOW);
        mcp.digitalWrite(Comp, LOW);
        mcp.digitalWrite(Fan_H, LOW);
      } else if (currentHumidity > humiditySetpoint + 0) {
        mcp.digitalWrite(Pump, HIGH);
        mcp.digitalWrite(Comp, HIGH);
        mcp.digitalWrite(Fan_H, HIGH);
      } else {

    }
  }
}

void sendSensor()
{
  unsigned long time_trigger = millis();
  if (iaqSensor.run()) // If new data is available
  {
    
    output = String(time_trigger);
    output += ", " + String(iaqSensor.rawTemperature);
    output += ", " + String(iaqSensor.pressure);
    output += ", " + String(iaqSensor.rawHumidity);
    output += ", " + String(iaqSensor.gasResistance);
    output += ", " + String(iaqSensor.iaq);
    output += ", " + String(iaqSensor.iaqAccuracy);
    output += ", " + String(iaqSensor.temperature);
    output += ", " + String(iaqSensor.humidity);
    output += ", " + String(iaqSensor.staticIaq);
    output += ", " + String(iaqSensor.co2Equivalent);
    output += ", " + String(iaqSensor.breathVocEquivalent);

    Blynk.virtualWrite(V11, iaqSensor.pressure);      // For Pressure
    Blynk.virtualWrite(V12, iaqSensor.temperature);            // For Temperature
    Blynk.virtualWrite(V13, iaqSensor.humidity);               // For Humidity
    Blynk.virtualWrite(V14, iaqSensor.staticIaq);               //For Static Index of Air Quality
    Blynk.virtualWrite(V15, iaqSensor.co2Equivalent);          // For CO2
    Blynk.virtualWrite(V16, iaqSensor.breathVocEquivalent); 

    Serial.print("Temperature: ");
    Serial.println(iaqSensor.temperature);
    Serial.print("Humidity: ");
    Serial.println(iaqSensor.humidity);
    Serial.println("");
    Serial.println("automaticTempMode:");
    Serial.print(automaticTempMode);
    Serial.println("");
    Serial.println("automaticHumMode:");
    Serial.print(automaticHumMode);
    Serial.println("");
    Serial.print("Target temp: ");
    Serial.println(temperatureSetpoint);
    Serial.print("Target humid: ");
    Serial.println(humiditySetpoint);
    Serial.println("");

  }
  else
  {
    // checkIaqSensorStatus();
  }

}


void setup() {

  // Initialize MCP23XXX with I2C address 0x27
  if (!mcp.begin_I2C(0x27)) {
    Serial.println("Error.");
    while (1);
  }

  ledcSetup(LEDC_CHANNEL, freq, resolution);

  // attach the channel to the GPIO to be controlled
  ledcAttachPin(MainLight, LEDC_CHANNEL);

  strip.setPixelColor(0, 0, 0, 0, 0);
  strip.show();
  Serial.begin(115200);


  delay(5000);


  mcp.pinMode(DoorLock, OUTPUT);
  mcp.pinMode(AirFresh1, OUTPUT);
  mcp.pinMode(AirFresh2, OUTPUT);
  mcp.pinMode(H_Coil, OUTPUT);
  mcp.pinMode(Pump, OUTPUT);
  mcp.pinMode(Fan_H, OUTPUT);
  mcp.pinMode(Comp, OUTPUT);
  mcp.pinMode(MaintL, OUTPUT);
  mcp.pinMode(MaintR, OUTPUT);
  pinMode(PIR, INPUT);

  mcp.digitalWrite(DoorLock, HIGH);
  mcp.digitalWrite(AirFresh1, HIGH);
  mcp.digitalWrite(AirFresh2, HIGH);
  mcp.digitalWrite(H_Coil, HIGH);
  mcp.digitalWrite(Pump, HIGH);
  mcp.digitalWrite(Fan_H, HIGH);
  mcp.digitalWrite(Comp, HIGH);
  mcp.digitalWrite(MaintL, HIGH);
  mcp.digitalWrite(MaintR, HIGH);




  emon.voltage(33, vCalibration, 1.7); // Voltage: input pin, calibration, phase_shift
  emon.current(32, currCalibration); // Current: input pin, calibration.


  delay(500);


  timer.setInterval(1000L, sendSensor);

  timer.setInterval(900L, PIRLED);
  timer.setInterval(3000L, sendEnergymon);
  timer.setInterval(4000L, controlTemperature);
  timer.setInterval(4000L, controlHumidity);


  

  Blynk.begin(auth, ssid, pass, "blynk.cloud", 8080);

  delay(500);
  Wire.begin();
  delay(3500);


  iaqSensor.begin(0X77, Wire);
  output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
  Serial.println(output);
  checkIaqSensorStatus();

  bsec_virtual_sensor_t sensorList[10] = {
    BSEC_OUTPUT_RAW_TEMPERATURE,
    BSEC_OUTPUT_RAW_PRESSURE,
    BSEC_OUTPUT_RAW_HUMIDITY,
    BSEC_OUTPUT_RAW_GAS,
    BSEC_OUTPUT_IAQ,
    BSEC_OUTPUT_STATIC_IAQ,
    BSEC_OUTPUT_CO2_EQUIVALENT,
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
  };

  iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
  checkIaqSensorStatus();

       

  for (int i = 0; i < LED_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(230, 0, 100, 75)); // Start up colour
    strip.show();
    delay(30);

    
  }

  for (int i = 0; i < 3; i++) {
    ledcWrite(LEDC_CHANNEL, 255);
    for (int j = 255; j > 0; j--) {
      ledcWrite(LEDC_CHANNEL, j);
      delay(10);
    }
    ledcWrite(LEDC_CHANNEL, 0);
    for (int j = 0; j < 255; j++) {
      ledcWrite(LEDC_CHANNEL, j);
      delay(10);
      ledcWrite(LEDC_CHANNEL, 255);
    }
  }
 for (int i = 0; i < LED_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0, 0)); 
    strip.show();
    delay(1);
  }
}

//Get buttons values


// Blynk virtual pin for LED on/off
BLYNK_WRITE(V1)
{
  bool buttonState = param.asInt();
  if (buttonState == 1) {
    // Fade the LED on to the brightness slider value.
    for (int i = ledcRead(LEDC_CHANNEL); i <= Brightness; i++) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(4);
    }
    ledState = true;
  } else {
    // Fade the LED off.
    for (int i = ledcRead(LEDC_CHANNEL); i >= 0; i--) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(4);
    }
    ledState = false;
    //Blynk.setProperty(V0, "readonly", "true");
  }
}
//Get buttons values
BLYNK_WRITE(V2) {
  bool RelayOne = param.asInt();
  if (RelayOne == 1) {
    mcp.digitalWrite(DoorLock, LOW);
  } else {
    mcp.digitalWrite(DoorLock, HIGH);
  }
}

//Get buttons values
BLYNK_WRITE(V3) {
  bool RelayTwo = param.asInt();
  if (RelayTwo == 1) {
    delay(1000);
    mcp.digitalWrite(AirFresh1, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh1, HIGH);
    delay(1000);
    mcp.digitalWrite(AirFresh1, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh1, HIGH);
  }
}

//Get buttons values
BLYNK_WRITE(V22) {
  bool RelayThree = param.asInt();
  if (RelayThree == 1) {
    delay(1000);
    mcp.digitalWrite(AirFresh2, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh2, HIGH);
    delay(1000);
    mcp.digitalWrite(AirFresh2, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh2, HIGH);
  }
}

BLYNK_WRITE(V4) {
  // When Heat button is pressed, turn on H-Coil and Fan_H relays
  if (param.asInt() == 1) {
    heatState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(H_Coil, LOW);
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When Heat button is released, turn off H-Coil and Fan_H relays
  else {
    heatState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(H_Coil, HIGH);
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}

BLYNK_WRITE(V6) {
  // When Cool button is pressed, turn on Fan_H and Comp relays
  if (param.asInt() == 1) {
    coolState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, LOW);
      mcp.digitalWrite(Comp, LOW);
    }
  }
  // When Cool button is released, turn off Fan_H and Comp relays
  else {
    coolState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, HIGH);
      mcp.digitalWrite(Comp, HIGH);
    }
  }
}

BLYNK_WRITE(V7) {
  // When Fan button is pressed, turn on Fan_H relay
  if (param.asInt() == 1) {
    fanState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When Fan button is released, turn off Fan_H relay
  else {
    fanState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}

BLYNK_WRITE(V8) {
  // When DeHumid button is pressed, turn on Pump, Comp, and Fan_H relays
  if (param.asInt() == 1) {
    dehumidState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Pump, LOW);
      mcp.digitalWrite(Comp, LOW);
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When DeHumid button is released, turn off Pump, Comp, and Fan_H relays
  else {
    dehumidState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Pump, HIGH);
      mcp.digitalWrite(Comp, HIGH);
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}


BLYNK_WRITE(V50) {
  // When Automatic Temp button is pressed, set automaticTempMode to 1 and turn off all relays
  if (param.asInt() == 1) {
    automaticTempMode = 1;
  }
  // When Automatic Temp button is released, set automaticTempMode to 0
  else {
    automaticTempMode = 0;
    mcp.digitalWrite(H_Coil, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Comp, HIGH);
  }
}

BLYNK_WRITE(V51) {
  // When Automatic Humidity button is pressed, set automaticHumMode to 1 and turn off all relays
  if (param.asInt() == 1) {
    automaticHumMode = 1;
  }
  // When Automatic Humidity button is released, set automaticHumMode to 0
  else {
    automaticHumMode = 0;
    mcp.digitalWrite(Pump, HIGH);
    mcp.digitalWrite(Comp, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
  }
}


BLYNK_WRITE(V23) {
  temperatureSetpoint = param.asInt();
}

BLYNK_WRITE(V5) {
  humiditySetpoint = param.asInt();
}

//Get buttons values
BLYNK_WRITE(V9) {
  bool RelayFive = param.asInt();
  if (RelayFive == 1) {
    mcp.digitalWrite(MaintL, LOW);
    delay(15000); 
  } else {
    mcp.digitalWrite(MaintL, HIGH);
       
  }
}

//Get buttons values
BLYNK_WRITE(V10) {
  bool RelaySix = param.asInt();
  if (RelaySix == 1) {
    mcp.digitalWrite(MaintR, LOW);
        delay(21500);
  } else {
    mcp.digitalWrite(MaintR, HIGH);

  }
}


BLYNK_WRITE(V25) {
  bool ALLOFF = param.asInt();
  if (ALLOFF == 1) {
    mcp.digitalWrite(H_Coil, HIGH);
    ledcWrite(LEDC_CHANNEL, 0);
    delay(500); 
    mcp.digitalWrite(H_Coil, LOW);
    ledcWrite(LEDC_CHANNEL, 0);
  }
}



BLYNK_WRITE(V0) //Slider - Manually adjust volume
{
  if (ledState) {
    Brightness = param.asInt();
    ledcWrite(LEDC_CHANNEL, Brightness);
  }
}
// Virtual pin for red control
BLYNK_WRITE(V34) {
    redValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for green control
BLYNK_WRITE(V35) {
    greenValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for blue control
BLYNK_WRITE(V36) {
    blueValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for white brightness control
BLYNK_WRITE(V37) {
    whiteBrightness = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for warm/cool transition control
BLYNK_WRITE(V38) {
    warmCool = param[0].asInt();
    int r = redValue, g = greenValue, b = blueValue;
    for(int i=0; i< strip.numPixels(); i++){
        // Adjust color temperature
        r = (255 - redValue) * warmCool / 100 + redValue;
        g = (255 - greenValue) * warmCool / 100 + greenValue;
        b = (255 - blueValue) * warmCool / 100 + blueValue;
        strip.setPixelColor(i, r, g, b, whiteBrightness);
    }
    strip.show();
}

void loop() {
  Blynk.run();//Run the Blynk library
  timer.run();//Run the Blynk timer
  
}


void PIRLED() {
  // Check if motion was detected
  int pirValue = digitalRead(PIR);
  Serial.println("Pir Value: " + String(pirValue));
  static bool ledState = false;
  static unsigned long lastMotionTime = 0;

  if (pirValue == HIGH) { // Motion was detected

    if (!ledState) {
      // LED is off, fade it in
      for (int i = 0; i <= 255; i++) {
        ledcWrite(LEDC_CHANNEL, i);
        delay(1);
      }
    } else {
      // LED is already on, keep it on
      ledcWrite(LEDC_CHANNEL, 255);
    }
    ledState = true;
    Blynk.virtualWrite(V1, HIGH); // update the Blynk switch
    // Update the last motion time
    lastMotionTime = millis();
  } else if (ledState && millis() - lastMotionTime > LED_OFF_INTERVAL) {
    // No motion was detected, and the LED is on, but it has been more than the LED_OFF_INTERVAL
    // since the last motion was detected, so fade the LED off
    for (int i = 255; i >= 0; i--) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(1);
      
    }
    ledState = false;
    Blynk.virtualWrite(V1, LOW); // update the Blynk switch
    Blynk.setProperty(V0, "readonly", "false");
  }
}





void sendEnergymon() {
    emon.calcVI(20, 2000);

    Blynk.virtualWrite(V30, emon.Vrms);

    Blynk.virtualWrite(V31, emon.Irms);

    Blynk.virtualWrite(V32, emon.apparentPower);
    Serial.print("\tkWh: ");
    kWh = kWh + emon.apparentPower*(millis()-lastmillis)/3600000000.0;
    Serial.print(kWh, 4);
    Serial.println("kWh");
    lastmillis = millis();
    Blynk.virtualWrite(V33, kWh);
}


// Helper function definitions
void checkIaqSensorStatus(void)
{
  if (iaqSensor.status != BSEC_OK)
  {
    if (iaqSensor.status < BSEC_OK)
    {
      output = "BSEC error code : " + String(iaqSensor.status);
      Serial.println(output);
      for (;;)
        errLeds();
    }
    else
    {
      output = "BSEC warning code : " + String(iaqSensor.status);
      Serial.println(output);
    }
  }

  if (iaqSensor.bme680Status != BME680_OK)
  {
    if (iaqSensor.bme680Status < BME680_OK)
    {
      output = "BME680 error code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
      for (;;)
        errLeds();
    }
    else
    {
      output = "BME680 warning code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
    }
  }
}

void errLeds(void)
{
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(100);
  digitalWrite(2, LOW);
  delay(100);
}

Some clues about which pin the relay is attached to, and whether it’s active HIGH or LOW would help.

You also have an issue in your void setup where you’re attempting to do serial prints before you’ve initialised your serial port.

Do you have any digital datastreams set-up?

What type of widgets do you have attached to whichever datastream is controlling this relay?

Pete.

Hi Peter,

I have quickly fixed the code so that the serial port is initialised first within void setup. My relay board is Active LOW. I don’t have any digital data streams, only virtual. The most odd thing is that sometimes on startup, everything is fine but after 5 min random relays activate.

// ---------------------------Blynk Definitions--------------=--------------- //
// ========================================================================== //
#define BLYNK_PRINT Serial
// Template ID, Device Name and Auth Token are provided by the Blynk.Cloud
// See the Device Info tab, or Template settings
#define BLYNK_TEMPLATE_ID "TMPL6ZVLd7iQ"
#define BLYNK_DEVICE_NAME "Ceiling Prototype 02"
#define BLYNK_AUTH_TOKEN "wR-atNg26VP6gOIKTjL0He1rBTOmOJPN"

// Comment this out to disable prints and save space
//#define BLYNK_PRINT Serial

// -----------------------Include Network Libraries-------------------------- //
// ========================================================================== //
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

// ----------------------Network Security Credentials------------------------- //
// ========================================================================== //
char auth[] = BLYNK_AUTH_TOKEN;

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Maple People";
char pass[] = "maplepeople";


// ----------------------Include BME680 Library/Defs------------------------- //
// ========================================================================== //
#include "bsec.h"

// Helper functions declarations
void checkIaqSensorStatus(void);
void errLeds(void);

// Create an object of the class Bsec
Bsec iaqSensor;

String output;

// ----------------------Include Usage Libraries/Defs------------------------ //
// ========================================================================== //
#include "EmonLib.h" 

EnergyMonitor emon;
#define vCalibration 114
#define currCalibration 19

float kWh = 0;
unsigned long lastmillis = millis();




// -----------------------Include RGBW Libraries/Defs------------------------ //
// ========================================================================== //

#include <Adafruit_NeoPixel.h>

#define LED_PIN 12
#define LED_COUNT 260

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);

// Variables to store the values from the sliders
int redValue, greenValue, blueValue, whiteBrightness, warmCool;

// ----------------------------Pin Definitions------------------------------- //
// ========================================================================== //
#include <Adafruit_MCP23X17.h>
#include <Wire.h>
//const uint8_t I2C_ADDRESS = 0x08;

Adafruit_MCP23X17 mcp;


// Define component pins
const int MainLight = 14;
#define SmokeSense 13
#define PIR 35
#define DoorLock 15
#define AirFresh1 5
#define AirFresh2 1
#define H_Coil 14
#define Pump 2
#define Fan_L 3
#define Fan_H 13
#define Comp 12 
#define MaintL 4
#define MaintR 11


bool heatState = false;
bool coolState = false;
bool fanState = false;
bool dehumidState = false;
int automaticTempMode = 0;
int automaticHumMode = 0;

int temperatureSetpoint = 19;
int humiditySetpoint = 40;


int Brightness = 0;  // how bright the LED is

// setting PWM properties
const int freq = 5000;
const int LEDC_CHANNEL = 0;
const int resolution = 8;

// Create a variable to track the state of the LED
bool ledState = false;

// Create a variable to track the time when motion was last detected
unsigned long lastMotionTime = 0;


// Set the interval at which the LED should turn off if no motion is detected (in milliseconds)
const unsigned long LED_OFF_INTERVAL = 30 * 60 * 1000; // 3 minutes



BlynkTimer timer;

void setup() {
  Serial.begin(115200);
  // Initialize MCP23XXX with I2C address 0x27
  if (!mcp.begin_I2C(0x27)) {
    Serial.println("Error.");
    while (1);
  }
 
  delay(500);
  
  mcp.pinMode(DoorLock, OUTPUT);
  mcp.pinMode(AirFresh1, OUTPUT);
  mcp.pinMode(AirFresh2, OUTPUT);
  mcp.pinMode(H_Coil, OUTPUT);
  mcp.pinMode(Pump, OUTPUT);
  mcp.pinMode(Fan_H, OUTPUT);
  mcp.pinMode(Comp, OUTPUT);
  mcp.pinMode(MaintL, OUTPUT);
  mcp.pinMode(MaintR, OUTPUT);
  pinMode(PIR, INPUT);

  mcp.digitalWrite(DoorLock, HIGH);
  mcp.digitalWrite(AirFresh1, HIGH);
  mcp.digitalWrite(AirFresh2, HIGH);
  mcp.digitalWrite(H_Coil, HIGH);
  mcp.digitalWrite(Pump, HIGH);
  mcp.digitalWrite(Fan_H, HIGH);
  mcp.digitalWrite(Comp, HIGH);
  mcp.digitalWrite(MaintL, HIGH);
  mcp.digitalWrite(MaintR, HIGH);

  ledcSetup(LEDC_CHANNEL, freq, resolution);

  // attach the channel to the GPIO to be controlled
  ledcAttachPin(MainLight, LEDC_CHANNEL);

  strip.setPixelColor(0, 0, 0, 0, 0);
  strip.show();



  delay(5000);






  emon.voltage(33, vCalibration, 1.7); // Voltage: input pin, calibration, phase_shift
  emon.current(32, currCalibration); // Current: input pin, calibration.


  delay(500);


  timer.setInterval(1000L, sendSensor);

  timer.setInterval(900L, PIRLED);
  timer.setInterval(3000L, sendEnergymon);
  timer.setInterval(4000L, controlTemperature);
  timer.setInterval(4000L, controlHumidity);


  

  Blynk.begin(auth, ssid, pass, "blynk.cloud", 8080);

  delay(500);
  Wire.begin();
  delay(3500);


  iaqSensor.begin(0X77, Wire);
  output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
  Serial.println(output);
  checkIaqSensorStatus();

  bsec_virtual_sensor_t sensorList[10] = {
    BSEC_OUTPUT_RAW_TEMPERATURE,
    BSEC_OUTPUT_RAW_PRESSURE,
    BSEC_OUTPUT_RAW_HUMIDITY,
    BSEC_OUTPUT_RAW_GAS,
    BSEC_OUTPUT_IAQ,
    BSEC_OUTPUT_STATIC_IAQ,
    BSEC_OUTPUT_CO2_EQUIVALENT,
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
  };

  iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
  checkIaqSensorStatus();

       

  for (int i = 0; i < LED_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(230, 0, 100, 75)); // Start up colour
    strip.show();
    delay(30);

    
  }

  for (int i = 0; i < 3; i++) {
    ledcWrite(LEDC_CHANNEL, 255);
    for (int j = 255; j > 0; j--) {
      ledcWrite(LEDC_CHANNEL, j);
      delay(10);
    }
    ledcWrite(LEDC_CHANNEL, 0);
    for (int j = 0; j < 255; j++) {
      ledcWrite(LEDC_CHANNEL, j);
      delay(10);
      ledcWrite(LEDC_CHANNEL, 255);
    }
  }
 for (int i = 0; i < LED_COUNT; i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0, 0)); 
    strip.show();
    delay(1);
  }
}

//Get buttons values


// Blynk virtual pin for LED on/off
BLYNK_WRITE(V1)
{
  bool buttonState = param.asInt();
  if (buttonState == 1) {
    // Fade the LED on to the brightness slider value.
    for (int i = ledcRead(LEDC_CHANNEL); i <= Brightness; i++) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(4);
    }
    ledState = true;
  } else {
    // Fade the LED off.
    for (int i = ledcRead(LEDC_CHANNEL); i >= 0; i--) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(4);
    }
    ledState = false;
    //Blynk.setProperty(V0, "readonly", "true");
  }
}
//Get buttons values
BLYNK_WRITE(V2) {
  bool RelayOne = param.asInt();
  if (RelayOne == 1) {
    mcp.digitalWrite(DoorLock, LOW);
  } else {
    mcp.digitalWrite(DoorLock, HIGH);
  }
}

//Get buttons values
BLYNK_WRITE(V3) {
  bool RelayTwo = param.asInt();
  if (RelayTwo == 1) {
    delay(1000);
    mcp.digitalWrite(AirFresh1, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh1, HIGH);
    delay(1000);
    mcp.digitalWrite(AirFresh1, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh1, HIGH);
  }
}

//Get buttons values
BLYNK_WRITE(V22) {
  bool RelayThree = param.asInt();
  if (RelayThree == 1) {
    delay(1000);
    mcp.digitalWrite(AirFresh2, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh2, HIGH);
    delay(1000);
    mcp.digitalWrite(AirFresh2, LOW);
    delay(1000);
    mcp.digitalWrite(AirFresh2, HIGH);
  }
}

BLYNK_WRITE(V4) {
  // When Heat button is pressed, turn on H-Coil and Fan_H relays
  if (param.asInt() == 1) {
    heatState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(H_Coil, LOW);
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When Heat button is released, turn off H-Coil and Fan_H relays
  else {
    heatState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(H_Coil, HIGH);
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}

BLYNK_WRITE(V6) {
  // When Cool button is pressed, turn on Fan_H and Comp relays
  if (param.asInt() == 1) {
    coolState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, LOW);
      mcp.digitalWrite(Comp, LOW);
    }
  }
  // When Cool button is released, turn off Fan_H and Comp relays
  else {
    coolState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, HIGH);
      mcp.digitalWrite(Comp, HIGH);
    }
  }
}

BLYNK_WRITE(V7) {
  // When Fan button is pressed, turn on Fan_H relay
  if (param.asInt() == 1) {
    fanState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When Fan button is released, turn off Fan_H relay
  else {
    fanState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}

BLYNK_WRITE(V8) {
  // When DeHumid button is pressed, turn on Pump, Comp, and Fan_H relays
  if (param.asInt() == 1) {
    dehumidState = true;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Pump, LOW);
      mcp.digitalWrite(Comp, LOW);
      mcp.digitalWrite(Fan_H, LOW);
    }
  }
  // When DeHumid button is released, turn off Pump, Comp, and Fan_H relays
  else {
    dehumidState = false;
    if (!automaticHumMode && !automaticTempMode) {
      mcp.digitalWrite(Pump, HIGH);
      mcp.digitalWrite(Comp, HIGH);
      mcp.digitalWrite(Fan_H, HIGH);
    }
  }
}


BLYNK_WRITE(V50) {
  // When Automatic Temp button is pressed, set automaticTempMode to 1 and turn off all relays
  if (param.asInt() == 1) {
    automaticTempMode = 1;
  }
  // When Automatic Temp button is released, set automaticTempMode to 0
  else {
    automaticTempMode = 0;
    mcp.digitalWrite(H_Coil, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Comp, HIGH);
  }
}

BLYNK_WRITE(V51) {
  // When Automatic Humidity button is pressed, set automaticHumMode to 1 and turn off all relays
  if (param.asInt() == 1) {
    automaticHumMode = 1;
  }
  // When Automatic Humidity button is released, set automaticHumMode to 0
  else {
    automaticHumMode = 0;
    mcp.digitalWrite(Pump, HIGH);
    mcp.digitalWrite(Comp, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
    mcp.digitalWrite(Fan_H, HIGH);
  }
}


BLYNK_WRITE(V23) {
  temperatureSetpoint = param.asInt();
}

BLYNK_WRITE(V5) {
  humiditySetpoint = param.asInt();
}

//Get buttons values
BLYNK_WRITE(V9) {
  bool RelayFive = param.asInt();
  if (RelayFive == 1) {
    mcp.digitalWrite(MaintL, LOW);
    delay(15000); 
  } else {
    mcp.digitalWrite(MaintL, HIGH);
       
  }
}

//Get buttons values
BLYNK_WRITE(V10) {
  bool RelaySix = param.asInt();
  if (RelaySix == 1) {
    mcp.digitalWrite(MaintR, LOW);
        delay(21500);
  } else {
    mcp.digitalWrite(MaintR, HIGH);

  }
}


BLYNK_WRITE(V25) {
  bool ALLOFF = param.asInt();
  if (ALLOFF == 1) {
    mcp.digitalWrite(H_Coil, HIGH);
    ledcWrite(LEDC_CHANNEL, 0);
    delay(500); 
    mcp.digitalWrite(H_Coil, LOW);
    ledcWrite(LEDC_CHANNEL, 0);
  }
}



BLYNK_WRITE(V0) //Slider - Manually adjust volume
{
  if (ledState) {
    Brightness = param.asInt();
    ledcWrite(LEDC_CHANNEL, Brightness);
  }
}
// Virtual pin for red control
BLYNK_WRITE(V34) {
    redValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for green control
BLYNK_WRITE(V35) {
    greenValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for blue control
BLYNK_WRITE(V36) {
    blueValue = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for white brightness control
BLYNK_WRITE(V37) {
    whiteBrightness = param[0].asInt();
    for(int i=0; i< strip.numPixels(); i++){
        strip.setPixelColor(i, redValue, greenValue, blueValue, whiteBrightness);
    }
    strip.show();
}

// Virtual pin for warm/cool transition control
BLYNK_WRITE(V38) {
    warmCool = param[0].asInt();
    int r = redValue, g = greenValue, b = blueValue;
    for(int i=0; i< strip.numPixels(); i++){
        // Adjust color temperature
        r = (255 - redValue) * warmCool / 100 + redValue;
        g = (255 - greenValue) * warmCool / 100 + greenValue;
        b = (255 - blueValue) * warmCool / 100 + blueValue;
        strip.setPixelColor(i, r, g, b, whiteBrightness);
    }
    strip.show();
}

void loop() {
  Blynk.run();//Run the Blynk library
  timer.run();//Run the Blynk timer
  
}


void PIRLED() {
  // Check if motion was detected
  int pirValue = digitalRead(PIR);
  Serial.println("Pir Value: " + String(pirValue));
  static bool ledState = false;
  static unsigned long lastMotionTime = 0;

  if (pirValue == HIGH) { // Motion was detected

    if (!ledState) {
      // LED is off, fade it in
      for (int i = 0; i <= 255; i++) {
        ledcWrite(LEDC_CHANNEL, i);
        delay(1);
      }
    } else {
      // LED is already on, keep it on
      ledcWrite(LEDC_CHANNEL, 255);
    }
    ledState = true;
    Blynk.virtualWrite(V1, HIGH); // update the Blynk switch
    // Update the last motion time
    lastMotionTime = millis();
  } else if (ledState && millis() - lastMotionTime > LED_OFF_INTERVAL) {
    // No motion was detected, and the LED is on, but it has been more than the LED_OFF_INTERVAL
    // since the last motion was detected, so fade the LED off
    for (int i = 255; i >= 0; i--) {
      ledcWrite(LEDC_CHANNEL, i);
      delay(1);
      
    }
    ledState = false;
    Blynk.virtualWrite(V1, LOW); // update the Blynk switch
    Blynk.setProperty(V0, "readonly", "false");
  }
}



void controlTemperature() {
  if (automaticTempMode == 1) {

      float currentTemperature = iaqSensor.temperature;

      if (currentTemperature < temperatureSetpoint - 0) {
        mcp.digitalWrite(H_Coil, LOW);
        mcp.digitalWrite(Fan_H, LOW);
        mcp.digitalWrite(Comp, HIGH);
      } else if (currentTemperature > temperatureSetpoint + 0) {
        mcp.digitalWrite(H_Coil, HIGH);
        mcp.digitalWrite(Fan_H, LOW);
        mcp.digitalWrite(Comp, LOW);
      } else {
    }
  }
}

void controlHumidity() {
  if (automaticHumMode == 1) {
      float currentHumidity = iaqSensor.humidity;

      if (currentHumidity < humiditySetpoint - 0) {
        mcp.digitalWrite(Pump, LOW);
        mcp.digitalWrite(Comp, LOW);
        mcp.digitalWrite(Fan_H, LOW);
      } else if (currentHumidity > humiditySetpoint + 0) {
        mcp.digitalWrite(Pump, HIGH);
        mcp.digitalWrite(Comp, HIGH);
        mcp.digitalWrite(Fan_H, HIGH);
      } else {

    }
  }
}


void sendEnergymon() {
    emon.calcVI(20, 2000);

    Blynk.virtualWrite(V30, emon.Vrms);

    Blynk.virtualWrite(V31, emon.Irms);

    Blynk.virtualWrite(V32, emon.apparentPower);
    Serial.print("\tkWh: ");
    kWh = kWh + emon.apparentPower*(millis()-lastmillis)/3600000000.0;
    Serial.print(kWh, 4);
    Serial.println("kWh");
    lastmillis = millis();
    Blynk.virtualWrite(V33, kWh);
}


// Helper function definitions
void checkIaqSensorStatus(void)
{
  if (iaqSensor.status != BSEC_OK)
  {
    if (iaqSensor.status < BSEC_OK)
    {
      output = "BSEC error code : " + String(iaqSensor.status);
      Serial.println(output);
      for (;;)
        errLeds();
    }
    else
    {
      output = "BSEC warning code : " + String(iaqSensor.status);
      Serial.println(output);
    }
  }

  if (iaqSensor.bme680Status != BME680_OK)
  {
    if (iaqSensor.bme680Status < BME680_OK)
    {
      output = "BME680 error code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
      for (;;)
        errLeds();
    }
    else
    {
      output = "BME680 warning code : " + String(iaqSensor.bme680Status);
      Serial.println(output);
    }
  }
}

void errLeds(void)
{
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);
  delay(100);
  digitalWrite(2, LOW);
  delay(100);
}


void sendSensor()
{
  unsigned long time_trigger = millis();
  if (iaqSensor.run()) // If new data is available
  {
    
    output = String(time_trigger);
    output += ", " + String(iaqSensor.rawTemperature);
    output += ", " + String(iaqSensor.pressure);
    output += ", " + String(iaqSensor.rawHumidity);
    output += ", " + String(iaqSensor.gasResistance);
    output += ", " + String(iaqSensor.iaq);
    output += ", " + String(iaqSensor.iaqAccuracy);
    output += ", " + String(iaqSensor.temperature);
    output += ", " + String(iaqSensor.humidity);
    output += ", " + String(iaqSensor.staticIaq);
    output += ", " + String(iaqSensor.co2Equivalent);
    output += ", " + String(iaqSensor.breathVocEquivalent);

    Blynk.virtualWrite(V11, iaqSensor.pressure);      // For Pressure
    Blynk.virtualWrite(V12, iaqSensor.temperature);            // For Temperature
    Blynk.virtualWrite(V13, iaqSensor.humidity);               // For Humidity
    Blynk.virtualWrite(V14, iaqSensor.staticIaq);               //For Static Index of Air Quality
    Blynk.virtualWrite(V15, iaqSensor.co2Equivalent);          // For CO2
    Blynk.virtualWrite(V16, iaqSensor.breathVocEquivalent); 

    Serial.print("Temperature: ");
    Serial.println(iaqSensor.temperature);
    Serial.print("Humidity: ");
    Serial.println(iaqSensor.humidity);
    Serial.println("");
    Serial.println("automaticTempMode:");
    Serial.print(automaticTempMode);
    Serial.println("");
    Serial.println("automaticHumMode:");
    Serial.print(automaticHumMode);
    Serial.println("");
    Serial.print("Target temp: ");
    Serial.println(temperatureSetpoint);
    Serial.print("Target humid: ");
    Serial.println(humiditySetpoint);
    Serial.println("");

  }
  else
  {
    // checkIaqSensorStatus();
  }

}

You still haven’t given us any clues where to look in your sketch for the code that controls these relays, or which pins they are connected to.

Pete.