(HARD) Controlling 2 relays with a momentary switch AND a latching switch

6v6gt:
So it appears to be a single pole, double throw switch.

The top Terminal is connected to pin 6
The middle terminal (common) is wired to 5 volts
The bottom Terminal is connected to pin 7

Pin 6 and pin 7 have pull down resistors (say 10k)

A press on the bottom part of the rocker has the effect that pin 7 is momentarily pulled HIGH.
It reverts to a middle position on release, where neither pin 6 nor pin 7 is connected to HIGH.

A single press on the top part of the rocker latches and holds pin 6 HIGH.
A second press on the top part of the rocker unlatches it neither pin 6 nor pin 7 is connected to HIGH.

Is that it ?

That's correct. Just an FYI, the rocker position affect the opposite terminal at the back of the rocker (Up feeds bottom terminal and vice versa) I use step down modules from 12v to 5v to pin 6-7. I don't have a setup connected to ground with a resistor like the typical pushbutton exercise.

Ok. It seems to be getting clearer. Can you show a wiring diagram which includes at least the switch, the step down modules (two buck converters?) , the Arduino and the relays.

So I guess if the top part of the rocker switch is already in the latched position (your wife has used the quick “all lights ON mode”) then any momentary press to the bottom part of the rocker switch will break the latch first.

Multiple continuous presses of the top part of the switch (latch / unlatch cycle) have the effect that first lights are ON, then further presses have no effect. That is, any transition on pin 6 (low to high, high to low) has the effect that all lights are forced ON.

I’m also guessing that the rocker switch breaks before it makes, that is that at no time are all contacts connected together.

Edit
——
Post crossed with @sherzaad

arduihome21:
Hello, thank you for reading this.
I've been working on this project for 2 months and was hoping to finalize it this weekend. I just need this bit of code to push this through.

Hardware
Arduino Uno
2 High Voltage Relay Connected to LED Flood Lights
1 Rocker Switch Triggers WHEN HIGH & N/O (LOW) .:

  • Rocking up is a latching contact (N/O LOW)
  • Rocking down is a momentary (N/O LOW)

I am a seasoned electrician.
I have two flood lights controlled by two high voltage relays. I am using a rocker switch the one used for ships with a fuse. They run on 12v. I have all the step-down hooked up to feed only 5v. to my Arduino Uno control pins 6 & 7.

Goals:
Momentary Rocker Position Function Pin 7:
1st click -Close Relay 1 ONLY
2nd click -Close Relay 2 ONLY
3rd click -Close Relay 1 & 2
4th click -Open Relay 1 & 2 (both lights off)
2 fast clicks -Open Relay 1 & 2 at any point in the loop (both lights off)

Latching Rocker Position Function Pin 6:

When HIGH -Close Relay 1 & 2 | AND IMPORTANT Reset Pin 7 State Logic
When LOW -Close Relay 1 & 2 | AND IMPORTANT Reset Pin 7 State Logic

HERE IS THE PROBLEM
The code below is for a typical Arduino board momentary push button (Normally HIGH when Closed) only connected to Pin 7

Current Hardware differences:
Rocker Switch (N/O LOW) with the Momentary position connected to Pin 7 and Latching position (N/O LOW) connected to Pin 6.

I call on someone to simplify this code for the above mentioned hardware.
Note: this code was designed for 3 lights with a push button N/C.

It seems to me using interrupt-on-change would make things so much simpler...

something like this maybe...

(compiles, NOT tested!)

/*
  Momentary Rocker Position Function Pin 7:
  1st click   -Close Relay 1 ONLY
  2nd click  -Close Relay 2 ONLY
  3rd click   -Close Relay 1 & 2
  4th click   -Open Relay 1 & 2 (both lights off)
  2 fast clicks -Open Relay 1 & 2 at any point in the loop (both lights off)

  Latching Rocker Position Function Pin 6:
  When HIGH -Close Relay 1 & 2
  When LOW - Do nothing
*/

// Pin assignement WORKING FRONT LIGHTS
#define latchPin 6
#define togglePin 7
#define led1Pin 8
#define led2Pin 9
#define led3Pin 10

//timings
#define InPulse 300 //300ms
#define PulseInterval 1000 //1000ms

enum fcnMode {
  OFF,
  LED1,
  LED2,
  ALL,
  NBSTATE
}; // OFF = 0 and NBSTATE=4

