Check Physical Button State

Hi all,

Used the sketch builder and modified to write this script which checks if a physical push button has been pressed and changed both the widget in the app (switch mode) and toggles the output state of the relay.

There are two push buttons and relays involved. It is part of a bigger project.

After vigorous testing and troubleshooting, I have no idea why I can’t get this to work! Pressing the push button does not do anything.

    /*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  WARNING!
    It's rather tricky to get it working, please read this article:
    https://github.com/blynkkk/blynk-library/wiki/ESP8266-with-AT-firmware

  This example shows how to synchronize Button widget
  and physical button state.

      App project setup:
        Button widget attached to V2 (Switch mode)
     *************************************************************/

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


    #include <ESP8266_Lib.h>
    #include <BlynkSimpleShieldEsp8266.h>

    // You should get Auth Token in the Blynk App.
    // Go to the Project Settings (nut icon).
    char auth[] = "Token";

    // Your WiFi credentials.
    // Set password to "" for open networks.
    char ssid[] = "Shed";
    char pass[] = "shed01";

    // Hardware Serial on Mega, Leonardo, Micro...
    //#define EspSerial Serial1

    // or Software Serial on Uno, Nano...
    #include <SoftwareSerial.h>
    SoftwareSerial EspSerial(0, 1); // RX, TX

    // Your ESP8266 baud rate:
    #define ESP8266_BAUD 9600

    ESP8266 wifi(&EspSerial);

    // Set your LED and physical button pins here
    const int lampRly = 7;
    const int lampBtn = 9;
    const int ampRly = 12;
    const int ampBtn = 10;

    BlynkTimer timer;
    void checkPhysicalButton();

    int lampRlyState = HIGH;
    int lampBtnState = LOW;
    int ampRlyState = HIGH;
    int ampBtnState = LOW;

    // Every time we connect to the cloud...
    BLYNK_CONNECTED() {
      // Request the latest state from the server
      Blynk.syncVirtual(V0); // Lamp
      Blynk.syncVirtual(V1); // Amp
    }

    // When App button is pushed - switch the state
    BLYNK_WRITE(V0) {  // Lamp  
      lampRlyState = param.asInt();
      digitalWrite(lampRly, lampRlyState);
    }

    BLYNK_WRITE(V1) { // Amp
      ampRlyState = param.asInt();
      digitalWrite(ampRly, ampRlyState);
    }

    void checkPhysicalButton()
    {
      if (digitalRead(lampBtn) == HIGH) { // Lamp
        // btnState is used to avoid sequential toggles
       if (lampBtnState != LOW) {

          // Toggle Lamp state
          lampRlyState = !lampRlyState;
          digitalWrite(lampRly, lampRlyState);

          // Update Button Widget
          Blynk.virtualWrite(V0, lampRlyState);
        }
        lampBtnState = LOW;
      } else {
        lampBtnState = HIGH;
      }

      if (digitalRead(ampBtn) == LOW) { // Amp
        if(ampBtnState != HIGH) {

          // Toggle Amp state
          ampRlyState = !ampRlyState;
          digitalWrite(ampRly, ampRlyState);

          // Update button widget
          Blynk.virtualWrite(V1, ampRlyState);
        }
        ampBtnState = LOW;
      } else {
        ampBtnState = HIGH;
      }
    }

    void setup()
    {
      // Debug console
      Serial.begin(9600);

      // Set ESP8266 baud rate
      EspSerial.begin(ESP8266_BAUD);
      delay(10);

      Blynk.begin(auth, wifi, ssid, pass);

      pinMode(lampRly, OUTPUT);
      pinMode(lampBtn, INPUT);
      digitalWrite(lampRly, lampRlyState);
      
      pinMode(ampRly, OUTPUT);
      pinMode(ampBtn, INPUT);
      digitalWrite(ampRly, ampBtnState);

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

    void loop()
    {
      Blynk.run();
      timer.run();
    }

@Riley_Boon

Hi
I have similar experience from the app control entity switch. I suggest you check the problem step by step.
The problem you describe is Pressing the push button does not do anything.

First start by coding a single button to control the relay. Marked that the code is not necessary. This will help you find the problem. Finish and post your results

I wish you success.:slight_smile:

How have you wired your physical buttons?
From your code it looks like one side of lampBtn is connected to GPIO 9 (Pin SD2 on a NodeMCU), but what is the other side of the physical button connected to? Is it Ground or 3.3v?

Pete.

1 Like

I’m using a Nano rather than a NodeMCU. One side of the button is wired to 5v and the other side to D9 on the Arduino. There is also a pull-down resistor on the same pin as the button connected to ground. I have tried just the bare code and I can make the relay switch on while the button is being held in.

1 Like

What happens if you change this line:

Blynk.virtualWrite(V0, lampRlyState);

to this:

Blynk.virtualWrite(V0, !lampRlyState);

I have a feeling that because your switch is normally low, and your relay normally high, you’re sending the wrong status across to Blynk.

Pete.

1 Like

You must’ve read my mind. I was just going through the code and changed that line about half an hour ago. I won’t able to check that once I can get the physical button to work though

1 Like

Can somebody please explain what the following bit of code does, I don’t understand why there are two if functions… the code came from the sketch builder. I have a feeling this could be where the problem is.

    void checkPhysicalButton()
{
  if (digitalRead(lampBtn) == HIGH) { // Lamp
   if (lampBtnState != LOW) { // this section here

      // Toggle Lamp state
      lampRlyState = !lampRlyState;
      digitalWrite(lampRly, lampRlyState);

      // Update Button Widget
      Blynk.virtualWrite(V0, !lampRlyState);
    }
    lampBtnState = LOW;
  } else {
    lampBtnState = HIGH;
  }
1 Like

It’s a switch debounce function, I think.

Pete.

You would want to wire it with a pullup resistor, as the code is “looking” for a low as a button press. The resistor should go between the input pin and 5V, with the button wired between the input pin and ground. (This is for the original code) As your code has changed one of the routines to “look” for a HIGH, I guess this is why.

Depending on if your relay is active high or active low you may need to change your button widget to send a LOW on press as well.

The two IF functions are used to avoid having the relay turn on and off if the button is held. That is, one button press = one toggle of relay.

The lampBtnState flag goes LOW once the button is pressed, and it does not go HIGH again until the button is let go. The second IF function will not run unless lampBtnState is HIGH

The timer acts as the debounce, as it only looks for a button press once every .1 Seconds.

Which part of the code do I need to change if I want it to toggle the output state when the button is pulled high?

Either I’m going totally mad, or @Toro_Blanco is wrong.

I’m looking at this on an iPhone, which makes it a little tricky, but as I read it this is what’s happening…
lampBtnState is declared as LOW at the top of the code.
The first time void loop runs without the physical button pressed the else after the first of the nested if statements sets lampBtnState to HIGH.

When void loop runs with the button pressed (lampBtn = HIGH) the second of the nested if statements is true because lampBtnState is now HIGH (!LOW).

The rest of that second nested if statement is then executed, which I think is where it goes wrong.
The Lamp relay is toggled (set to low, to turn the lamp on.
The Blynk switch is set to the same state as the lamp relay (LOW) which turns the lamp off again immediately, which I think is where you’re going wrong.
lampBtnState I’d then set to LOW, so the code as to go through a full loop without the lamp tutor being presses before its set back to HIGH again.

I think that if you make the change I suggested earlier and set the Blynk widget switch to the opposite of the relay then it should work.

Pete.

Well this is how I see it. In reference to the original code on the sketch builder.

if (digitalRead(lampBtn) == LOW) checks to see if the pin (lampBtn) has been pulled LOW. In other words has the button been pressed.

if (lampBtnState != LOW) checks to see if the lanpBtnState flag is NOT LOW. Upon boot, lampBtnState is LOW, so if the button is held while booting, the function will stop at this point.

Once button is released (or if not held on boot), the first IF statement will not be true, so the lampBtnState flag will be set HIGH.

When the button is again pressed, the first and second IF statements will be true, so lampRlyState will be changed from its current state to the opposite lampRlyState = !lampRlyState; it will then change the state of the output on lampRlyPin to that of the new lampRlyState. digitalWrite(lampRly, lampRlyState); It then updates the state of the botton/switch widget Blynk.virtualWrite(V0, lampRlyState); and lastly changes lampBtnState flag to LOW lampBtnState = LOW;

When the button is released and pressed again, this process repeats, changing everthing to the opposite state it was before.

I think where you may be confused (or possibly me) is that this chunk of code does not get executed when the widget is updated, it only runs when the button on the widget is actually pressed in the app.

 BLYNK_WRITE(V0) {  // Lamp  
      lampRlyState = param.asInt();
      digitalWrite(lampRly, lampRlyState);
    }```

The changing of the switch widget to its opposite is only needed if your relay is active LOW, otherwise the relay will be off when the switch widget is on

I am fairly confident that the code in the sketch builder works. I have it running on two separate projects as we speak.

I have the button wired to use the built in pull-up resistor, and have changed to switch widget to output low when pressed as my relays are an active low.

We’re obviously talking about different code here, because nowhere in the code posted above is there any code that says
if (digitalRead(lampBtn) == LOW)

There is a line that says
if (digitalRead(ampBtn) == LOW)
but this is the ampBtn not lampBtn (confusing I know). Presumably one controls an amplifier and the other a light. I’ve been stepping-through the code for the light.

Pete.

As I had stated. My post was referring to the original code on the sketch builder. As this is where @Riley_Boon had stated he got it from. https://examples.blynk.cc/?board=ESP8266&shield=ESP8266%20WiFi&example=More%2FSync%2FSyncPhysicalButton

He had duplicated portions of the code to have it work with two different buttons, and also wanted it to work with a pin that is pulled LOW, and a button wired to 5V. He also modified some of the code in an attempt to make it function.

What I am saying is that the ORIGINAL CODE on sketch builder works just fine. The two IF loops are needed to keep the relay from toggling if the button is held for too long. It should be wired with the pin pulled HIGH with the internal pull-up resistor, and the momentary button should pull the pin LOW (to ground) when pressed. The relay should be active HIGH.

For an active LOW relay, no modifications to the code are needed, but you must switch the logic of the widget/switch to send a LOW when pressed.

With some very simple modifications to the code (not the way the OP did), it could be made to work with the pin pulled LOW with an external resistor, and having the momentary button hardwired to pull the pin HIGH.

Thank you @Toro_Blanco. I had modified the code in an attempt to get it working but must’ve changed some of the wrong things around.

I have duplicated the code to run with two push buttons and two relays, one for a lamp and one for an amplifier, it confuses me too!

The relays I have are active low. I have changed that function within the app. I am yet to get the app communicating with the project though as I am having other issues.

The buttons I have should pull the relays low when they are pressed in. They are wired to 5v, so should detect when they are pulled high, and they have external pull down resistors. Which portion of the original code as you stated do I need to modify to allow them to work with this?