How to use 1 way switch instead of push switches in Home Automation project

I am making a Home Automation project with blynk and manual switching with feedback. I want to use a 1-way switch instead of push switch to make this work. This is the switch.
6-amp-1-way-switch-28n-3-29-500x500
My code is working with push switch but I want to use this 1-way switch. My code is here:

#define BLYNK_PRINT Serial            
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266mDNS.h>  // For OTA with ESP8266
#include <WiFiUdp.h>  // For OTA
#include <ArduinoOTA.h>  // For OTA

BlynkTimer timer;

void checkPhysicalButton();

int relay1State = LOW;
int pushButton1State = HIGH;

int relay2State = LOW;
int pushButton2State = HIGH;

int relay3State = LOW;
int pushButton3State = HIGH;

int relay4State = LOW;
int pushButton4State = HIGH;

#define AUTH "AuthToken"  // You should get Auth Token in the Blynk App.  
#define WIFI_SSID "SSID"                   //Enter Wifi Name
#define WIFI_PASS "Pass"                   //Enter wifi Password

#define SERVER "blynk-cloud.com "             // Comment-out if use Blynk hosted cloud service
#define PORT 8442

#define RELAY_PIN_1      12   //D6
#define RELAY_PIN_2      16   //D0
#define RELAY_PIN_3       4   //D2
#define RELAY_PIN_4       5   //D1 

#define PUSH_BUTTON_1     2   //D4
#define PUSH_BUTTON_2    14   //D5
#define PUSH_BUTTON_3    13   //D7
#define PUSH_BUTTON_4     1   //TX

#define VPIN_BUTTON_1    V12 
#define VPIN_BUTTON_2    V13
#define VPIN_BUTTON_3    V14
#define VPIN_BUTTON_4    V15  

#define OTA_HOSTNAME "Home_Automation"


BLYNK_CONNECTED() {

  // Request the latest state from the server

  Blynk.syncVirtual(VPIN_BUTTON_1);
  Blynk.syncVirtual(VPIN_BUTTON_2);
   Blynk.syncVirtual(VPIN_BUTTON_3);
  Blynk.syncVirtual(VPIN_BUTTON_4);

  // Alternatively, you could override server state using:
 // Blynk.virtualWrite(VPIN_BUTTON_1, relay1State);
 // Blynk.virtualWrite(VPIN_BUTTON_2, relay2State);
 // Blynk.virtualWrite(VPIN_BUTTON_3, relay3State);
 // Blynk.virtualWrite(VPIN_BUTTON_4, relay4State);

}

// When App button is pushed - switch the state

BLYNK_WRITE(VPIN_BUTTON_1) {
  relay1State = param.asInt();
  digitalWrite(RELAY_PIN_1, relay1State);
}

BLYNK_WRITE(VPIN_BUTTON_2) {
  relay2State = param.asInt();
  digitalWrite(RELAY_PIN_2, relay2State);
}
BLYNK_WRITE(VPIN_BUTTON_3) {
  relay3State = param.asInt();
  digitalWrite(RELAY_PIN_3, relay3State);
}
BLYNK_WRITE(VPIN_BUTTON_4) {
  relay4State = param.asInt();
  digitalWrite(RELAY_PIN_4, relay4State);
}