unsigned long previousMillis, interval, pulse;
uint8_t funcState = 0, input_7 = LOW;

// Use pcint ISR for each group (UNO)
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{

}

ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{

}

ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
  uint8_t input = digitalRead(togglePin);

  if (input == LOW) {
    //HIGH->LOW change. calculate interval time
    interval = previousMillis - millis();
    previousMillis = millis();
  }
  else {
    //LOW->HIGH change. calculate pulse time  (low instead of HIGH as using input pullups here)
    pulse = previousMillis - millis();
    previousMillis = millis();
  }

  //toggle swich was operated
  if (pulse >= InPulse) {
    if (interval < PulseInterval) {
      //2 fast clicks - Open Relay 1 & 2 at any point in the loop (both lights off)
      funcState = 0;
    }
    else {
      //move along state machine
      funcState = funcState % NBSTATE;
    }
  }

}

//Pin change interrupt for a pin, can be called multiple times
void pciSetup(byte pin)
{
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

void setup() {
  //initialise serial comms
  Serial.begin(115200);
  // set pullups, if necessary
  pinMode(latchPin, INPUT_PULLUP);
  pinMode(togglePin, INPUT_PULLUP);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(led3Pin, OUTPUT);

  //set up interrupt-on-change pins
  //pciSetup(latchPin);
  pciSetup(togglePin);

  //initialise variable
  previousMillis = millis();
}


void loop() {
  Serial.print("Function : ");
  Serial.println(funcState);

  if (digitalRead(latchPin) == LOW) {
    //LOW -Close Relay 1 & 2 (low instead of HIGH as using input pullups here)
    funcState = 3;
  }

  //set mode
  switch (funcState) {
    //1st click   -Close Relay 1 ONLY
    case LED1:
      digitalWrite(led1Pin, HIGH);
    break;

    //2nd click  -Close Relay 2 ONLY
    case LED2:
      digitalWrite(led2Pin, HIGH);
    break;

    //3rd click   -Close Relay 1 & 2
    case ALL:
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, HIGH);
      digitalWrite(led3Pin, HIGH);
    break;

    //4th click   -Open Relay 1 & 2 (both lights off)
    case OFF:
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      digitalWrite(led3Pin, LOW);
    break;
  }
}

hope that helps....

Thinking about it some more, although that rocker switch can be made to work for this application, it would have probably been better to have used three separate push to make switches (normal push buttons) labelled:

ALL LIGHTS ON
ALL LIGHTS OFF
EXPERT

6v6gt:
Can you show a wiring diagram which includes at least the switch, the step down modules (two buck converters?) , the Arduino and the relays.

Here is the diagram attached.

sherzaad:
It seems to me using interrupt-on-change would make things so much simpler...

something like this maybe...

(compiles, NOT tested!)

/*

Momentary Rocker Position Function Pin 7:
1st click -Close Relay 1 ONLY
2nd click -Close Relay 2 ONLY
3rd click -Close Relay 1 & 2
4th click -Open Relay 1 & 2 (both lights off)
2 fast clicks -Open Relay 1 & 2 at any point in the loop (both lights off)

Latching Rocker Position Function Pin 6:
When HIGH -Close Relay 1 & 2
When LOW - Do nothing
*/

// Pin assignement WORKING FRONT LIGHTS
#define latchPin 6
#define togglePin 7
#define led1Pin 8
#define led2Pin 9
#define led3Pin 10

//timings
#define InPulse 300 //300ms
#define PulseInterval 1000 //1000ms

enum fcnMode {
OFF,
LED1,
LED2,
ALL,
NBSTATE
}; // OFF = 0 and NBSTATE=4

unsigned long previousMillis, interval, pulse;
uint8_t funcState = 0, input_7 = LOW;

// Use pcint ISR for each group (UNO)
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{

}

ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{

}

ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
uint8_t input = digitalRead(togglePin);

if (input == LOW) {
//HIGH->LOW change. calculate interval time
interval = previousMillis - millis();
previousMillis = millis();
}
else {
//LOW->HIGH change. calculate pulse time (low instead of HIGH as using input pullups here)
pulse = previousMillis - millis();
previousMillis = millis();
}

//toggle swich was operated
if (pulse >= InPulse) {
if (interval < PulseInterval) {
//2 fast clicks - Open Relay 1 & 2 at any point in the loop (both lights off)
funcState = 0;
}
else {
//move along state machine
funcState = funcState % NBSTATE;
}
}

}

