[SOLVED] Button Widget Virtual Pin

I’m trying to do something really simple i’m sure but for some reason i can’t get the sketch to do what i want.

All i want to do is turn on and off the blue LED on my esp8266 board with a virtual pin. At the moment the only way i can get the button widget (V20) to work is to have another button widget (d4) added to the screen as well. As soon as i remove the buttin widget (d4) and reboot the board the button widget (v20) no longer works.

I also have a LED widget displaying the state of the dio pin

Any advice is much appreciated.

    #include <ESP8266mDNS.h>
    #include <WiFiUdp.h>
    #include <ArduinoOTA.h>
    #define BLYNK_PRINT Serial
    #include <ESP8266WiFi.h>
    #include <BlynkSimpleEsp8266.h>

    char auth[] = "**";


    // Replace with your network credentials
    char ssid[] = "***";
    char pass[] = "***";

    const int btnPin = 2; //esp8266 onboard blue LED

    WidgetLED led3(V3);

    BlynkTimer timer;

    BLYNK_CONNECTED() {
            Blynk.syncVirtual(V20);
    }
    // V3 LED Widget represents the physical button state
    boolean btnState = false;

    void buttonLedWidget()
    {
      // Read button
      boolean isPressed = (digitalRead(btnPin) == HIGH);

      // If state has changed...
      if (isPressed != btnState) {
        if (isPressed) {
          led3.off();
         Blynk.virtualWrite(V20, 0);
        } else {
          led3.on();
          Blynk.virtualWrite(V20, 1);
        }
        btnState = isPressed;
      }
    }

    BLYNK_WRITE(V20){

     if (param.asInt()){
         digitalWrite(btnPin, LOW); // lights on
       } 
      else {
      digitalWrite(btnPin, HIGH); // lights off
     }
     
    }



    void setup() {
      Serial.begin(115200);
      Blynk.begin(auth, ssid, pass);
      pinMode(btnPin, INPUT_PULLUP);
      ArduinoOTA.begin();
      

    }

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

A real simple way to do this is as follows:

BLYNK_WRITE(V20) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
} 

And your Virtual LED - on a timer, can be condensed like this:

void buttonLedWidget() {
  if  (digitalRead(btnPin) == HIGH) {  // Sets LED widget ON or OFF depending on state of btnpin
    led3.on();
  } else {
    led3.off();
  }
}

Then as you toggle the LED on and off with the virtual button, the timer routine will see the state change of the digital pin and reflect it accordingly via the virtual LED.

BTW, this is just one way… there are many, and you can even combine the button and LED functions into one, so no need of the timer.

And as for the pinMode() of your btnPin (the LED on pin 2), unless ESPs are radically different, I think it should be set as an OUTPUT.

1 Like

@Gunner thanks very much for your advice its very much appreciated. It’s working now. Cheers.

@Gunner do you know a way to improve the update of the Virtual Pin. Because there is a slight delay from when I press Button Widget to the actual activation of the digital pin (milliseconds) the button widget when pressed is instantly flicks to the reverse state until the digital pin has been activated then the button widget then remains in the correct state.

@GG07 you want faster than milliseconds? How many milliseconds is it at present, around 200 or 2000?

As the control is done via the internet there will always be some delay.

If it’s critical you can host the server at your location and that will reduce the response time a little but it’s overkill for most projects and more hardware for you to maintain.

#define BLYNK_PRINT Serial


#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


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

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

// Select your pin with physical button
const int btnPin = 4;

WidgetLED led3(V3);

BlynkTimer timer;

BLYNK_CONNECTED() {
    Blynk.syncAll();
}


void LedWidget() {
  if  (digitalRead(btnPin) == HIGH) {  // Sets LED widget ON or OFF depending on state of btnpin
    led3.on();
    
  } else {
    led3.off ();
    
  }
}

void ButtonWidget() {
  if  (digitalRead(btnPin) == HIGH) {  // Sets LED widget ON or OFF depending on state of btnpin
    
    Blynk.virtualWrite(V20, HIGH);
  } else {
    
    Blynk.virtualWrite(V20, LOW);
  }
}

BLYNK_WRITE(V20) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
}

BLYNK_WRITE(V21) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
}

BLYNK_WRITE(V22) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
}

BLYNK_WRITE(V23) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
}

BLYNK_WRITE(V24) {
digitalWrite(btnPin, param.asInt());  // Sets btnPin HIGH or LOW depending on state of Button Widget.
}

void setup()
{
  Serial.begin(115200);
  Blynk.begin(auth, ssid, pass);
  pinMode(btnPin, OUTPUT);
  timer.setInterval(1000L, LedWidget);
  timer.setInterval(1000L, ButtonWidget);
  ArduinoOTA.begin();
}

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

Is it possible to post Mp4 video somehow? I could show you exactly what is happening.

You can paste a YouTube link and it will embed the video in the post.

This is a link to google photos with the video

https://photos.app.goo.gl/YoT1JX6V0aBd61jl2

Watched the video and your issue is covered in the lines above.

IF speed is important change 1000L to 100L or even lower.

Ok cheers for that. I didn’t realise I could go as low as that. Will give it a go. Thanks again.

I think I read that Blynk modified the SimpleTimer and it will work down to about 12ms but that doesn’t mean you will see a response in 12ms due to “internet lag”. Depends where you are in relation to the Blynk servers around the world etc. Should be able to get it MCUH faster than you currently have.

Not sure I see the relevance though for a “beehive”. If the LED’s were used to start a Formula 1 race then go with a local server :slight_smile:

Ensure you stick well within the maximum 100 server requests per second as per http://docs.blynk.cc/#troubleshooting-flood-error

@GG07 Not sure if you have a reason for the separate timed functions, but you could reduce it to a single timer, calling a single function that would set both the LED and Button Widgets state:

// Note the function name change, associated timer needs to reflect same name change.
void LedButtonWidget() { 
  if  (digitalRead(btnPin) == HIGH) {  // Sets LED widget ON or OFF depending on state of btnpin
    led3.on();
    Blynk.virtualWrite(V20, HIGH);
  } else {
    led3.off ();
    Blynk.virtualWrite(V20, LOW);
  }
}

Ok thanks @Costas & @Gunner for your advice so quickly too. Great stuff.

Make sure you’ve set your button widget in a switch mode.

Timers are good to keep widgets updated if your pin can be physically affected. But when the pin is affected in your code, you don’t have to wait for a timer callback.

Obviously, you also should keep widget state in your code to avoid networking overload issues.

So, your code may look like this:

const int btnPin = 4;
int btnState = LOW;

void updateButtonWidgetIfNeeded() {
  int newBtnState = digitalRead(btnPin);
  if (btnState != newBtnState) {
    btnState = newBtnState;
    Blynk.virtualWrite(V20, btnState);
  }
}
// ..
BLYNK_WRITE(V21) {
    digitalWrite(btnPin, param.asInt());
    updateButtonWidgetIfNeeded();
}
// ..
timer.setInterval(1000L, updateButtonWidgetIfNeeded);

That’s awesome thanks very much for your advice @Eugene and @Gunner.