Arduino Mega with Ethernet stops working

Hi all!

I have an Arduino Mega board with an ethernet shield connected to it. The pins control relays that turn ON/OFF lights mostly (both 12V LED and 230V "normal" lights), and control shutters. I have also input pins for light switches and sensors (temperature sensor, rain sensor, motion sensor, reed switch).
I have installed it a week ago and my problem is that everything works fine for a couple of hours (or days), then the ethernet shield suddenly stops working (it cannot be even pinged anymore). The sketch runs continously so I am still able to switch the lights. After reboot, all goes back to operation.
The more serious issue is that after one week of operation the whole thing stopped working today (it does not respond to anything). The lights on the ethernet shield are off, however the green led on the Mega is ON. I haven't yet had the chance to try out from USB so I cannot provide more information at this point but if you have any idea what could be wrong, I would be very grateful!

Thanks in advance!

have you checked if the LEDs are fighting the ethernet shield for ownership of any pins. you didn't supply wiring or code so we can only guess.

My money is in the wiring overloading mega .

Often with code supplied, the internet connection is made during setup , so if for any reason the connection is lost , the Arduino cannot re connect .

Anyhow , yes code and a proper wiring diagram needed .

There is a bug in your sketch.

Seriously - why don't you post your code in code tags, a schematic what you have connected how, and good pictures of your installation so we can see if there might be a wiring problem?

see:

Hi!

The design is highly special for my unique use case, and the code is long (2000 rows) - this is the reason why I have asked for a general idea in the first place if there is a known bug in the ethernet/mqtt library, or a known limitation of the hardware. But I try to attach the code now.
Please keep in mind that this code was intended to use only for myself, so there are places where it is not really nice, but is a working solution. I have started extending the code of Jeroen Schaeken's MqttRelayWithState in the first place (arduinoHouse/mqttRelayWithState.ino at master · jschaeke/arduinoHouse · GitHub) so you can recognize traits of that code in mine but it has been completely rewritten with a lot additional functionalities.

I do not have a diagram at this point but i will create it soon (I only have an excel table to have a list of pins which pin does what).

A question at first: I use pins 11, 12 too (but not 10 or 13). Somewhere I read that pins 10-11-12-13 are used by the ethernet shield but I am nut sure...

So anyway, here is my sketch (sensitive parts are exchanged with A,B,X,Y,Z letters):

#include <Ethernet.h>
#include <PubSubClient.h>
#include <Bounce2.h>
#include <AsyncDelay.h>

#include <DHT.h>

// temp & hum sensors
#define DHT1PIN 2
#define DHT2PIN 3
#define DHT3PIN 4
#define DHT4PIN 5
#define DHT5PIN 58
#define DHT6PIN 59

#define DHTTYPE DHT21

DHT dht1(DHT1PIN, DHTTYPE);
DHT dht2(DHT2PIN, DHTTYPE);
DHT dht3(DHT3PIN, DHTTYPE);
DHT dht4(DHT4PIN, DHTTYPE);
DHT dht5(DHT5PIN, DHTTYPE);
DHT dht6(DHT6PIN, DHTTYPE);

// shutters
#define SHUTTER1UPPIN 60
#define SHUTTER1DOWNPIN 61
#define SHUTTER2UPPIN 62
#define SHUTTER2DOWNPIN 63

#define SHUTTER1UPSWITCH 64
#define SHUTTER1DOWNSWITCH 65
#define SHUTTER2UPSWITCH 66
#define SHUTTER2DOWNSWITCH 67