//Pin change interrupt for a pin, can be called multiple times
void pciSetup(byte pin)
{
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

void setup() {
//initialise serial comms
Serial.begin(115200);
// set pullups, if necessary
pinMode(latchPin, INPUT_PULLUP);
pinMode(togglePin, INPUT_PULLUP);
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
pinMode(led3Pin, OUTPUT);

//set up interrupt-on-change pins
//pciSetup(latchPin);
pciSetup(togglePin);

//initialise variable
previousMillis = millis();
}

void loop() {
Serial.print("Function : ");
Serial.println(funcState);

if (digitalRead(latchPin) == LOW) {
//LOW -Close Relay 1 & 2 (low instead of HIGH as using input pullups here)
funcState = 3;
}

//set mode
switch (funcState) {
//1st click -Close Relay 1 ONLY
case LED1:
digitalWrite(led1Pin, HIGH);
break;

//2nd click  -Close Relay 2 ONLY
case LED2:
  digitalWrite(led2Pin, HIGH);
break;

//3rd click   -Close Relay 1 & 2
case ALL:
  digitalWrite(led1Pin, HIGH);
  digitalWrite(led2Pin, HIGH);
  digitalWrite(led3Pin, HIGH);
break;

//4th click   -Open Relay 1 & 2 (both lights off)
case OFF:
  digitalWrite(led1Pin, LOW);
  digitalWrite(led2Pin, LOW);
  digitalWrite(led3Pin, LOW);
break;

}
}




hope that helps....

I had no luck with this code.
Results are as follow.

Latching is firing from Pin6 when engaged. Somewhat unstable; will not fire everytime and seem to require a delay to reset.

Momentary state login at Pin 7 does not engage any relays.

See picture. Ignore the breadboard pushbutton and crimping cable colors. Ran out of colors for crimp and rocker terminal connections.

OK. I am getting the feel for the complexity of the project.
I'm already impressed by the number of voltage converters you have integrated into the design.
It looks like you are switching a 12 volt signal derived from an HLK-PM12 module and using buck converters to condition those signals for input into an Arduino Uno. This is rather an unusual arrangement, but I might have missed something about that switch you are using. Does that switch (Seaflow bilge pump) have any requirement for a 12volt supply (illumination or some other function) ? Even so, there may be simpler methods for providing the necessary 5 volt signals for the Uno, for example a resistor divider network.

I'm guessing that those who have supplied you with code to try underestimated the hardware setup.

Just to repeat the question, is there any particular reason that the Seaflow switch should be supplied with 12 volts ?

Edit


I think I may have answered my own question from: SEAFLO 3-Way Marine Boat Electric Switch Panel Used with Floating Switch for Protection from China
It appears to have specified 12 or 24volts at least for the illumination.

6v6gt:
Is there any particular reason that the Seaflow switch should be supplied with 12 volts ?

You got it. It runs on 12v. I buck both positions to 5v. I have to do that since they go in different Pins.
Is idling on HIGH and triggering on LOW with a pull resistor is safer for the Arduino?

arduihome21:
You got it. It runs on 12v. I buck both positions to 5v. I have to do that since they go in different Pins.
Is idling on HIGH and triggering on LOW with a pull resistor is safer for the Arduino?

I would have done it like this for the connection between the switch and the arduino. It uses two simple voltage dividers instead of two buck converters. I've made some assumptions about the internal working of that switch and its internal light but, anyway, you connect +12v, ground, 1 and 2 to it. Important with the voltage dividers is that the ground is good (soldered is better than a breadboard connection) to prevent 12 volts appearing on an arduino pin. It will also work with the buck converters as you have it but that is a rather heavy weight solution. Ensure also that they are adjusted for the correct output voltage.

You've indicated Wemos relay shields but the relay modules in the picture appear to be other models. Are you going to move the whole thing to Wemos in the future ? If you are migrating to a 3.3 volt system, it would be good to plan which voltages you are going to standardise on to minimise the number of power supplies.

6v6gt:
Important with the voltage dividers is that the ground is good (soldered is better than a breadboard connection) to prevent 12 volts appearing on an arduino pin.

Thanks for that. It's already a big learning curve for me without the resistor calculation so I decided to go with the buck. Of course this will all be tidied up without the breadboard once we have the code.

You've indicated Wemos relay shields but the relay modules...

Was just a generic relay that I picked for the drawing in Fritzing. My relay runs on 5v.

Once I have the code, I'll just need a box for my wife to reach the latching switch...

Well, as far as the code goes, you now have two offers of a solution so I will not interfere there unless you are abandoned.

Best would be if the person providing the solution tests a simple model of it. The rocker switch can be simulated by a push button and a jumper. The jumper simulates the latch and has to be disconnected before the push button is pressed to simulate the breaking of the latch when the momentary side of the rocker is pressed.

Once I have the code, I'll just need a box for my wife to reach the latching switch...

mount it a bit lower ?

6v6gt:
mount it a bit lower ?

Nah... she's fine. :slight_smile:

arduihome21:
I had no luck with this code...

I did not expect it to work 'OK' tbh. I share that as a draft code to get you going. What was missing was some debounce logic!

Had some time and found this an interesting challenge, so got working on it with some LEDs, a push switch and a slide switch and got the logic you wanted working! 8)