void checkPhysicalButton()
{
  if (digitalRead(PUSH_BUTTON_1) == LOW) {
    // pushButton1State is used to avoid sequential toggles
    if (pushButton1State != LOW) {

      // Toggle Relay state
      relay1State = !relay1State;
      digitalWrite(RELAY_PIN_1, relay1State);

      // Update Button Widget
      Blynk.virtualWrite(VPIN_BUTTON_1, relay1State);
    }
    pushButton1State = LOW;
  } else {
    pushButton1State = HIGH;
  }

  if (digitalRead(PUSH_BUTTON_2) == LOW) {
    // pushButton2State is used to avoid sequential toggles
    if (pushButton2State != LOW) {

      // Toggle Relay state
      relay2State = !relay2State;
      digitalWrite(RELAY_PIN_2, relay2State);

      // Update Button Widget
      Blynk.virtualWrite(VPIN_BUTTON_2, relay2State);
    }
    pushButton2State = LOW;
  } else {
    pushButton2State = HIGH;
  }

  if (digitalRead(PUSH_BUTTON_3) == LOW) {
    // pushButton3State is used to avoid sequential toggles
    if (pushButton3State != LOW) {

      // Toggle Relay state
      relay3State = !relay3State;
      digitalWrite(RELAY_PIN_3, relay3State);

      // Update Button Widget
      Blynk.virtualWrite(VPIN_BUTTON_3, relay3State);
    }
    pushButton3State = LOW;
  } else {
    pushButton3State = HIGH;
  }

  if (digitalRead(PUSH_BUTTON_4) == LOW) {
    // pushButton4State is used to avoid sequential toggles
    if (pushButton4State != LOW) {

      // Toggle Relay state
      relay4State = !relay4State;
      digitalWrite(RELAY_PIN_4, relay4State);

      // Update Button Widget
      Blynk.virtualWrite(VPIN_BUTTON_4, relay4State);
    }
    pushButton4State = LOW;
  } else {
    pushButton4State = HIGH;
  }
}

void setup()
{

  Serial.begin(115200);
  Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS,"blynk-cloud.com", 8442);
  ArduinoOTA.setHostname(OTA_HOSTNAME);  // For OTA - Use your own device identifying name
  ArduinoOTA.begin();  // For OTA

  pinMode(RELAY_PIN_1, OUTPUT);
  pinMode(PUSH_BUTTON_1, INPUT_PULLUP);
  digitalWrite(RELAY_PIN_1, relay1State);


  pinMode(RELAY_PIN_2, OUTPUT);
  pinMode(PUSH_BUTTON_2, INPUT_PULLUP);
  digitalWrite(RELAY_PIN_2, relay2State);


  pinMode(RELAY_PIN_3, OUTPUT);
  pinMode(PUSH_BUTTON_3, INPUT_PULLUP);
  digitalWrite(RELAY_PIN_3, relay3State);


  pinMode(RELAY_PIN_4, OUTPUT);
  pinMode(PUSH_BUTTON_4, INPUT_PULLUP);
  digitalWrite(RELAY_PIN_4, relay4State);

  // Setup a function to be called every 100 ms
  timer.setInterval(500L, checkPhysicalButton);
}

void loop()
{
  Blynk.run();
  ArduinoOTA.handle();  // For OTA
  timer.run();
}

Help me for this. Which function show be used ?

Do you mean the simple switch to turn ON/OFF lights in our houses? Ok to using Blynk as switch state feedback, but I donā€™t understand how you could control relays both from the app and from the physical 1-way switch. Am I missing something?
If you want to use a 1-way switch, you will not have an ON and an OFF state but a change of state at each exchange of the switch position.

DG

1 Like

Check out the code. I am using push switches to high the relay as well as the Blynk app to switch on/off. But itā€™s working only with push switch but I want to add the 1 way switch in this project. Check out this diagram for more reference:

Hope you understand my concern now.

Letā€™s take an example. You press the switch and relay 1 goes HIGH. Then turn off the relay via the application. If you press the switch to the new position, what do you want to happen?

DG

1 Like

It should again switch on.

I think YOU will need to come up with some clever coding to handle these types of scenarios. Have you even tried? Or are you hoping someone will just write the code for you?

Ok, so you donā€™t want ON and OFF in a fixed position of the switch. To get what you want I would do so:

void checkPhysicalButton()
{
    int State = digitalRead(PUSH_BUTTON_1);
    if (State != oldState) {
        oldState = State;
        relay1State = !relay1State;
        digitalWrite(RELAY_PIN_1, relay1State);
        Blynk.virtualWrite(VPIN_BUTTON_1, relay1State);
    }
    ... and so on...
1 Like

Yeah Iā€™m trying my level best but Iā€™m a beginner and I canā€™t find any solution for this. Thatā€™s why I am asking for help if you have any suggestion then you can give or else thank you for just over-viewing my project.

Thank you, let me try and revert back to you soon. Thanks for your effort.

There is a very simple solution.
Use a CHANGE interrupt.

Pete.

1 Like

what i can understand is he is trying to turn on the appliance from the normal switch and later we turn it on off via the app it should not matter, when we toggle the switch it should turn on of off knowing the previous state. Like the SONOFF do. They get connected to the normal switches, Obviously the switch state(position) will confuse whether it is on or off as it will not change its position by itself when we use the app to turn on or off.

lets say GPIO will get connected to GND(from switch) and it will trigger the appliance. later turn off the device from app.

Now when the switch is again pressed the GPIO will float and now the appliance must turn back on,

This is what i can understand by his explanationā€¦

But doing so may put few pins floating and few connected to GNDā€¦ This may affect the ESP while booting during a power failure.

Just to elaborate on what I said before about using interrupts, hereā€™s a more in-depth explanation about what I think the possible solutions are (hopefully Iā€™m understanding the question correctly.

The current code scans the pushbutton every 500ms (quite a long delay)

timer.setInterval(500L, checkPhysicalButton);

and then has some debounce code, which is probably redundant with 500ms scans of the button state:

  if (digitalRead(PUSH_BUTTON_3) == LOW) {
    // pushButton3State is used to avoid sequential toggles
    if (pushButton3State != LOW) {

      // Toggle Relay state
      relay3State = !relay3State;
      digitalWrite(RELAY_PIN_3, relay3State);

      // Update Button Widget
      Blynk.virtualWrite(VPIN_BUTTON_3, relay3State);
    }
    pushButton3State = LOW;
  } else {
    pushButton3State = HIGH;
  }

This same approach could be used with a toggle switch rather than a pushbutton, but would require a flag to store the previous state of the switch and a check to see when that state has changed. If the current state is not equal to the previous state the the switch has been flipped and the various processes such as toggling the relay and updating the corresponding button in the Blynk app need to be called.

The other way is to attach an interrupt to the pin that the toggle switch is connected to, and set it as a CHANGE type. Whenever the switch changes state (the pin switches from HIGH to LOW or LOW to HIGH then the interrupt will be triggered.
This definitely does need some debounce code and this code needs to incorporate a timer to ensure that a certain period of time has elapsed between interrupts (100ms maybe?). When you declare the interrupt you need to specify which function will be called when the interrupt is triggered. This is the function that will contain the debounce code, and which will call the processes that toggle the relay and update the button widget in Blynk.

There are some rules about using interrupts that arenā€™t documented very well (or at all in some cases) in the standard Arduino code documentation:

  • Variables that change within the function that is called when the interrupt is triggered (known as the Interrupt Service Routine or ISR) must be declared as volatile
  • The name of the ISR must include the ICACHE_RAM_ATTR attribute, like this: void ICACHE_RAM_ATTR your_function_name()
  • The ISR function must be before the void setup() or you must pre-declare the ISR function name at the top of your code like this void ICACHE_RAM_ATTR your_function_name(); This is known as a Forward Declaration.
  • Your ISR code must be ā€˜lean and meanā€™, doing just the bare minimum and avoiding thinks like serial prints wherever possible.

Whichever approach is used, the pinmode declaration for the pin that has the switch attached to it should include a PULLIP parameter, so the pin doesnā€™t float at a voltage that is neither HIGH or LOW.

Pete.

1 Like

Is this correct ? Because it is working only for one time which is switching it on but can switch off.

void checkPhysicalButton()
{
   if (digitalRead(PUSH_BUTTON_1) == LOW) {
    if (State1 != oldState1) {
        oldState1 = State1;
        relay1State = !relay1State;
        digitalWrite(RELAY_PIN_1, relay1State);
        Blynk.virtualWrite(VPIN_BUTTON_1, relay1State);
    }
    pushButton1State = LOW;
   } else {
    pushButton1State = HIGH;
   }  
   
if (digitalRead(PUSH_BUTTON_2) == LOW) {
    if (State2 != oldState2) {
        oldState2 = State2;
        relay2State = !relay2State;
        digitalWrite(RELAY_PIN_2, relay2State);
        Blynk.virtualWrite(VPIN_BUTTON_2, relay2State);
    }
    pushButton2State = LOW;
  } else {
    pushButton2State = HIGH;
  }
    
if (digitalRead(PUSH_BUTTON_3) == LOW) {
    if (State3 != oldState3) {
        oldState3 = State3;
        relay3State = !relay3State;
        digitalWrite(RELAY_PIN_3, relay3State);
        Blynk.virtualWrite(VPIN_BUTTON_3, relay3State);
        }
    pushButton3State = LOW;
  } else {
    pushButton3State = HIGH;
  }

  if (digitalRead(PUSH_BUTTON_4) == LOW) {
    if (State4 != oldState4) {
        oldState4 = State4;
        relay4State = !relay4State;
        digitalWrite(RELAY_PIN_4, relay1State);
        Blynk.virtualWrite(VPIN_BUTTON_4, relay4State);
        }
    pushButton4State = LOW;
  } else {
    pushButton4State = HIGH;
  }
}

Check and suggest change. Thank you in advance.

Obviously we will have the input pullup in the pinmodeā€¦ What i meant was say we have 4 switches there are plenty of permutation like (during the boot) all pins may be low, all pins may be left floating(input pullup), or any one or two or three may be connected to GNDā€¦ I feel these may stop the device from booting properly. If we are using GPIO0 then its definitely going into programming more, so we should not use it.

Two questions:

  1. why do you evaluate the switch status only if it is low?
  2. what is the functionality of State1(2,3,4) that you use in the code?

I try to answer the 2 questions:

  1. with 1-way switches you cannot evaluate a single state of the switch but you must evaluate the change of state;
  2. the code you posted cannot work. You have to remove the old code you used with push buttons. In my example code I used the State variable that ā€œcontainedā€ the state of the switch input to check the change of state.
void checkPhysicalButton()
{
    int State = digitalRead(PUSH_BUTTON_1); //"State" containes the logical level of the switch
    if (State != oldState) { //Change of the input state? Yes if I change the switch position
        oldState = State; //in order to be ready for a new change of state
        relay1State = !relay1State;
        digitalWrite(RELAY_PIN_1, relay1State);
        Blynk.virtualWrite(VPIN_BUTTON_1, relay1State);
    }
    ... and so on...

So, in my opinion, you donā€™t need pushButton1State.

P.S.: as @PeteKnight said, a 500ms check interval is quite long. Reduce it.
If you donā€™t like this procedure, you can try to implement the @PeteKnight solution: CHANGE Interrupt: itā€™s smarter, but probably a little more complex.

DG

3 Likes

The code is working fine. Thank you. But I have a question Do I have to debounce the switches or just reducing check interval will be ok ?

You only need to denounce if you are using the interrupt routine.

If you are just checking the state every 100ms you maybe fine. If you get unwanted triggers play with the ā€œcheckingā€ interval.

1 Like

I agree with @daveblynk. I think that debounce functions are more useful for push buttons as they are mechanically more subject to this problem. About 100 ms is a correct time interval.

DG

1 Like

Can you show us what are you upto with the code ? It can be helpful for others or we can improve it if neededā€¦

EDIT

After seeing this post i took 4 toggle switches(Normal wall switches) and connected one terminal to GND and other to VCC via a 10k resistor. And connected the point between VCC and 10k resistor to the input pin of the nodemcu.
Uploaded the sketch it works fine. later when i restart the nodemcu it wont boot, as few pins will be high and few will be low. While experimenting i burnt up my (ESP12F on a breakout board). Now i after reboot it will go into programming mode. GPIO0 is shorted i guess. So it works fine only after uploading the code, after reboot it will ask to upload a new program.
input pins D1 D4 D6 D7. output D2 D0 D5 D8. (WORKS FINE WITH PUSH BUTTON)

Is there any fault in the circuit ??

Not all pins are ment to be used the way you want to. Google ā€œesp8266 usable pinsā€