// Update these with values suitable for your network.
byte mac[]    = {  0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
byte server[] = { A, B, X, Y };
byte ip[]     = { A, B, X, Y };

EthernetClient ethernetClient;
PubSubClient client(ethernetClient);
long lastMsg = 0;
char msg[50];
int value = 0;
AsyncDelay delay_rainsensor;
AsyncDelay delay_tempsensor;
AsyncDelay delay_closetLED1;
AsyncDelay delay_closetLED2;
AsyncDelay delay_closetLED3;

const char* outTopic = "stat/arduinomega/state";
const char* outSceneTopic = "stat/arduinomega/";
const char* outSensorTopic = "tele/arduinomega/SENSOR";
//const char* inTopic = "cmnd/arduinomega/POWER/#";
const char* inTopic2 = "cmnd/arduinomega/DEF";
const char* inTopic = "cmnd/arduinomega/#";
const char* outRelayTopic = "stat/arduinomega/POWER";
const char* outPinTopic = "stat/arduinomega/switch";
const char* outShutterCmdTopic = "stat/arduinomega/SHUTTER";
const char* outShutterPosTopic = "stat/arduinomega/SHUTTERPOS";
const char* inShutterCmndTopic = "cmnd/arduinomega/SHUTTER"; 
const char* inRestartCmndTopic = "cmnd/arduinomega/RESTART"; 

bool shutterButtonStates[] = {
  HIGH, HIGH, HIGH, HIGH
}; // pin: 64, 65, 66, 67

bool relayStates[] = {
  LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
};

int relayPins[] = {
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34
};       // an array of pin numbers to which LEDs are attached
const int pinCount = 14;
//int pinCount = 10;

int reedSensorPins[] = {
8, 9, 11, 12, 14, 44, 55, 57
};       // an array of pin numbers to which REED sensors are attached
const int reedSensorPinCount = 8;

const int PIRCount = 4;
const int tempSensorCount = 5;

bool relaysTurnOn[pinCount] = {};
unsigned long int overridePIR[PIRCount] = {};

bool nightPeeRelays[pinCount] = {};

//--------------------CONFIGURABLE DEFAULTS-------------------------
int defTimeoutStateChangeCounterMs = 1000; // 1 second
int defNumStateChangeDisableEnablePIRs = 5;
int defNumStateChangeTurnOnAll = 4;
int defNumStateChangeTurnOffAll = 3;
int defNumStateChangeControlShutter = 3;
int defNumStateChangeStayTurnedONOrNightPee = 2; // if turnOnAllLights is active it forces the current light to exclude from OFF timer, OR
                                                 // if turnOnAllLight is not active it initiates Mark's night pee feature to turn on several lights
unsigned long int defTimerTurnOnAllLightsMs = 180000; // 3 minutes
unsigned long int defTimerTurnOnLightsForNightPeeMs = 180000; // 3 minutes
int defOverridePIRTimeoutMin = 60;
int defDisablePIR1 = 0;
int defDisablePIR2 = 0;
int defDisablePIR3 = 0;
int defDisablePIR4 = 0;
unsigned long int defTimerPIR1Ms = 30000;
unsigned long int defTimerPIR2Ms = 30000;
unsigned long int defTimerPIR3Ms = 30000;
unsigned long int defTimerPIR4Ms = 30000;
unsigned long int defDelayRainSensorMs = 10000;
unsigned long int defDelayTempSensorMs = 30000;
unsigned long int defDelayTimerClosetLEDMs = 300000;
unsigned long int defRainSensorTresholdValue = 900;
unsigned long int defShutter1OpenCloseDurationMs = 49000; //49 sec
unsigned long int defShutter2OpenCloseDurationMs = 49000; //49 sec
unsigned long int defShutter1MotorStartDurationMs = 1200; //1,2 sec
unsigned long int defShutter2MotorStartDurationMs = 1200; //1,2 sec
int defStairsTurnOnClosetShelfLights = 1;
int defWardrobeTurnOnClosetShelfLights = 1;
int defTimerTurnOffLightDuringDayMin = 10;
bool excludedRelays[pinCount] = {};

//-----------------------------------------------------
int defDisableEnablePIRs = 1;

String dayOrNight = "NIGHT"; // override this info from OPENHAB via MQTT message (topic: cmnd/arduinomega/DAYORNIGHT) when time of day changes...
int expCnt1 = 0;
int expCnt2 = 0;
int expCnt3 = 0;
int counter = 0;
int initCounter;
unsigned long int turnOnAllLightsTimestamp = 0;
unsigned long int turnOnLightsForNightPeeTimestamp = 0;
unsigned long int MQTTFailedConnectTime = 0;
unsigned long int timerPIR1 = 0;
unsigned long int timerPIR2 = 0;
unsigned long int timerPIR3 = 0;
unsigned long int timerPIR4 = 0;

// shutter variable initialization
int               Shutter1Direction = 20; // values: 1-UP, 2-DOWN, 10-STOP (previous state was UP), 20-STOP (previous state was DOWN)
unsigned long int Shutter1OperationTimeMs = 0;
long int          Shutter1PosTimeMs = 0;
int               Shutter2Direction = 20; // values: 1-UP, 2-DOWN, 10-STOP (previous state was UP), 20-STOP (previous state was DOWN)
unsigned long int Shutter2OperationTimeMs = 0;
long int          Shutter2PosTimeMs = 0;

unsigned long int millisTStampTimerDuringDay[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0
};

unsigned long int millisTStamp[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0
};
int lightCnt = 9;

int toggleCnt[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0
}; // 18 19 20 45 46 47 48 40 42


#define PIN_DETECT_6 6
#define PIN_DETECT_7 7
#define PIN_DETECT_8 8
#define PIN_DETECT_9 9
#define PIN_DETECT_44 44
#define PIN_DETECT_11 11
#define PIN_DETECT_12 12
#define PIN_DETECT_57 57 // 13 is LED and not recommended to be used...
#define PIN_DETECT_14 14
#define PIN_DETECT_15 15  
#define PIN_DETECT_16 16  
#define PIN_DETECT_17 17
#define PIN_DETECT_18 18
#define PIN_DETECT_19 19
#define PIN_DETECT_20 20
#define PIN_DETECT_45 45
#define PIN_DETECT_46 46
#define PIN_DETECT_47 47
#define PIN_DETECT_48 48
#define PIN_DETECT_40 40
#define PIN_DETECT_41 41 
#define PIN_DETECT_42 42  
#define PIN_DETECT_55 55
#define PIN_DETECT_56 56 
#define PIN_DETECT_43 43  

#define PIN_DETECT_54 54  // A0

#define PIN_DETECT_64 64
#define PIN_DETECT_65 65
#define PIN_DETECT_66 66
#define PIN_DETECT_67 67
#define PIN_DETECT_68 68

//---------END NEW PINS ------------------
Bounce debounce6 = Bounce();
Bounce debounce7 = Bounce();
Bounce debounce8 = Bounce();
Bounce debounce9 = Bounce();
Bounce debounce44 = Bounce();
Bounce debounce11 = Bounce();
Bounce debounce12 = Bounce();
Bounce debounce57 = Bounce();
Bounce debounce14 = Bounce();
Bounce debounce15 = Bounce();
Bounce debounce16 = Bounce();
Bounce debounce17 = Bounce();
Bounce debounce18 = Bounce();
Bounce debounce19 = Bounce();
Bounce debounce20 = Bounce();
Bounce debounce45 = Bounce();
Bounce debounce46 = Bounce();
Bounce debounce47 = Bounce();
Bounce debounce48 = Bounce();
Bounce debounce40 = Bounce();
Bounce debounce41 = Bounce();
Bounce debounce42 = Bounce();
Bounce debounce55 = Bounce();
Bounce debounce56 = Bounce();
Bounce debounce43 = Bounce(); 
Bounce debounce64 = Bounce();
Bounce debounce65 = Bounce();
Bounce debounce66 = Bounce(); 
Bounce debounce67 = Bounce();
Bounce debounce68 = Bounce();

// -------------------------------

boolean doSwitch = false;

void setup_ethernet() {
  Serial.println("\nSetup ethernet");
  delay(10);
  // We start by connecting to a WiFi network
  Ethernet.begin(mac, ip);

  digitalWrite(13, LOW);
  delay(500);
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
  digitalWrite(13, HIGH);

}

void shutterControl(int pin, int OnOff) {
  if (pin == SHUTTER1UPSWITCH) {
    if(OnOff == 0) {
      //alway safe to turn OFF relay but do not resend OFF command
      if (digitalRead(SHUTTER1UPPIN) == HIGH) {
        executeShutterCmd(1, 0, 1); 
      }
    } else {
      // check the belonging relay and manage turn off that...
      if(digitalRead(SHUTTER1DOWNPIN) == LOW) {
            Serial.print(digitalRead(SHUTTER1UPPIN), DEC);
        // belonging relay is OFF -> safe to turn this ON
        if(digitalRead(SHUTTER1UPPIN) == LOW) {
          executeShutterCmd(1, 1, 0);
        }
      } else {
        // belonging relay is ON -> STOP shutter
        executeShutterCmd(1, 0, 2);
      }
    }
  } else if (pin == SHUTTER1DOWNSWITCH) {
    if(OnOff == 0) {
      //alway safe to turn OFF relay but do not resend OFF command
      if (digitalRead(SHUTTER1DOWNPIN) == HIGH) {
        executeShutterCmd(1, 0, 2); 
      }
    } else {
      // check the belonging relay and manage turn off that...
      if(digitalRead(SHUTTER1UPPIN) == LOW) {
        // belonging relay is OFF -> safe to turn this ON
        if(digitalRead(SHUTTER1DOWNPIN) == LOW) {
          executeShutterCmd(1, 2, 0);
        }
      } else {
        // belonging relay is ON -> STOP shutter
        executeShutterCmd(1, 0, 1);
      }
    }   
  } else if (pin == SHUTTER2UPSWITCH) {
    if(OnOff == 0) {
      //alway safe to turn OFF relay but do not resend OFF command
      if (digitalRead(SHUTTER2UPPIN) == HIGH) {
        executeShutterCmd(2, 0, 1); 
      }
    } else {
      // check the belonging relay and manage turn off that...
      if(digitalRead(SHUTTER2DOWNPIN) == LOW) {
        // belonging relay is OFF -> safe to turn this ON
        if(digitalRead(SHUTTER2UPPIN) == LOW) {
          executeShutterCmd(2, 1, 0);
        }
      } else {
        // belonging relay is ON -> STOP shutter
        executeShutterCmd(2, 0, 2);
      }
    } 
  } else if (pin == SHUTTER2DOWNSWITCH) {
    if(OnOff == 0) {
      //alway safe to turn OFF relay but do not resend OFF command
      if (digitalRead(SHUTTER2DOWNPIN) == HIGH) {
        executeShutterCmd(2, 0, 2); 
      }
    } else {
      // check the belonging relay and manage turn off that...
      if(digitalRead(SHUTTER2UPPIN) == LOW) {
        // belonging relay is OFF -> safe to turn this ON
        if(digitalRead(SHUTTER2DOWNPIN) == LOW) {
          executeShutterCmd(2, 2, 0);
        }
      } else {
        // belonging relay is ON -> STOP shutter
        executeShutterCmd(2, 0, 1);
      }
    }
  }
}

void executeShutterSequence(int shutterNum) { //sequence goes like: UP, STOP, DOWN, STOP, ...
  int shutterDirection;
  Serial.print("Executing next command for shutter");
  Serial.println(shutterNum, DEC);

  if(shutterNum == 1) {
    shutterDirection = Shutter1Direction;
  } else if (shutterNum == 2) {
    shutterDirection = Shutter2Direction;
  }
  
  if(shutterDirection == 10) {
    // Execute DOWN after STOP
    executeShutterCmd(shutterNum, 2, 0);
  } else if (shutterDirection == 20) {
    // Execute UP after STOP
    executeShutterCmd(shutterNum, 1, 0);
  } else if (shutterDirection == 1) {
    // Execute STOP after UP
    executeShutterCmd(shutterNum, 0, 1);
  } else if (shutterDirection == 2) {
    // Execute STOP after DOWN
    executeShutterCmd(shutterNum, 0, 2);
  }
}

void executeShutterCmd(int shutterNum, int dir, int fromDir) { // dir: 0-STOP, 1-UP, 2-DOWN; fromDir says if we STOP the shutter from moving UP (value: 1) or DOWN (value: 2)
//position: 0-fully closed, 100-fully opened; Fully closed: 0ms, Fully Opened: defShutterXOpenCloseDuration
  int shutterPos = 0;
  if(shutterNum == 1) {
    if(dir == 0) {
      Shutter1OperationTimeMs = millis() - Shutter1OperationTimeMs; 

      // STOP the shutter, calculate and publish position, direction
      if(fromDir == 1) { //STOP from UP
        Shutter1Direction = 10;
        digitalWrite(SHUTTER1UPPIN,LOW);
        Shutter1PosTimeMs = Shutter1PosTimeMs + Shutter1OperationTimeMs;
      } else if (fromDir == 2) { //STOP from DOWN
        Shutter1Direction = 20;
        digitalWrite(SHUTTER1DOWNPIN,LOW);
        Shutter1PosTimeMs = Shutter1PosTimeMs - Shutter1OperationTimeMs;
      }
      
      //normalize pos time if we ran out of it
      if(Shutter1PosTimeMs > defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs){
        Shutter1PosTimeMs = defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs;
      } else if (Shutter1PosTimeMs < 0) {
        Shutter1PosTimeMs = 0;
      }
      
      shutterPos = Shutter1PosTimeMs * 100 / (defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs);
      publishShutterDir(1, 0);
      publishShutterPos(1, shutterPos);
    } else if (dir == 1 && Shutter1PosTimeMs < defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs) {
      // Shutter UP
      digitalWrite(SHUTTER1UPPIN,HIGH);
      Shutter1Direction = 1;
      Shutter1OperationTimeMs = millis();
      publishShutterDir(1, 1);
    } else if (dir == 2) {
      // Shutter DOWN
      digitalWrite(SHUTTER1DOWNPIN,HIGH);
      Shutter1Direction = 2;
      Shutter1OperationTimeMs = millis();
      publishShutterDir(1, 2);
    }
  } else if (shutterNum == 2) {
    if(dir == 0) {
      Shutter2OperationTimeMs = millis() - Shutter2OperationTimeMs; 

      // STOP the shutter, calculate and publish position, direction
      if(fromDir == 1) { //STOP from UP
        Shutter2Direction = 10;
        digitalWrite(SHUTTER2UPPIN,LOW);
        Shutter2PosTimeMs = Shutter2PosTimeMs + Shutter2OperationTimeMs;
      } else if (fromDir == 2) { //STOP from DOWN
        Shutter2Direction = 20;
        digitalWrite(SHUTTER2DOWNPIN,LOW);
        Shutter2PosTimeMs = Shutter2PosTimeMs - Shutter2OperationTimeMs;
      }

      //normalize pos time if we ran out of it
      if(Shutter2PosTimeMs > defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs){
        Shutter2PosTimeMs = defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs;
      } else if (Shutter2PosTimeMs < 0) {
        Shutter2PosTimeMs = 0;
      }
      
      shutterPos = Shutter2PosTimeMs * 100 / (defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs);
      publishShutterDir(2, 0);
      publishShutterPos(2, shutterPos);
    } else if (dir == 1 && Shutter2PosTimeMs < (defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs)) {
      // Shutter UP
      digitalWrite(SHUTTER2UPPIN,HIGH);
      Shutter2Direction = 1;
      Shutter2OperationTimeMs = millis();
      publishShutterDir(2, 1);
    } else if (dir == 2) {
      // Shutter DOWN
      digitalWrite(SHUTTER2DOWNPIN,HIGH);
      Shutter2Direction = 2;
      Shutter2OperationTimeMs = millis();
      publishShutterDir(2, 2);
    }    
  }
}

bool get_token(String &from, String &to, uint8_t index, char separator, unsigned long int length)
{
  uint16_t start = 0, idx = 0;
  uint8_t cur = 0;
  while (idx < length)
  {
    if (from.charAt(idx) == separator)
    {
      if (cur == index)
      {
        to = from.substring(start, idx);
        return true;
      }
      cur++;
      while ((idx < length - 1) && (from.charAt(idx + 1) == separator)) idx++;
      start = idx + 1;
    }
    idx++;
  }
  if ((cur == index) && (start < length))
  {
    to = from.substring(start, length);
    return true;
  }
  return false;
}

void setDefaultValues(byte* payload, unsigned long int length) {
  int token_idx = 0;
  int idx = 0;
  String token, payloadStr;
  String tokenValueArr;
  Serial.println("\n Received new DEFAULT values via MQTT!"); 
  while (get_token(payload, token, token_idx, ' ', length)) {
      Serial.println("\nToken: " + token);
      if (token.startsWith("timeoutStateChangeCounterMs")) {
        defTimeoutStateChangeCounterMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ntimeoutStateChangeCounterMs changed to:"+(String)defTimeoutStateChangeCounterMs);
      } else if (token.startsWith("numStateChangeTurnOnAll")) {
        defNumStateChangeTurnOnAll = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefNumStateChangeTurnOnAll changed to:"+(String)defNumStateChangeTurnOnAll);
      } else if (token.startsWith("numStateChangeDisableEnablePIRs")) {
        defNumStateChangeDisableEnablePIRs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefNumStateChangeTurnOnAll changed to:"+(String)defNumStateChangeTurnOnAll);
      } else if (token.startsWith("numStateChangeTurnOffAll")) {
        defNumStateChangeTurnOffAll = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefNumStateChangeTurnOffAll changed to:"+(String)defNumStateChangeTurnOffAll);
      } else if (token.startsWith("numStateChangeControlShutter")) {
        defNumStateChangeControlShutter = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefNumStateChangeControlShutter changed to:"+(String)defNumStateChangeControlShutter);
      } else if (token.startsWith("numStateChangeStayTurnedONOrNightPee")) { // override turn off timer for belonging relay
        defNumStateChangeStayTurnedONOrNightPee = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefNumStateChangeStayTurnedONOrNightPee changed to:"+(String)defNumStateChangeStayTurnedONOrNightPee);
      } else if (token.startsWith("timerTurnOnAllLightsMs")) { // timer to turn off all lights after turnOnAllLights feature executed
        defTimerTurnOnAllLightsMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerTurnOnAllLightsMs changed to:"+(String)defTimerTurnOnAllLightsMs);
      } else if (token.startsWith("timerTurnOnLightsForNightPeeMs")) {
        defTimerTurnOnLightsForNightPeeMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerTurnOnLightsForNightPeeMs changed to:"+(String)defTimerTurnOnLightsForNightPeeMs);
      } else if (token.startsWith("overridePIRTimeoutMin")) {
        defOverridePIRTimeoutMin = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\defOverridePIRTimeoutMin changed to:"+(String)defOverridePIRTimeoutMin);
      } else if (token.startsWith("disablePIR1")) {
        defDisablePIR1 = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDisablePIR1 changed to:"+(String)defDisablePIR1);
      } else if (token.startsWith("disablePIR2")) {
        defDisablePIR2 = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDisablePIR2 changed to:"+(String)defDisablePIR2);
      } else if (token.startsWith("disablePIR3")) {
        defDisablePIR3 = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDisablePIR3 changed to:"+(String)defDisablePIR3);
      } else if (token.startsWith("disablePIR4")) {
        defDisablePIR4 = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDisablePIR4 changed to:"+(String)defDisablePIR4);
      } else if (token.startsWith("disableAllPIRs")) {
        if (token.substring(token.indexOf('=') + 1) == '1' ) {
         defDisablePIR1 = 1;
         defDisablePIR2 = 1;
         defDisablePIR3 = 1;
         defDisablePIR4 = 1;
        } else if (token.substring(token.indexOf('=') + 1) == '0' ) {
         defDisablePIR1 = 0;
         defDisablePIR2 = 0;
         defDisablePIR3 = 0;
         defDisablePIR4 = 0;        
        }
        Serial.println("\ndisableAllPIRs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timerPIR1Ms")) { // timer to turn off assigned relay after PIR detected motion and turned relay on
        defTimerPIR1Ms = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerPIR1Ms changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timerPIR2Ms")) { // timer to turn off assigned relay after PIR detected motion and turned relay on
        defTimerPIR2Ms = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerPIR2Ms changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timerPIR3Ms")) { // timer to turn off assigned relay after PIR detected motion and turned relay on
        defTimerPIR3Ms = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerPIR3Ms changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timerPIR4Ms")) { // timer to turn off assigned relay after PIR detected motion and turned relay on
        defTimerPIR4Ms = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerPIR4Ms changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("statCycleRainSensorMs")) {
        defDelayRainSensorMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDelayRainSensorMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("statCycleTempSensorMs")) {
        defDelayTempSensorMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDelayTempSensorMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timeoutClosetLEDMs")) {      
        defDelayTimerClosetLEDMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDelayTimerClosetLEDMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("shutter1OpenCloseDurationMs")) {      
        defShutter1OpenCloseDurationMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefShutter1OpenCloseDurationMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("shutter2OpenCloseDurationMs")) {      
        defShutter2OpenCloseDurationMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefShutter2OpenCloseDurationMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("shutter1MotorStartDurationMs")) {      
        defShutter1MotorStartDurationMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefShutter1MotorStartDurationMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("shutter2MotorStartDurationMs")) {      
        defShutter2MotorStartDurationMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefShutter2MotorStartDurationMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("rainSensorTresholdValue")) {      
        defRainSensorTresholdValue = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefRainSensorTresholdValue changed to:"+(String)token.substring(token.indexOf('=') + 1));        
      } else if (token.startsWith("timerClosetLEDMs")) {
        defDelayTimerClosetLEDMs = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefDelayTimerClosetLEDMs changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("stairsTurnOnClosetShelfLights")) {
        defStairsTurnOnClosetShelfLights = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefStairsTurnOnClosetShelfLights changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if(token.startsWith("wardrobeTurnOnClosetShelfLights")) {
        defWardrobeTurnOnClosetShelfLights = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\defWardrobeTurnOnClosetShelfLights changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("timerTurnOffLightDuringDayMin")) {
        defTimerTurnOffLightDuringDayMin = token.substring(token.indexOf('=') + 1).toInt();
        Serial.println("\ndefTimerTurnOffLightDuringDayMin changed to:"+(String)token.substring(token.indexOf('=') + 1));
      } else if (token.startsWith("excludedRelaysTurnOnAllLights")) { // we have 14relays (from pin 21 to pin 34). 
                                                                  // Example for this parameter in the format:  excludedRelaysTurnOnAllLights=false,false,true,true,false,false,false,false,false,false,false,false,false,false 
                                                                  //                    Pin numbers of relays:                                  D21   D22  D23  D24  D25   D26   D27   D28   D29    D30  D31   D32    D33   D34
                                                                  // those relays won't be turned on by the feature of TurnOnAllLights
        tokenValueArr = token.substring(token.indexOf('=') + 1);
        Serial.print("\nexcludedRelaysTurnOnAllLights changed to:");
        while (get_token(tokenValueArr, token, idx, ',', tokenValueArr.length()))
        {
          if(token.startsWith("1") || token.startsWith("true")) {
            excludedRelays[idx] = true;
            Serial.print(" true");
          } else {
            excludedRelays[idx] = false;
            Serial.print(" false");
          }
          idx++;
        }
        Serial.println();
      }
    token_idx++;
  }
}

void delayTimers() {
  delay_rainsensor.start(defDelayRainSensorMs, AsyncDelay::MILLIS);
  delay_tempsensor.start(defDelayTempSensorMs, AsyncDelay::MILLIS);
}

void publishPinStates() {
  for (int thisPin = 0; thisPin < pinCount; thisPin++) {
    char* state = relayStates[thisPin] == LOW ? "OFF" : "ON";
    publishRelayState(thisPin + 1, state);
  }
  for (int thisPin = 0; thisPin < reedSensorPinCount; thisPin++) {
    char* state = digitalRead(reedSensorPins[thisPin]) == LOW ? "OFF" : "ON";
    publishPinState(reedSensorPins[thisPin], state);
  }
}

void toggleRelay(int pos) {
  Serial.println("\ntoggle relay: ");
  Serial.println(pos);
  Serial.println(relayPins[pos]);
  if (digitalRead(relayPins[pos]) == HIGH) {
    //Turning off is safe to be done immediately
    digitalWrite(relayPins[pos], LOW);
    relayStates[pos] = LOW;
    publishRelayState(pos +1,"OFF") ;
    Serial.println("\nRelay: OFF ");

    //closet leds for stairs light turn OFF
    if(pos == 10 && defStairsTurnOnClosetShelfLights == 1) {
      digitalWrite(relayPins[0], LOW);
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
    } else if(pos == 10 && defStairsTurnOnClosetShelfLights == 2) {
      digitalWrite(relayPins[1], LOW);
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
      switchRelay('0', 1); // pin22 - blue LED
    } else if(pos == 10 && defStairsTurnOnClosetShelfLights == 3) {
      digitalWrite(relayPins[0], LOW); // pin21 - white LED
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
    }
    
    //closet leds for Wardrobe light turn OFF
    if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 1) {
      digitalWrite(relayPins[0], LOW);
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
    } else if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 2) {
      digitalWrite(relayPins[1], LOW);
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
      switchRelay('0', 1); // pin22 - blue LED
    } else if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 3) {
      digitalWrite(relayPins[0], LOW); // pin21 - white LED
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
      
      digitalWrite(relayPins[1], LOW); // pin22 - blue LED
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
    }
    
    // check timer during day and reset if necessary
    if ((pos >= 2 && pos <= 10) && (millisTStampTimerDuringDay[pos-2] != 0)) {
      millisTStampTimerDuringDay[pos-2] = 0;
    }
  } else if (digitalRead(relayPins[pos]) == LOW) {
    //turning on is done in setStates
    digitalWrite(relayPins[pos], HIGH);
    publishRelayState(pos +1,"ON") ;
    relayStates[pos] = HIGH;
    Serial.println("\nRelay: ON ");

    //there is a timer to turn off the light during the day...
    if(dayOrNight.equals("DAY") && pos >= 2 && pos <= 10) {
      millisTStampTimerDuringDay[pos-2] = millis();
    }
  }
}