here's the code:

/*
  Momentary Rocker Position Function Pin 7:
  1st click   -Close Relay 1 ONLY
  2nd click  -Close Relay 2 ONLY
  3rd click   -Close Relay 1 & 2
  4th click   -Open Relay 1 & 2 (both lights off)
  2 fast clicks -Open Relay 1 & 2 at any point in the loop (both lights off)

  Latching Rocker Position Function Pin 6:
  When HIGH -Close Relay 1 & 2
  When LOW - Do nothing
*/

// Pin assignement WORKING FRONT LIGHTS
#define latchPin 6
#define togglePin 7
#define led1Pin 8
#define led2Pin 9
#define led3Pin 10

//timings
#define InPulse 100 //200ms (reaction time -debounce time)
#define PulseInterval 1000 //1000ms (maximum 'fast clicks') 

enum fcnMode {
  OFF,
  LED1,
  LED2,
  ALL,
  NBSTATE
}; // OFF = 0 and NBSTATE=4

unsigned long startPulse, startInterval, interval, pulse;
uint8_t funcState = 0, input_7 = LOW;
volatile uint8_t in_temp;

// Use pcint ISR for each group (UNO)
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{

}

ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{

}

ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
  in_temp = digitalRead(togglePin);
}
//-----------------------------------

//Pin change interrupt for a pin, can be called multiple times
void pciSetup(byte pin)
{
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

void setup() {
  //initialise serial comms
  Serial.begin(115200);
  // set pullups, if necessary
  pinMode(latchPin, INPUT_PULLUP);
  pinMode(togglePin, INPUT_PULLUP);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(led3Pin, OUTPUT);

  //set up interrupt-on-change pins
  //pciSetup(latchPin);
  pciSetup(togglePin);

  //initialise variable
  startPulse = millis();
  startInterval = millis();
}


void loop() {
  //Serial.print("Function : ");
  //Serial.println(funcState);

  if (digitalRead(latchPin) == LOW) {
    //LOW -Close Relay 1 & 2 (low instead of HIGH as using input pullups here)
    funcState = NBSTATE - 1;
  }
  else if (input_7 != in_temp) {//check last toggle pin read value against current value
    delay(100); //acts as debounce delay
    if (digitalRead(togglePin) == in_temp) {//debounce check. toggle pin read still same as initial read
      input_7 = in_temp;

      if (input_7 == LOW) {
        //HIGH->LOW change.
        startPulse = millis(); //start pulse timer
      }
      else {
        //LOW->HIGH change. calculate pulse time  (low instead of HIGH as using input pullups here)
        pulse = millis() - startPulse;
        //toggle swich was operated
        if (pulse >= InPulse) {
          //Serial.println("toggle!");
          interval = millis() - startInterval; //calculate interval time since last pulse
          startInterval = millis(); //start Interval timer
          if (interval < PulseInterval) {
            //2 fast clicks - Open Relay 1 & 2 at any point in the loop (both lights off)
            funcState = 0;
          }
          else {
            //move along state machine
            funcState = (funcState + 1) % NBSTATE;
          }

        }
      }
    }
  }

  //set mode
  switch (funcState) {
    //1st click   -Close Relay 1 ONLY
    case LED1:
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, LOW);
    break;

    //2nd click  -Close Relay 2 ONLY
    case LED2:
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, HIGH);
    break;

    //3rd click   -Close Relay 1 & 2
    case ALL:
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, HIGH);
      digitalWrite(led3Pin, HIGH);
    break;

    //4th click   -Open Relay 1 & 2 (both lights off)
    case OFF:
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      digitalWrite(led3Pin, LOW);
    break;
  }
}