void switchRelay(char* switchState, int pos) {
  Serial.println("\nSwitch relay: ");
  Serial.println(pos);
  Serial.println(relayPins[pos]);
  if (switchState == '0') {
    //Turning off is safe to be done immediately
    digitalWrite(relayPins[pos], LOW);
    relayStates[pos] = LOW;
    publishRelayState(pos +1,"OFF") ;
    Serial.println("\nRelay: OFF ");
   
    //closet leds for stairs light turn OFF
    if(pos == 10 && defStairsTurnOnClosetShelfLights == 1) {
      digitalWrite(relayPins[0], LOW);
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
    } else if(pos == 10 && defStairsTurnOnClosetShelfLights == 2) {
      digitalWrite(relayPins[1], LOW);
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
      switchRelay('0', 1); // pin22 - blue LED
    } else if(pos == 10 && defStairsTurnOnClosetShelfLights == 3) {
      digitalWrite(relayPins[0], LOW); // pin21 - white LED
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
      
      digitalWrite(relayPins[1], LOW); // pin22 - blue LED
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
    }

    //closet leds for Wardrobe light turn OFF
    if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 1) {
      digitalWrite(relayPins[0], LOW);
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
    } else if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 2) {
      digitalWrite(relayPins[1], LOW);
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
      switchRelay('0', 1); // pin22 - blue LED
    } else if(pos == 2 && defWardrobeTurnOnClosetShelfLights == 3) {
      digitalWrite(relayPins[0], LOW); // pin21 - white LED
      relayStates[0] = LOW;
      publishRelayState(0 +1,"OFF") ;
      Serial.println("\nRelay: 21 OFF ");
      
      digitalWrite(relayPins[1], LOW); // pin22 - blue LED
      relayStates[1] = LOW;
      publishRelayState(1 +1,"OFF") ;
      Serial.println("\nRelay: 22 OFF ");
    }
    
    // check timer during day and reset if necessary
    if ((pos >= 2 && pos <= 10) && (millisTStampTimerDuringDay[pos-2] != 0)){
      millisTStampTimerDuringDay[pos-2] = 0;
    }
  } else if (switchState == '1') {
    //turning on is done in setStates
    digitalWrite(relayPins[pos], HIGH);
    publishRelayState(pos +1,"ON") ;
    relayStates[pos] = HIGH;
    Serial.println("\nRelay: ON ");

    //there is a timer to turn off the light during the day...
    if(dayOrNight.equals("DAY") && pos >= 2 && pos <= 10) {
      millisTStampTimerDuringDay[pos-2] = millis();
    }
  }
}