Note that in my code I am using the internal pullup resistors for the inputs ie the inputs are switched to ground
Latch/Toggle ON -> logic LOW
Latch/Toggle OFF -> logic HIGH

There isnt much that needs changing to make the above code work with the opposite logic, so give it a go! :wink:

I would wire the inputs to the arduino as suggested in reply #28 if I were you.

FYI as level shifter you can use voltage-dividers,OP-AMPs or logic gates but DC-DC converter IMHO are a poor choice for this purpose.

hope that helps....

6v6gt:
I would have done it like this for the connection between the switch and the arduino. It uses two simple voltage dividers instead of two buck converters.

Can you provide your calculation I believe you have to be using Ohm's law. That will get me over the fence hopefully for next time. Thanks

The rules for a voltage divider are quite simple. In this case, it is to provide a logic level for input to a 5 volt Microcontroller pin from a 12 volt source.
So 5/12 (read five twelfths) of the total voltage is spread from ground to the pin and the remaining 7/12 is spread between the pin and the 12 volt source.
The other consideration is that, in this case, about 1mA would be a reasonable current so I chose a total resistance of 12k ohms also to make the calculation easier. That is the Ohms Law part of it.
5/12 of 12k is 5k
7/12 of 12k is 7k
To be on the safe side I chose the nearest lower standard resistor value for the bottom resistor and the nearest higher standard for the top resistor.
But also Google for “voltage divider calculator” and you get a few hits.

sherzaad:
Note that in my code I am using the internal pullup resistors for the inputs ie the inputs are switched to ground
Latch/Toggle ON -> logic LOW
Latch/Toggle OFF -> logic HIGH

There isnt much that needs changing to make the above code work with the opposite logic, so give it a go! :wink:

I would wire the inputs to the arduino as suggested in reply #28 if I were you.

FYI as level shifter you can use voltage-dividers,OP-AMPs or logic gates but DC-DC converter IMHO are a poor choice for this purpose.

hope that helps....

Hi Sherzaad, I loaded up the code and nothing happens. I am confused, the code seems to be okay but you mention that this need to be edited for the opposite logic to work. I am unsure to what needs to be edited because this seems to be the correct code. Let me know.

/*
  Momentary Rocker Position Function Pin 7:
  1st click   -Close Relay 1 ONLY
  2nd click  -Close Relay 2 ONLY
  3rd click   -Close Relay 1 & 2
  4th click   -Open Relay 1 & 2 (both lights off)
  2 fast clicks -Open Relay 1 & 2 at any point in the loop (both lights off)

  Latching Rocker Position Function Pin 6:
  When HIGH -Close Relay 1 & 2
  When LOW - Do nothing
*/

// Pin assignement WORKING FRONT LIGHTS
#define latchPin 6
#define togglePin 7
#define led1Pin 8
#define led2Pin 9
#define led3Pin 10

//timings
#define InPulse 100 //200ms (reaction time -debounce time)
#define PulseInterval 1000 //1000ms (maximum 'fast clicks')

enum fcnMode {
  OFF,
  LED1,
  LED2,
  ALL,
  NBSTATE
}; // OFF = 0 and NBSTATE=4

unsigned long startPulse, startInterval, interval, pulse;
uint8_t funcState = 0, input_7 = LOW;
volatile uint8_t in_temp;

// Use pcint ISR for each group (UNO)
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{

}

ISR (PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{

}

ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
  in_temp = digitalRead(togglePin);
}
//-----------------------------------

//Pin change interrupt for a pin, can be called multiple times
void pciSetup(byte pin)
{
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

void setup() {
  //initialise serial comms
  Serial.begin(115200);
  // set pullups, if necessary
  pinMode(latchPin, INPUT_PULLUP);
  pinMode(togglePin, INPUT_PULLUP);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(led3Pin, OUTPUT);

  //set up interrupt-on-change pins
  //pciSetup(latchPin);
  pciSetup(togglePin);

  //initialise variable
  startPulse = millis();
  startInterval = millis();
}


void loop() {
  //Serial.print("Function : ");
  //Serial.println(funcState);

  if (digitalRead(latchPin) == LOW) {
    //LOW -Close Relay 1 & 2 (low instead of HIGH as using input pullups here)
    funcState = NBSTATE - 1;
  }
  else if (input_7 != in_temp) {//check last toggle pin read value against current value
    delay(100); //acts as debounce delay
    if (digitalRead(togglePin) == in_temp) {//debounce check. toggle pin read still same as initial read
      input_7 = in_temp;

      if (input_7 == LOW) {
        //HIGH->LOW change.
        startPulse = millis(); //start pulse timer
      }
      else {
        //LOW->HIGH change. calculate pulse time  (low instead of HIGH as using input pullups here)
        pulse = millis() - startPulse;
        //toggle swich was operated
        if (pulse >= InPulse) {
          //Serial.println("toggle!");
          interval = millis() - startInterval; //calculate interval time since last pulse
          startInterval = millis(); //start Interval timer
          if (interval < PulseInterval) {
            //2 fast clicks - Open Relay 1 & 2 at any point in the loop (both lights off)
            funcState = 0;
          }
          else {
            //move along state machine
            funcState = (funcState + 1) % NBSTATE;
          }

        }
      }
    }
  }

  //set mode
  switch (funcState) {
    //1st click   -Close Relay 1 ONLY
    case LED1:
      digitalWrite(led1Pin, HIGH);
    break;

    //2nd click  -Close Relay 2 ONLY
    case LED2:
      digitalWrite(led2Pin, HIGH);
    break;

    //3rd click   -Close Relay 1 & 2
    case ALL:
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, HIGH);
      digitalWrite(led3Pin, HIGH);
    break;

    //4th click   -Open Relay 1 & 2 (both lights off)
    case OFF:
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
      digitalWrite(led3Pin, LOW);
    break;
  }
}

you been given various versions of code based on your description of the hardware and what you want it to do

you need to study the code and understand why it doesn't work. maybe your descriptions have a problem

arduihome21:
Hi Sherzaad, I loaded up the code and nothing happens. I am confused, the code seems to be okay but you mention that this need to be edited for the opposite logic to work. I am unsure to what needs to be edited because this seems to be the correct code. Let me know.

I have a serial monitor loop in these two last version of codes. It just keeps running these characters.

18:26:05.768 -> Function : 0
18:26:05.768 -> Function : 0
18:26:05.768 -> Function : 0
o⸮⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i⸮@⸮i
Function : 0
18:26:22.329 -> Function : 3
18:26:22.329 -> Function : 3

arduihome21:
Hi Sherzaad, I loaded up the code and nothing happens. I am confused, the code seems to be okay but you mention that this need to be edited for the opposite logic to work. I am unsure to what needs to be edited because this seems to be the correct code. Let me know.

Of course it won't!
with your current setup, the pin would never see a LOW and therefore not trigger.
So, either you change the way the inputs are read (ie do not used INPUT_PULLUP)
OR
you could use transistors/optocoupler.
To use them I would re-wire circuit in reply #28 as follows. It should then be just plug and play, in theory at least!

PS: in my original code I commented out the serial prints for a reason. they do mess with the code operation I found.

sherzaad:
You change the way the inputs are read (ie do not used INPUT_PULLUP)

Thanks for that. I thought you'd left something out intentionally as well for educational purposes.

My understanding is that we currently have a PULLUP in my design not the opposite. Why isn't this code working. I think I can't understand your comments in the code.

  pinMode(latchPin, INPUT_PULLUP);
  pinMode(togglePin, INPUT_PULLUP);
  if (digitalRead(latchPin) == LOW) {
    //LOW -Close Relay 1 & 2 (low instead of HIGH as using input pullups here)
    funcState = NBSTATE - 1;
  }
  else if (input_7 != in_temp) {//check last toggle pin read value against current value
    delay(100); //acts as debounce delay
    if (digitalRead(togglePin) == in_temp) {//debounce check. toggle pin read still same as initial read
      input_7 = in_temp;

      if (input_7 == LOW) {
        //HIGH->LOW change.
        startPulse = millis(); //start pulse timer
      }
      else {
        //LOW->HIGH change. calculate pulse time  (low instead of HIGH as using input pullups here)
        pulse = millis() - startPulse;
        //toggle swich was operated
        if (pulse >= InPulse) {
          //Serial.println("toggle!");
          interval = millis() - startInterval; //calculate interval time since last pulse
          startInterval = millis(); //start Interval timer
          if (interval < PulseInterval) {
            //2 fast clicks - Open Relay 1 & 2 at any point in the loop (both lights off)
            funcState = 0;
          }