void cmdAcknowledged(int OnOff, int togglePos, int cmdNum) {
  int blinkTimeMs;
  int relayPos = togglePos + 2;
  if (OnOff == 1) {
    // feature turning ON -> long blinks
    blinkTimeMs = 1000;
  } else {
    // feature turning OFF -> short blinks
    blinkTimeMs = 250;
  }
  for(int i=0; i<(cmdNum*2); i++){
    delay(blinkTimeMs);
    if (digitalRead(relayPins[relayPos]) == HIGH) {
      switchRelay('0', relayPos);
    } else {
      switchRelay('1', relayPos);
    }
  }  
}

void turnOnAllLightsWithTimer() {
  // only use this feature if night pee feature is not active
  if (turnOnLightsForNightPeeTimestamp == 0 ) { 
  // check if feature is already active?
    if (turnOnAllLightsTimestamp == 0) {
      turnOnAllLightsTimestamp = millis();
  // feature not yet active
     //reinitialize array
     memcpy(relaysTurnOn, '\0', sizeof(relaysTurnOn)); 
      
      for (int relayPos = 0; relayPos < pinCount; relayPos++) { 
        if (digitalRead(relayPins[relayPos]) == LOW) {
          if (excludedRelays[relayPos] == false) {
            if((relayPos == 3 || relayPos == 4) && (digitalRead(55) == HIGH)) { // do not turn on bedroom lights when bedroom door is closed
              continue;
            }
            switchRelay('1', relayPos);
            relaysTurnOn[relayPos] = true;
          }
        }
      }
    } else {
      turnOnAllLightsTimestamp = millis(); // we need to update timestamp anyway - even if feature is already activated
    }
  } else {
    Serial.println("\nPEE is active, not starting TurnOnAllLights!");
  }
}

void turnOnLightsForNightPeeWithTimer() {
  if (turnOnAllLightsTimestamp == 0) {
// we can only use this feature if turnOnAllLights is not active
    if (turnOnLightsForNightPeeTimestamp != 0) {
      // feature is active -> only extend timer
       turnOnLightsForNightPeeTimestamp = millis();
    } else {
      // feature is not active -> activate 
      memcpy(relaysTurnOn, '\0', sizeof(relaysTurnOn));
      turnOnLightsForNightPeeTimestamp = millis();
      for (int relayPos = 0; relayPos < pinCount; relayPos++) { 
        if (nightPeeRelays[relayPos] == true) {
          switchRelay('1', relayPos);
          relaysTurnOn[relayPos] = true;
        }
      }
    }
  }
}

void turnOffLights() {
  for (int relayPos = 0; relayPos < pinCount; relayPos++) { 
    if (relaysTurnOn[relayPos] == true ) {
      switchRelay('0', relayPos);
    }
  }
  turnOnAllLightsTimestamp = 0; // it means feature not active
  turnOnLightsForNightPeeTimestamp = 0;
  memcpy(relaysTurnOn, '\0', sizeof(relaysTurnOn)); 
}

void turnOffAllLights() {
  Serial.println("\ninitialize all PINS to go LOW with turnOffAllLights");
  for (int relayPos = 0; relayPos < pinCount; relayPos++) { 
      switchRelay('0', relayPos);
  }
  turnOnAllLightsTimestamp = 0; // it means feature not active
  turnOnLightsForNightPeeTimestamp = 0;
  memcpy(relaysTurnOn, '\0', sizeof(relaysTurnOn)); 
}


void checkTimeoutAndExecute() {
  // check toggle timeout
  for (int pos = 0; pos < lightCnt; pos++) {
    if ((toggleCnt[pos] > 0) && (millisTStamp[pos] + defTimeoutStateChangeCounterMs < millis())) {
      //timer expired -> execute command
      executeCmnd(pos);
    }
    
    // turn off light after timer expired
    if ((millisTStampTimerDuringDay[pos] != 0) && (millisTStampTimerDuringDay[pos] + defTimerTurnOffLightDuringDayMin * 60000 < millis())) {
      //timer expired -> execute command
      switchRelay('0', pos + 2);
      millisTStampTimerDuringDay[pos] = 0;
    }
  }
}


void lightForceToStayOn(int togglePos) {
  if (turnOnAllLightsTimestamp != 0) {
    relaysTurnOn[togglePos + 2] = false; // relay position is toggleposition + 2
  } else if (togglePos == 3 || togglePos == 4) { // you can initiate night pee only from kids room!
      turnOnLightsForNightPeeWithTimer();
      Serial.println("\nPee");
  } else {
    // we need to turn ON the light anyway if it is not turned on already...
    //togglePos                             0 1  2  3  4  5  6  7  8
    // map between togglePos and Pins:     18 19 20 45 46 47 48 40 42
    // map between togglePos and relayPin: 23 24 25 26 27 28 29 30 31
    if(digitalRead(togglePos + 23) == LOW ) {
      switchRelay('1', togglePos +2); //relayPos is togglePos + 2
    }
    
    overridePIRIfNecessary(togglePos); 
  }
}

void overridePIRIfNecessary(int togglePos){
    if (togglePos == 8) {
      //PIR sensor 1 - lepcso
      overridePIR[0] = millis();
      Serial.println("PIR1 overriden for stairs");
    } else if (togglePos == 7 ) {
      //PIR sensor 2 - eloszoba
      overridePIR[1] = millis();
      Serial.println("PIR2 overriden for upstairs corridor");
    } else if (togglePos == 6) {
      //PIR sensor 3 - bathroom
      overridePIR[2] = millis();
      Serial.println("PIR3 overriden for bathroom");
    } else if(togglePos == 0) {
       //PIR sensor 4 - Wardrobe
       overridePIR[3] = millis();
       Serial.println("PIR4 overriden for wardrobe");
    }  
}

void executeCmnd(int togglePos) {
  Serial.println("\nExecute command:");
  Serial.println(toggleCnt[togglePos], DEC);
  if (toggleCnt[togglePos] == 1) { // this is only a normal switch
    toggleRelay(togglePos + 2);    //relayPos is togglePos+2

    delay(50); // allow time for state change
    
    //consider if closet leds should be turned on if stairs is turned on
    if(togglePos == 8 && digitalRead(relayPins[togglePos+2]) == HIGH) {
      if(defStairsTurnOnClosetShelfLights == 1) {
        switchRelay('1', 0); // pin21 - white LED
      } else if (defStairsTurnOnClosetShelfLights == 2) {
        switchRelay('1', 1); // pin21 - blue LED
      } else if (defStairsTurnOnClosetShelfLights == 3) {
        switchRelay('1', 0); // pin21 - white LED
        switchRelay('1', 1); // pin21 - blue LED
      }
    }

    //consider if closet leds should be turned on if Wardrobe main light is turned on
    if(togglePos == 0 && digitalRead(relayPins[togglePos+2]) == HIGH) {
      if(defWardrobeTurnOnClosetShelfLights == 1) {
        switchRelay('1', 0); // pin21 - white LED
      } else if (defWardrobeTurnOnClosetShelfLights == 2) {
        switchRelay('1', 1); // pin21 - blue LED
      } else if (defWardrobeTurnOnClosetShelfLights == 3) {
        switchRelay('1', 0); // pin21 - white LED
        switchRelay('1', 1); // pin21 - blue LED
      }
    }

  } else if ((toggleCnt[togglePos] == defNumStateChangeControlShutter) && (togglePos == 1 || togglePos == 2 || togglePos == 6)) { // pins: 19, 20 - (bedroom), 48 - bathroom
    if(togglePos == 1 || togglePos == 2) {
      executeShutterSequence(1); //control shutter of the same room with the light switch (shutter1-bedroom)
    } else if(togglePos == 6) {
     executeShutterSequence(2); //control shutter of the same room with the light switch (shutter2-bathroom) 
    }
  }else if (toggleCnt[togglePos] == defNumStateChangeStayTurnedONOrNightPee) {
    if (turnOnAllLightsTimestamp != 0) {
      //light force to stay turned on
      lightForceToStayOn(togglePos);
      Serial.println("\nlightForceStayOn");
      cmdAcknowledged(1, togglePos, defNumStateChangeStayTurnedONOrNightPee);
    } else {
      // initiate disable PIR feature or from kids room the nightPee feature
      lightForceToStayOn(togglePos);
    }    
  } else if (toggleCnt[togglePos] == defNumStateChangeTurnOffAll) {
    // initiate turn off all lights
    turnOffAllLights();
    Serial.println("\nTurnOFFAllLights");
  } else if (toggleCnt[togglePos] == defNumStateChangeTurnOnAll) {
    // initiate turn on all lights
    turnOnAllLightsWithTimer();
    Serial.println("\nTurnONAllLights");
  } else if (toggleCnt[togglePos] == defNumStateChangeDisableEnablePIRs) {
    if(defDisablePIR1 == 0) {
      // disable PIR sensors
      defDisablePIR1 = 1;
      defDisablePIR2 = 1;
      defDisablePIR3 = 1;
      defDisablePIR4 = 1;
      defDisableEnablePIRs = 0; //PIRs OFF so disabled
      cmdAcknowledged(0, togglePos, defNumStateChangeDisableEnablePIRs);
      Serial.println("\nDisablePIRS");
    } else {
      //enable PIR sensors
      defDisablePIR1 = 0;
      defDisablePIR2 = 0;
      defDisablePIR3 = 0;
      defDisablePIR4 = 0;
      defDisableEnablePIRs = 1; //PIRS ON so enabled
      cmdAcknowledged(1, togglePos, defNumStateChangeDisableEnablePIRs);   
      Serial.println("\nEnablePIRS");
    }
  }
  toggleCnt[togglePos]    = 0;
  millisTStamp[togglePos] = 0;
}

void handleToggle(int togglePos, int relayPos) {
      if (toggleCnt[togglePos] == 0) {
      // new toggle sequence
        Serial.println("\nNew sequence!");
        millisTStamp[togglePos] = millis();
        toggleCnt[togglePos] = 1;
      } else if (millisTStamp[togglePos] + defTimeoutStateChangeCounterMs < millis()) {
      // timer expired -> execute without adding this extra toggle
      Serial.println("\nTimer EXPIRED! Execute cmnd");
        executeCmnd(togglePos);
      } else {
      // still within time -> increase toggleCnt and start new timer
        toggleCnt[togglePos] = toggleCnt[togglePos] + 1;
        Serial.println("\nIncrease toggleCnt to:"+toggleCnt[togglePos]);
        millisTStamp[togglePos] = millis();
      }
}

void setStates() {
  if (doSwitch) {
    for (int thisPin = 0; thisPin < pinCount; thisPin++) {
      digitalWrite(relayPins[thisPin], relayStates[thisPin]);
    }
    doSwitch = false;
    delay_tempsensor.start(defDelayTempSensorMs, AsyncDelay::MILLIS);
  }
}

void publishShutterDir(int shutterNum, int dir) {
  char outputTopicBuff[100];
  //char shutterNumC = shutterNum;
  char shutterNumC[3];

  memset(outputTopicBuff, '\0', sizeof(outputTopicBuff));
  memset(shutterNumC, '\0', sizeof(shutterNumC));

  String shutterNumStr = String(shutterNum);
  shutterNumStr.toCharArray(shutterNumC, shutterNumStr.length() + 1);

  strcpy(outputTopicBuff, outShutterCmdTopic);
  strcat(outputTopicBuff, shutterNumC);

  Serial.print("\nShutter");
  Serial.print(shutterNum, DEC);
  Serial.print(": ");
  if(dir == 0) {
    client.publish(outputTopicBuff, "0");
    Serial.println("STOP");        
  } else if (dir == 1) { //UP
      client.publish(outputTopicBuff, "1");
      Serial.println("UP");      
  } else if (dir == 2) { //DOWN
      client.publish(outputTopicBuff, "2");
      Serial.println("DOWN");
  }         
}

void publishShutterPos(int shutterNum, int pos) {
  char outputTopicBuff[100];
  //char shutterNumC = shutterNum;
  char posC[4];
  //sprintf(posC,"%d", pos);
  char shutterNumC[3];

  memset(outputTopicBuff, '\0', sizeof(outputTopicBuff));
  memset(posC, '\0', sizeof(posC));
  memset(shutterNumC, '\0', sizeof(shutterNumC));
  
  String shutterNumStr = String(shutterNum);
  shutterNumStr.toCharArray(shutterNumC, shutterNumStr.length() + 1);
  
  String posStr = String(pos);
  posStr.toCharArray(posC, posStr.length() + 1);
  
  strcpy(outputTopicBuff, outShutterPosTopic);
  strcat(outputTopicBuff, shutterNumC);

  Serial.print("\nShutter");
  Serial.print(shutterNum, DEC);
  Serial.print("position: ");
  Serial.println(pos, DEC);
  
  client.publish(outputTopicBuff, posC);       
}

void publishScene(char* scene, char* state) {
  char outputTopicBuff[100];
  memset(outputTopicBuff, '\0', sizeof(outputTopicBuff));
  strcpy(outputTopicBuff, outSceneTopic);
  char sceneName[30];
  memset(sceneName, '\0', sizeof(sceneName));
  sprintf(sceneName, "%s", scene);
  strcat(outputTopicBuff, sceneName);
  client.publish(outputTopicBuff, state);
  Serial.println("\nscene state change:");
  Serial.println(state);
}

void publishRelayState(int relayNbr, char* state) {
  char outputTopicBuff[100];
  memset(outputTopicBuff, '\0', sizeof(outputTopicBuff));
  strcpy(outputTopicBuff, outRelayTopic);
  char relaybuffer[5];
   memset(relaybuffer, '\0', sizeof(relaybuffer));
  sprintf(relaybuffer, "%d", relayNbr);
  strcat(outputTopicBuff, relaybuffer);
  client.publish(outputTopicBuff, state);

  // reset PIR override - in case if it had been activated
  if(state == "OFF" && relayPins[relayNbr - 1] == 23) { //wardrobe
    overridePIR[3] = 0;
  } else if(state == "OFF" && relayPins[relayNbr - 1] == 29) { //bathroom
    overridePIR[2] = 0;
  } else if(state == "OFF" && relayPins[relayNbr - 1] == 30) { //upstairs corridor
    overridePIR[1] = 0;
  } else if(state == "OFF" && relayPins[relayNbr - 1] == 31) { //stairs
    overridePIR[0] = 0;
  }
}

void publishPinState(int pinNbr, char* state) {
  char outputTopicBuff[100];
   memset(outputTopicBuff, '\0', sizeof(outputTopicBuff));
  strcpy(outputTopicBuff, outPinTopic);
  char relaybuffer[5];
   memset(relaybuffer, '\0', sizeof(relaybuffer));
  sprintf(relaybuffer, "%d", pinNbr);
  strcat(outputTopicBuff, relaybuffer);
  client.publish(outputTopicBuff, state);
  Serial.println("\npinstate changed:");
  Serial.println(pinNbr);
  Serial.println(state);
}

void motionDetected(int pinNr, int OnOff) { 
  // PIR sensors are not active during turnOnAllLights and turnOnLightNightPee features
  if (turnOnAllLightsTimestamp == 0 && turnOnLightsForNightPeeTimestamp == 0) {
    switch(pinNr) {
      case 15: //PIR sensor1
        if(defDisablePIR1 == 0 && overridePIR[0] == 0) {
          if(OnOff == 0) {
            timerPIR1 = millis();
          } else {
            if(digitalRead(relayPins[10]) == LOW) { //Pin31 is the belonging relay, whose position in array is 10
              switchRelay('1', 10);
              timerPIR1 = 0;
            }
          }
        }
      break;
      case 16: //PIR sensor2
        if(defDisablePIR2 == 0 && overridePIR[1] == 0) {
          if(OnOff == 0) {
            timerPIR2 = millis();
          } else {
            if(digitalRead(relayPins[9]) == LOW) { //Pin30 is the belonging relay, whose position in array is 9
              switchRelay('1', 9);
              timerPIR2 = 0;
            }
          }
        }
      break;
      case 17: //PIR sensor3
        if(defDisablePIR3 == 0 && overridePIR[2] == 0) {
          if(OnOff == 0) {
            timerPIR3 = millis();
          } else {
            if(digitalRead(relayPins[8]) == LOW) { //Pin29 is the belonging relay, whose position in array is 8
              switchRelay('1', 8);
              timerPIR3 = 0;
            }
          }
        }
      break;
      case 56: //PIR sensor4
        if(defDisablePIR4 == 0 && overridePIR[3] == 0) {
          if(OnOff == 0) {
            timerPIR4 = millis();
          } else {
            if(digitalRead(relayPins[2]) == LOW) { //Pin23 is the belonging relay, whose position in array is 8
              switchRelay('1', 2);
              timerPIR4 = 0;
            }
          }
        }
      break;
    }
  }
}

void checkPIRTimersAndTurnOffRelayIfNecessary() { 
    if (((timerPIR1 != 0) && (timerPIR1 + defTimerPIR1Ms < millis()) && (overridePIR[0] == 0)) || // timer expired after motion sensor went to OFF
         (overridePIR[0] !=0 && overridePIR[0] + defOverridePIRTimeoutMin * 60000 < millis())) { // override PIR sensor is activated, but timeout reached -> turning OFF light
      //turn OFF relay
      switchRelay('0', 10);
      timerPIR1 = 0;
      overridePIR[0] = 0;
    } else if (((timerPIR2 != 0) && (timerPIR2 + defTimerPIR2Ms < millis()) && (overridePIR[1] == 0)) || // timer expired after motion sensor went to OFF
         (overridePIR[1] !=0 && overridePIR[1] + defOverridePIRTimeoutMin * 60000 < millis())) { // override PIR sensor is activated, but timeout reached -> turning OFF light
      //turn OFF relay
      switchRelay('0', 9);
      timerPIR2 = 0;
      overridePIR[1] = 0;
    } else if (((timerPIR3 != 0) && (timerPIR3 + defTimerPIR3Ms < millis()) && (overridePIR[2] == 0)) || // timer expired after motion sensor went to OFF
         (overridePIR[2] !=0 && overridePIR[2] + defOverridePIRTimeoutMin * 60000 < millis())) { // override PIR sensor is activated, but timeout reached -> turning OFF light
      //turn OFF relay
      switchRelay('0', 8);
      timerPIR3 = 0;
      overridePIR[2] = 0;
    } else if (((timerPIR4 != 0) && (timerPIR4 + defTimerPIR4Ms < millis()) && (overridePIR[3] == 0)) || // timer expired after motion sensor went to OFF
         (overridePIR[3] !=0 && overridePIR[3] + defOverridePIRTimeoutMin * 60000 < millis())) { // override PIR sensor is activated, but timeout reached -> turning OFF light
      //turn OFF relay
      switchRelay('0', 2);
      timerPIR4 = 0;
      overridePIR[3] = 0;
    }
}

void checkAndHandleShutterPosition() {
  int shutter1Pos = 0;
  int shutter2Pos = 0;
//CHECK SHUTTER1
  if(Shutter1Direction == 1 && Shutter1OperationTimeMs + 1000 < millis()) { // send position update every second   
    Shutter1OperationTimeMs = millis() - Shutter1OperationTimeMs;
    Shutter1PosTimeMs = Shutter1PosTimeMs + Shutter1OperationTimeMs;
    
    if(Shutter1PosTimeMs >= (defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs)) {// check if max position reached
      // max position reached - STOP shutter
      digitalWrite(SHUTTER1UPPIN, LOW);
      Shutter1PosTimeMs = defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs;
      Shutter1Direction = 10;
      //publish STOP
      publishShutterDir(1, 0);
    }
    shutter1Pos = Shutter1PosTimeMs * 100 / (defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs);
    publishShutterPos(1, shutter1Pos);
    Shutter1OperationTimeMs = millis();
  } else if (Shutter1Direction == 2 && Shutter1OperationTimeMs + 1000 < millis()) {
    Shutter1OperationTimeMs = millis() - Shutter1OperationTimeMs;
    Shutter1PosTimeMs = Shutter1PosTimeMs - Shutter1OperationTimeMs;
    
    if(Shutter1PosTimeMs <= 0) {// check if min position reached
      // min position reached - STOP shutter
      digitalWrite(SHUTTER1DOWNPIN, LOW);
      Shutter1PosTimeMs = 0;
      Shutter1Direction = 20;
      //publish STOP
      publishShutterDir(1, 0);
    }
    shutter1Pos = Shutter1PosTimeMs * 100 / (defShutter1OpenCloseDurationMs + defShutter1MotorStartDurationMs);
    publishShutterPos(1, shutter1Pos);   
    Shutter1OperationTimeMs = millis();
  }

// CHECK SHUTTER2
  if(Shutter2Direction == 1 && Shutter2OperationTimeMs + 1000 < millis()) {
    Shutter2OperationTimeMs = millis() - Shutter2OperationTimeMs;
    Shutter2PosTimeMs = Shutter2PosTimeMs + Shutter2OperationTimeMs;
    
    if(Shutter2PosTimeMs >= (defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs)) {// check if max position reached
      // max position reached - STOP shutter
      digitalWrite(SHUTTER2UPPIN, LOW);
      Shutter2PosTimeMs = defShutter2OpenCloseDurationMs;
      Shutter2Direction = 10;
      //publish STOP
      publishShutterDir(2, 0);
    }
    shutter2Pos = Shutter2PosTimeMs * 100 / (defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs);
    publishShutterPos(2, shutter2Pos);
    Shutter2OperationTimeMs = millis();  
  } else if (Shutter2Direction == 2 && Shutter2OperationTimeMs + 1000 < millis()) {
    Shutter2OperationTimeMs = millis() - Shutter2OperationTimeMs;
    Shutter2PosTimeMs = Shutter2PosTimeMs - Shutter2OperationTimeMs;
    
    if(Shutter2PosTimeMs <= 0) {// check if min position reached
      // min position reached - STOP shutter
      digitalWrite(SHUTTER2DOWNPIN, LOW);
      Shutter2PosTimeMs = 0;
      Shutter2Direction = 20;
      //publish STOP
      publishShutterDir(2, 0);
    }
    shutter2Pos = Shutter2PosTimeMs * 100 / (defShutter2OpenCloseDurationMs + defShutter2MotorStartDurationMs);
    publishShutterPos(2, shutter2Pos); 
    Shutter2OperationTimeMs = millis();      
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  int relayNumber;
  int posInArray;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  Serial.println("\nLength: " + (String)length);
  String topicString = String(topic);
  if (topicString.length() >= 20 && topicString.startsWith("cmnd/arduinomega/DEF")) {
// set default values!
    setDefaultValues(payload, length);
  } else if (topicString.length() >= 27 && topicString.startsWith("cmnd/arduinomega/DAYORNIGHT")) {
    String payloadStr = String((char*)payload);
    if(payloadStr.startsWith("DAY")) {
      dayOrNight = "DAY";
    } else {
      dayOrNight = "NIGHT";
    }
    Serial.println("dayOrNight new value: " + dayOrNight);
  }  else if (topicString.length() >= 25 && topicString.startsWith("cmnd/arduinomega/SHUTTER")) {
    if(topicString.charAt(24) == '1') { //SHUTTER1
      //String payloadStr = String((char*)payload);
      //if(payloadStr.startsWith("0")) {
      if(payload[0] == '0') {
        Serial.println("\nShutter1 command STOP executing...");
        shutterControl(SHUTTER1UPSWITCH, 0); 
        shutterControl(SHUTTER1DOWNSWITCH, 0);   
      //} else if(payloadStr.startsWith("1")) {
      } else if(payload[0] == '1') {
        Serial.println("\nShutter1 command UP executing...");
        shutterControl(SHUTTER1UPSWITCH, 1); 
      //} else if(payloadStr.startsWith("2")) {
      } else if(payload[0] == '2') {
        Serial.println("\nShutter1 command DOWN executing...");
        shutterControl(SHUTTER1DOWNSWITCH, 1); 
      }
    } else if (topicString.charAt(24) == '2') { //SHUTTER2
      if(payload[0] == '0') {
        Serial.println("\nShutter2 command STOP executing...");
        shutterControl(SHUTTER2UPSWITCH, 0);
        shutterControl(SHUTTER2DOWNSWITCH, 0);  
      //} else if(payloadStr.startsWith("1")) {
      } else if(payload[0] == '1') {
        Serial.println("\nShutter2 command UP executing...");
        shutterControl(SHUTTER2UPSWITCH, 1); 
      //} else if(payloadStr.startsWith("2")) {
      } else if(payload[0] == '2') {
        Serial.println("\nShutter2 command DOWN executing...");
        shutterControl(SHUTTER2DOWNSWITCH, 1); 
      }    
    }
  } else if (topicString.length() >= 22 && topicString.startsWith("cmnd/arduinomega/POWER")) {
    relayNumber = topicString.substring(22).toInt();
    posInArray = relayNumber - 1;
    Serial.println(posInArray, DEC);
    char* switchState = (char)payload[0];
    if (switchState == '2') {
      if (relayStates[posInArray] == HIGH) {
        switchState = '0';
      } else {
        switchState = '1';
      }
    }

    switchRelay(switchState, posInArray);
    if (switchState == '1') {
      doSwitch = true;
    }
  } else if (topicString.length() >= 22 && topicString.startsWith("cmnd/arduinomega/RESTART")) {
    char* switchState = (char)payload[0];
    if (switchState == '1') {
      // RESTART ARDUINO
      asm volatile ( "jmp 0");
    }
  } else if (topicString.length() >= 26 && topicString.startsWith("cmnd/arduinomega/GETCONFIG")) {
    char outstr[150];
    sprintf(outstr, " defTimeoutStateChangeCounterMs: %d;"
                    " defNumStateChangeDisableEnablePIRs: %d;"
                    " defNumStateChangeTurnOnAll: %d;"
                    " defNumStateChangeTurnOffAll: %d;"
                    " defNumStateChangeControlShutter: %d;"
                    " defNumStateChangeStayTurnedONOrNightPee: %d;"
                    " defTimerTurnOnAllLightsMs: %d;"
                    " defTimerTurnOnLightsForNightPeeMs: %d;"
                    " defOverridePIRTimeoutMin: %d;"
                    " defDisablePIR1: %d;"
                    " defDisablePIR2: %d;"
                    " defDisablePIR3: %d;"
                    " defDisablePIR4: %d;"
                    " defTimerPIR1Ms: %d;"
                    " defTimerPIR2Ms: %d;"
                    " defTimerPIR3Ms: %d;"
                    " defTimerPIR4Ms: %d;"
                    " defDelayRainSensorMs: %d;"
                    " defDelayTempSensorMs: %d;"
                    " defDelayTimerClosetLEDMs: %d;"
                    " defRainSensorTresholdValue: %d;"
                    " defShutter1OpenCloseDurationMs: %d;"
                    " defShutter2OpenCloseDurationMs: %d;"
                    " defShutter1MotorStartDurationMs: %d"
                    " defShutter2MotorStartDurationMs: %d"
                    " defStairsTurnOnClosetShelfLights: %d;"
                    " defWardrobeTurnOnClosetShelfLights: %d;"
                    " defTimerTurnOffLightDuringDayMin: %d;"
                    " defDisableEnablePIRs: %d;"
                    " dayOrNight: %s;", defTimeoutStateChangeCounterMs, defNumStateChangeDisableEnablePIRs, defNumStateChangeTurnOnAll, defNumStateChangeTurnOffAll, defNumStateChangeControlShutter,
                              defNumStateChangeStayTurnedONOrNightPee, defOverridePIRTimeoutMin, defDisablePIR1, defDisablePIR2, defDisablePIR3, defDisablePIR4, defTimerPIR1Ms, defTimerPIR2Ms,
                              defTimerPIR3Ms, defTimerPIR4Ms, defDelayRainSensorMs, defDelayTempSensorMs, defDelayTimerClosetLEDMs, defRainSensorTresholdValue, defShutter1OpenCloseDurationMs,
                              defShutter2OpenCloseDurationMs, defShutter1MotorStartDurationMs, defShutter2MotorStartDurationMs, defStairsTurnOnClosetShelfLights, defWardrobeTurnOnClosetShelfLights, defTimerTurnOffLightDuringDayMin, defDisableEnablePIRs, dayOrNight);
    for(int i = 0; i < pinCount; i++) {
      if(excludedRelays[i] == false) {
        sprintf(outstr, " excludedRelays[%d]: false;");
      } else {
        sprintf(outstr, " excludedRelays[%d]: true;");
      }
    }
    sprintf(outstr, '\0');
    client.publish("stat/arduinomega/CONFIG", outstr);
//bool excludedRelays[pinCount] = {};

  }
}


void reconnect() {
  Serial.println("\nTrying to connect to MQTT...");
  if (client.connect("XXX", "YYY", "ZZZ")) {
    Serial.println("connected");
    client.subscribe(inTopic);
    delay(100);
    client.subscribe(inShutterCmndTopic);
    delay(100);
    client.publish(outTopic, "ON");
    digitalWrite(13, HIGH);
    publishPinStates();
    //delay(100);
    //client.subscribe(inTopic2);
    MQTTFailedConnectTime = 0;
  } else {
    Serial.print("failed, rc=");
    Serial.print(client.state());
     digitalWrite(13, LOW);
     delay(500);
      digitalWrite(13, HIGH);
      delay(500);
      digitalWrite(13, LOW);
  }
}

void printRelayStates() {
  Serial.print("\nPin states:");
  for (int i = 0; i < pinCount; i++) {
    Serial.print(relayPins[i]);
    Serial.print(": ");
    Serial.print(relayStates[i], DEC);
    Serial.print(",");
    Serial.print(digitalRead(relayPins[i]));
    Serial.print("; ");
  }
  Serial.print("\n");
}

void printTemperature(DHT sensor, char const * topic)
{
    float temp = sensor.readTemperature();
    float hum  = sensor.readHumidity();

    if(isnan(temp)) {
      Serial.println("Failed to read temperature from DHT sensor!");
    return;
    }

    if(isnan(hum)) {
      Serial.println("Failed to read humidity from DHT sensor!");
      return;
    }
    

    Serial.print(" temperature: ");
    Serial.print(temp);
    Serial.print(" Celsius,\t humidity: ");
    Serial.print(hum);
    Serial.println(" %");

    char temp_char[5]; 
    char hum_char[5];

    dtostrf(temp, 2, 1, temp_char);
    temp_char[4]='\0';
    dtostrf(hum, 2, 1, hum_char);
    hum_char[4]='\0';

    char outstr[150];
    sprintf(outstr, "{\"AM2301\":{\"Temperature\":%s,\"Humidity\":%s},\"TempUnit\":\"C\"}", temp_char, hum_char);
    client.publish(topic, outstr);
}


void setup() { 
  client.setBufferSize(2048); //PubSubClient change max length of message
  initCounter = 0; 
  expCnt1 = 0;
  expCnt2 = 0;
  expCnt3 = 0;
  
 
// add default values
  excludedRelays[7] = true;  //by default exclude: 8th element, which is D28 pin, which is guest room
  excludedRelays[11] = true; //                    12th element, which is D32 pin -> wardrobe LED1
  excludedRelays[12] = true; //                    13th element, D33 -> wardrobe LED2
  excludedRelays[13] = true; //                    14th element, D34 -> bedroom closet LED

  nightPeeRelays[8] = true;
  nightPeeRelays[9] = true;
  nightPeeRelays[10] = true;
  
  Serial.begin(115200);

  for (int thisPin = 0; thisPin < pinCount; thisPin++) {
    digitalWrite(relayPins[thisPin], LOW);
    pinMode(relayPins[thisPin], OUTPUT);
  }

  //manually initialize shutter relays as well...
  digitalWrite(SHUTTER1UPPIN, LOW);
  pinMode(SHUTTER1UPPIN, OUTPUT);
  digitalWrite(SHUTTER1DOWNPIN, LOW);
  pinMode(SHUTTER1DOWNPIN, OUTPUT);

  digitalWrite(SHUTTER2UPPIN, LOW);
  pinMode(SHUTTER2UPPIN, OUTPUT);
  digitalWrite(SHUTTER2DOWNPIN, LOW);
  pinMode(SHUTTER2DOWNPIN, OUTPUT);
  
  //init state relayboard
  //turnAllOff();
  delayTimers();
  //input
  pinMode(PIN_DETECT_6, INPUT_PULLUP);
  pinMode(PIN_DETECT_7, INPUT_PULLUP);
  pinMode(PIN_DETECT_8, INPUT_PULLUP);
  pinMode(PIN_DETECT_9, INPUT_PULLUP);
  pinMode(PIN_DETECT_44, INPUT_PULLUP);
  pinMode(PIN_DETECT_11, INPUT_PULLUP);
  pinMode(PIN_DETECT_12, INPUT_PULLUP);
  pinMode(PIN_DETECT_57, INPUT_PULLUP);
  pinMode(PIN_DETECT_14, INPUT_PULLUP);
  pinMode(PIN_DETECT_15, INPUT_PULLUP);
  pinMode(PIN_DETECT_16, INPUT_PULLUP);
  pinMode(PIN_DETECT_17, INPUT_PULLUP);
  pinMode(PIN_DETECT_18, INPUT_PULLUP);
  pinMode(PIN_DETECT_19, INPUT_PULLUP);
  pinMode(PIN_DETECT_20, INPUT_PULLUP);
   pinMode(PIN_DETECT_45, INPUT_PULLUP);
   pinMode(PIN_DETECT_46, INPUT_PULLUP);
   pinMode(PIN_DETECT_47, INPUT_PULLUP);
   pinMode(PIN_DETECT_48, INPUT_PULLUP);
   pinMode(PIN_DETECT_40, INPUT_PULLUP);
   pinMode(PIN_DETECT_41, INPUT_PULLUP);
   pinMode(PIN_DETECT_42, INPUT_PULLUP);
   pinMode(PIN_DETECT_55, INPUT_PULLUP);
   pinMode(PIN_DETECT_56, INPUT_PULLUP);
   pinMode(PIN_DETECT_43, INPUT_PULLUP);
   pinMode(PIN_DETECT_54, INPUT_PULLUP);
   pinMode(PIN_DETECT_64, INPUT_PULLUP);
   pinMode(PIN_DETECT_65, INPUT_PULLUP);
   pinMode(PIN_DETECT_66, INPUT_PULLUP);
   pinMode(PIN_DETECT_67, INPUT_PULLUP);
   pinMode(PIN_DETECT_68, INPUT_PULLUP);
  // -------------------------------------
  debounce6.attach(PIN_DETECT_6);
  debounce7.attach(PIN_DETECT_7);
  debounce8.attach(PIN_DETECT_8);
  debounce9.attach(PIN_DETECT_9);
  debounce44.attach(PIN_DETECT_44);
  debounce11.attach(PIN_DETECT_11);
  debounce12.attach(PIN_DETECT_12);
  debounce57.attach(PIN_DETECT_57);
  debounce14.attach(PIN_DETECT_14);
  debounce15.attach(PIN_DETECT_15);
  debounce16.attach(PIN_DETECT_16);
  debounce17.attach(PIN_DETECT_17);
  debounce18.attach(PIN_DETECT_18);
  debounce19.attach(PIN_DETECT_19);
  debounce20.attach(PIN_DETECT_20);
  debounce45.attach(PIN_DETECT_45);
  debounce46.attach(PIN_DETECT_46);
  debounce47.attach(PIN_DETECT_47);
  debounce48.attach(PIN_DETECT_48);
  debounce40.attach(PIN_DETECT_40);
  debounce41.attach(PIN_DETECT_41);
  debounce42.attach(PIN_DETECT_42);
  debounce55.attach(PIN_DETECT_55);
  debounce56.attach(PIN_DETECT_56);  
  debounce43.attach(PIN_DETECT_43);
  debounce64.attach(PIN_DETECT_64);
  debounce65.attach(PIN_DETECT_65);  
  debounce66.attach(PIN_DETECT_66);
  debounce67.attach(PIN_DETECT_67);  
  debounce68.attach(PIN_DETECT_68);

  // -----------------------------------
  debounce6.interval(50);
  debounce7.interval(50);
  debounce8.interval(50);
  debounce9.interval(50);
  debounce44.interval(50);
  debounce11.interval(50);
  debounce12.interval(50);
  debounce57.interval(50);
  debounce14.interval(50);
  debounce15.interval(50);
  debounce16.interval(50);
  debounce17.interval(50);
  debounce18.interval(50);
  debounce19.interval(50);
  debounce20.interval(50);
  debounce45.interval(50); 
  debounce46.interval(50); 
  debounce47.interval(50); 
  debounce48.interval(50); 
  debounce40.interval(50); 
  debounce41.interval(50); 
  debounce42.interval(50); 
  debounce55.interval(50);
  debounce56.interval(50);
  debounce43.interval(50); 
  debounce64.interval(50);
  debounce65.interval(50); 
  debounce66.interval(50);
  debounce67.interval(50); 
  debounce68.interval(50);
  // ------------------------------------ 
  setup_ethernet();
  client.setServer(server, 1883);
  client.setCallback(callback);
  dht1.begin();
  dht2.begin();
  dht3.begin();
  dht4.begin();
  dht5.begin();
  dht6.begin();

  memset(overridePIR, 0, PIRCount*sizeof(int));
}

void loop() {
  //if(initCounter == 0) {
    //during first run init the relay states
  //  turnOffAllLights();
  //  initCounter++;
  //}
  
  // try to reconnect 3times 2seconds apart, and retry this sequence after 30seconds
  if ((!client.connected()) && ((MQTTFailedConnectTime + 30000 < millis()) || (millis()< 30000 && counter != -1) || counter > 0)) { 
    if(counter < 4){
     reconnect();
     counter = counter +1; 
    } else { 
      if(millis() < 30000){
        counter = -1;
      } else{
        counter = 0; 
      }
      MQTTFailedConnectTime = millis();
    }
  }

  checkTimeoutAndExecute();
  checkAndHandleShutterPosition();
  if ((turnOnAllLightsTimestamp != 0) && (turnOnAllLightsTimestamp + defTimerTurnOnAllLightsMs < millis())) {
  // timer expired -> turn off lights that had been turned on with turnOnAllLights
    turnOffLights();
  } else if ((turnOnLightsForNightPeeTimestamp != 0) && (turnOnLightsForNightPeeTimestamp + defTimerTurnOnLightsForNightPeeMs < millis())) {
    turnOffLights();
  }

  checkPIRTimersAndTurnOffRelayIfNecessary();
  
  if (delay_tempsensor.isExpired()) {
    printRelayStates();
    for(int i = 1; i <= tempSensorCount; i++) {
       char outBuff[30];
      sprintf(outBuff, "%s%d", outSensorTopic, i);
   
      switch(i) {
        case 1: 
          printTemperature(dht1, outBuff);  
          break;
        case 2:
          printTemperature(dht2, outBuff);
          break;
        case 3: 
          printTemperature(dht3, outBuff);  
          break;
        case 4:
          printTemperature(dht4, outBuff);
          break;
        case 5:
          printTemperature(dht5, outBuff);
          break;
        case 6:
          printTemperature(dht6, outBuff);
          break;
      } 
    }
    delay_tempsensor.repeat();
  }

  debounce6.update(); //wardrobe LED white switch
  if ( debounce6.fell()){
    publishPinState(6, "OFF");
    toggleRelay(0); 
  } else if (debounce6.rose()) {
    publishPinState(6, "ON");
    toggleRelay(0); 
  }
  
  debounce7.update(); // wardrobe LED blue switch
  if ( debounce7.fell()){
    publishPinState(7, "OFF");
    toggleRelay(1); 
  } else if (debounce7.rose()) {
    publishPinState(7, "ON");
    toggleRelay(1); 
  }

  debounce8.update();
  if ( delay_closetLED1.isExpired() && expCnt1 == 0) {
    switchRelay('0', 11);
    expCnt1 = 1;
  } else if ( debounce8.rose()){
    publishPinState(8, "ON");
    switchRelay('1', 11);
    //delay_closetLED1.start(defDelayTimerClosetLEDMs, AsyncDelay::MILLIS);
    Serial.println(defDelayTimerClosetLEDMs, DEC);
    delay_closetLED1.start(defDelayTimerClosetLEDMs, AsyncDelay::MILLIS);
    expCnt1 = 0;
  } else if (debounce8.fell()) {
    publishPinState(8, "OFF");
    switchRelay('0', 11);
  }

  debounce9.update();
  if ( delay_closetLED2.isExpired() && expCnt2 == 0) {
    switchRelay('0', 12);
    expCnt2 = 1;
  } else if ( debounce9.rose()){
    publishPinState(9, "ON");
    switchRelay('1', 12);
    delay_closetLED2.start(defDelayTimerClosetLEDMs, AsyncDelay::MILLIS);
    expCnt2 = 0;
  } else if (debounce9.fell()) {
    publishPinState(9, "OFF");
    switchRelay('0', 12);
  }

  debounce44.update();
  if ( delay_closetLED3.isExpired() && expCnt3 == 0) {
    switchRelay('0', 13);
    expCnt3 = 1;
  } else if ( debounce44.rose()){
    publishPinState(44, "ON");
    switchRelay('1', 13);
    delay_closetLED3.start(defDelayTimerClosetLEDMs, AsyncDelay::MILLIS);
    expCnt3 = 0;
  } else if (debounce44.fell()) {
    publishPinState(44, "OFF");
    switchRelay('0', 13);
  }

  debounce11.update();
  if ( debounce11.fell()){
    publishPinState(11, "OFF");
  } else if (debounce11.rose()) {
    publishPinState(11, "ON");
  }

  debounce12.update();
  if ( debounce12.fell()){
    publishPinState(12, "OFF");
  } else if (debounce12.rose()) {
    publishPinState(12, "ON");
  }

  debounce57.update();
  if ( debounce57.fell()){
    publishPinState(57, "OFF");
  } else if (debounce57.rose()) {
    publishPinState(57, "ON");
  }

  debounce14.update();
  if ( debounce14.fell()){
    publishPinState(14, "OFF");
  } else if (debounce14.rose()) {
    publishPinState(14, "ON");
  }

  debounce15.update();
  if ( debounce15.fell()){
    publishPinState(15, "OFF");
    motionDetected(15, 0);
  } else if (debounce15.rose()) {
    publishPinState(15, "ON");
    motionDetected(15, 1);
  }

  debounce16.update();
  if ( debounce16.fell()){
    publishPinState(16, "OFF");
    motionDetected(16, 0);
  } else if (debounce16.rose()) {
    publishPinState(16, "ON");
    motionDetected(16, 1);
  }

  debounce17.update();
  if ( debounce17.fell()){
    publishPinState(17, "OFF");
    motionDetected(17, 0);
  } else if (debounce17.rose()) {
    publishPinState(17, "ON");
    motionDetected(17, 1);
  }

  debounce18.update();
  if ( debounce18.fell()){
    publishPinState(18, "OFF");
    handleToggle(0, 2);
  } else if (debounce18.rose()) {
    publishPinState(18, "ON");
    handleToggle(0, 2);
  }
  

  debounce19.update();
  if ( debounce19.fell()){
    publishPinState(19, "OFF");
    handleToggle(1, 3);
  } else if (debounce19.rose()) {
    publishPinState(19, "ON");
    handleToggle(1, 3);
  }

  debounce20.update();
  if ( debounce20.fell()){
    publishPinState(20, "OFF");
    handleToggle(2, 4);
  } else if (debounce20.rose()) {
    publishPinState(20, "ON");
    handleToggle(2, 4);
  }

  debounce45.update();
  if ( debounce45.fell()){
    publishPinState(45, "OFF");
    handleToggle(3, 5);
  } else if (debounce45.rose()) {
    publishPinState(45, "ON");
    handleToggle(3, 5);
  }

  debounce46.update();
  if ( debounce46.fell()){
    publishPinState(46, "OFF");
    handleToggle(4, 6);
  } else if (debounce46.rose()) {
    publishPinState(46, "ON");
    handleToggle(4, 6);
  }

  debounce47.update();
  if ( debounce47.fell()){
    publishPinState(47, "OFF");
    handleToggle(5, 7);
  } else if (debounce47.rose()) {
    publishPinState(47, "ON");
    handleToggle(5, 7);
  }

  debounce48.update();
  if ( debounce48.fell()){
    publishPinState(48, "OFF");
    handleToggle(6, 8);
  } else if (debounce48.rose()) {
    publishPinState(48, "ON");
    handleToggle(6, 8);
  }

  debounce40.update();
  if ( debounce40.fell()){
    publishPinState(40, "OFF");
    handleToggle(7, 9);
  } else if (debounce40.rose()) {
    publishPinState(40, "ON");
    handleToggle(7, 9);
  }

  debounce41.update();
  if ( debounce41.fell()){
    publishPinState(41, "OFF");
    handleToggle(7, 9);
  } else if (debounce41.rose()) {
    publishPinState(41, "ON");
    handleToggle(7, 9);
  }

  debounce42.update();
  if ( debounce42.fell()){
    publishPinState(42, "OFF");
    handleToggle(8, 10);
  } else if (debounce42.rose()) {
    publishPinState(42, "ON");
    handleToggle(8, 10);
  }

  debounce55.update(); //bedroom door sensor
  if ( debounce55.fell()){
    publishPinState(55, "OFF");
  } else if (debounce55.rose()) {
    publishPinState(55, "ON");
  }

  debounce56.update(); //wardrobe PIR
  if ( debounce56.fell()){
    publishPinState(56, "OFF");
    motionDetected(56, 0);
  } else if (debounce56.rose()) {
    publishPinState(56, "ON");
     motionDetected(56, 1);
  }
  
  debounce43.update();
  if ( debounce43.fell()){
    publishPinState(43, "OFF");
    handleToggle(8, 10);
  } else if (debounce43.rose()) {
    publishPinState(43, "ON");
    handleToggle(8, 10);
  }

//Shutter1Up 
  debounce64.update();
  if ( debounce64.fell()){
    publishPinState(64, "OFF");
  } else if (debounce64.rose()) {
    publishPinState(64, "ON");
    shutterControl(SHUTTER1UPSWITCH, 1);
  }

//Shutter1Down
  debounce65.update();
  if ( debounce65.fell()){
    publishPinState(65, "OFF");
  } else if (debounce65.rose()) {
    publishPinState(65, "ON");
    shutterControl(SHUTTER1DOWNSWITCH, 1);
  }

//Shutter2Up 
  debounce66.update();
  if ( debounce66.fell()){
    publishPinState(66, "OFF");
  } else if (debounce66.rose()) {
    publishPinState(66, "ON");
    shutterControl(SHUTTER2UPSWITCH, 1);
  }

//Shutter2Down
  debounce67.update();
  if ( debounce67.fell()){
    publishPinState(67, "OFF");
  } else if (debounce67.rose()) {
    publishPinState(67, "ON");
    shutterControl(SHUTTER2DOWNSWITCH, 1);
  }

// Custom switch, bound to nothing by default...
  debounce68.update();
  if ( debounce68.fell()){
    publishPinState(68, "OFF");
  } else if (debounce68.rose()) {
    publishPinState(68, "ON");
  }
  
// ---------------------------------
  if (delay_rainsensor.isExpired()) {
    int val = analogRead(54);
    char cstr[10];
    sprintf(cstr, "%d", val);
    
    char topic[30];
    char outstr[150];
    sprintf(topic, "%s%d", outSensorTopic, 6);
    Serial.print("\nRain sensor value:");
    Serial.print(val, DEC);
    if (val < defRainSensorTresholdValue ) {
      sprintf(outstr, "{\"RAIN_SENSOR\":{\"Value\":%d,\"Raining:\":ON}}", val);
      Serial.println(", Raining: ON");
    } else {
      sprintf(outstr, "{\"RAIN_SENSOR\":{\"Value\":%d,\"Raining:\":OFF}}", val);
      Serial.println(", Raining: OFF");
    }
    client.publish(topic, outstr);    
    delay_rainsensor.repeat();
  }
 
  client.loop();
}
1 Like

on a Mega the SPI pins are
50 (MISO), 51 (MOSI), 52 (SCK), 53 (SS).

10 might be the CS of your ethernet shield
4 might be the CS of the SD Card
See the description and datasheet of your ethernet shield.

I use W5100-R3.

The wiring diagram:

W5100-R3_EN_10041306.pdf (60,8 kB)

PIN4 is in use by a temperature sensor (DHT22). Should I avoid using that PIN?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.