Control Lights with Blynk and Physical Buttons

I found this code by searching here and it is incredibly close to what I want. I have 3 buttons on my Blynk app that each turn on a light. Then I also have 3 momentary physical buttons that each turn on the same set of lights. The only thing missing is if I turn on a light with the app and the app shows the light being on, I would like the button on the app to turn off if I turn the lights off with the physical button and also show on if I turn it on with the physical button.

What happens now is if I turn the light on with the app, it shows on, but if I turn the light off with the physical button, the app still shows on.

#define BLYNK_PRINT Serial


#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

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

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

// Set your LED and physical button pins here
const int ledPin1 = 9;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int ledPin4 = 15;
const int btnPin1 = 2;
const int btnPin2 = 3;
const int btnPin3 = 4;
const int btnPin4 = 0;

BlynkTimer timer;
void checkPhysicalButton();

int led1State = LOW;
int btn1State = HIGH;

int led2State = LOW;
int btn2State = HIGH;

int led3State = LOW;
int btn3State = HIGH;

int led4State = LOW;
int btn4State = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V12);
  Blynk.syncVirtual(V13);
  Blynk.syncVirtual(V14);
  Blynk.syncVirtual(V15);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V12, led1State);
  //Blynk.virtualWrite(V13, led2State);
  //Blynk.virtualWrite(V14, led3State);
  //Blynk.virtualWrite(V15, led4State);

}

// When App button is pushed - switch the state
BLYNK_WRITE(V12) {
  led1State = param.asInt();
  digitalWrite(ledPin1, led1State);
}
  
 BLYNK_WRITE(V13) {
  led2State = param.asInt();
  digitalWrite(ledPin2, led2State);
 }
BLYNK_WRITE(V14) {
  led3State = param.asInt();
  digitalWrite(ledPin3, led3State);
}
BLYNK_WRITE(V15) {
  led4State = param.asInt();
  digitalWrite(ledPin4, led4State);
}

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

      // Toggle LED state
      led1State = !led1State;
      digitalWrite(ledPin1, led1State);

      // Update Button Widget
      Blynk.virtualWrite(V12, led1State);
    }
    btn1State = LOW;
  } else {
    btn1State = HIGH;
  }

  if (digitalRead(btnPin2) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btn2State != LOW) {

      // Toggle LED state
      led2State = !led2State;
      digitalWrite(ledPin2, led2State);

      // Update Button Widget
      Blynk.virtualWrite(V13, led2State);
    }
    btn2State = LOW;
  } else {
    btn2State = HIGH;
  }

  if (digitalRead(btnPin3) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btn3State != LOW) {

      // Toggle LED state
      led3State = !led3State;
      digitalWrite(ledPin3, led3State);

      // Update Button Widget
      Blynk.virtualWrite(V14, led3State);
    }
    btn3State = LOW;
  } else {
    btn3State = HIGH;
  }

  if (digitalRead(btnPin4) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btn4State != LOW) {

      // Toggle LED state
      led4State = !led4State;
      digitalWrite(ledPin4, led4State);

      // Update Button Widget
      Blynk.virtualWrite(V15, led4State);
    }
    btn4State = LOW;
  } else {
    btn4State = HIGH;
  }
}

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

  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);

 { pinMode(ledPin1, OUTPUT);
  pinMode(btnPin1, INPUT_PULLUP);
  digitalWrite(ledPin1, led1State);
  timer.setInterval(100L, checkPhysicalButton);}

 { pinMode(ledPin2, OUTPUT);
  pinMode(btnPin2, INPUT_PULLUP);
  digitalWrite(ledPin2, led2State);
  timer.setInterval(100L, checkPhysicalButton);}
{
  pinMode(ledPin3, OUTPUT);
  pinMode(btnPin3, INPUT_PULLUP);
  digitalWrite(ledPin3, led3State);
  timer.setInterval(100L, checkPhysicalButton);}

 { pinMode(ledPin4, OUTPUT);
  pinMode(btnPin4, INPUT_PULLUP);
  digitalWrite(ledPin4, led4State);

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

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

I don’t understand why this line appears 4 times in your void setup, or why your void setup seems to have contracted a nasty case of excessive curly brackets!

Pete.

I did not write the code, I just found it with some searching and I’m trying to change it slightly to do what I want. So far it does as it will turn the lights on and off with the Blynk app and momentary buttons exactly as I want, but I can’t get it to change the status of the lights on the Blynk app

Have you looked at the ‘sync physical button’ example in the Sketch Builder?

Pete.

I did see that, but from what I can tell(based on my very limited knowledge) it seems like that is meant to light an “LED” on the app and not affect the button on the app.

No, it keeps the widget button synchronised with the physical button, and turns on/off an LED widget rather than a physical one.

I think the code you are using was probably based on that example, but butchered to a point where it no longer works.

I’m guessing that your eventual aim is t simply to turn LEDs on/off with physical and widget buttons, but maybe to control relays instead?

Pete.

Pete, you are 100% correct in my plan. I am pretty clueless but that code did seem unnecessarily messy. Since it was close it seemed easier to fix it enough to work rather than start over. I’ll try the sample code you mentioned and see if I can get what I want from it though.

The main thing I seem to be running into or not understanding are the pins listed in the code. I am using an Arduino Nano 33 IoT. All of the numbered pins have a letter first. The code examples just have numbers for pins. I want to use D2, D3, and D4 for my physical buttons but if I put that into the code I get an error “D2 not declared in this scope”. If I could get some insight on what is going wrong there, maybe I can understand how the code works better rather than just trying to copy/paste what someone else is doing.

This is what I am trying to use. I left the D2 in there from when I get the error, but if I just remove the D and leave the 2, it works perfectly with the app buttons, but not the physical buttons.



/*************************************************************
  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.

 *************************************************************

  Blynk using a LED widget on your phone!

  App project setup:
    LED widget on V3
 *************************************************************/

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


#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

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

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Dont Blink 182";
char pass[] = "Starkey1";

// Set your LED and physical button pins here
const int ledPin = 7;
const int btnPin = D2;

BlynkTimer timer;
void checkPhysicalButton();

int ledState = LOW;
int btnState = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V2);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V2, ledState);
}

// When App button is pushed - switch the state
BLYNK_WRITE(V2) {
  ledState = param.asInt();
  digitalWrite(ledPin, ledState);
}

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

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin, ledState);

      // Update Button Widget
      Blynk.virtualWrite(V2, ledState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

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

  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);

  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  digitalWrite(ledPin, ledState);

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

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

First, check that you’ve selected the correct board type in the IDE when you compile the code. If you have then just do what you have and drop the “D”

Do you mean it doesn’t compile, or doesn’t work?

Pete.

Ok, I have it working with 3 lights from the app buttons and one physical button. I am still not getting any feedback for the button state into the app though. Just trying to make one do the job and then I’ll worry about making the other 2 follow



/*************************************************************
  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.

 *************************************************************

  Blynk using a LED widget on your phone!

  App project setup:
    LED widget on V3
 *************************************************************/

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


#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

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

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


// Set your LED and physical button pins here
const int ledPin1 = 9;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int btnPin1 = 2;
const int btnPin2 = 3;
const int btnPin3 = 4;

BlynkTimer timer;
void checkPhysicalButton();

int ledState = LOW;
int btnState = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V2);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V2, ledState);
}

// When App button is pushed - switch the state
BLYNK_WRITE(V2) {
  ledState = param.asInt();
  digitalWrite(ledPin1, ledState);
}

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

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin1, ledState);

      // Update Button Widget
      Blynk.virtualWrite(9, ledState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

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

  Blynk.begin(auth, ssid, pass);

  pinMode(ledPin1, OUTPUT);
  pinMode(btnPin1, INPUT_PULLUP);
  digitalWrite(ledPin1, ledState);

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

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

Your button widget is connected to pin V2, yet you are updating whatever (if anything) is attached to pin V9 when the state of the physical button is changing.

This…

should look like this…

// Update Button Widget 
Blynk.virtualWrite(V9, ledState);

The V in front of the virtual PIN number is optional, but it’s good practice to include it.

Pete.

That was left over from one of my attempts at making sense of this. They are currently all V2 where they were originally in the sample code. There is still no change to the status on the app when the physical button is used

Ok, I decided to back way up and see what happens. I copied the code direct from the example and then moved my physical connections to match the code. This way my editing couldn’t possibly have an affect on functionality. Still the exact same result. App control of the light works and the physical button works, but using the physical button shows nothing in the app. Isn’t the point of the example for it to work and learn by seeing what works?


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


#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

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

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

// Set your LED and physical button pins here
const int ledPin = 7;
const int btnPin = 8;

BlynkTimer timer;
void checkPhysicalButton();

int ledState = LOW;
int btnState = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V2);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V2, ledState);
}

// When App button is pushed - switch the state
BLYNK_WRITE(V2) {
  ledState = param.asInt();
  digitalWrite(ledPin, ledState);
}

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

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin, ledState);

      // Update Button Widget
      Blynk.virtualWrite(V2, ledState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

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

  Blynk.begin(auth, ssid, pass);

  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  digitalWrite(ledPin, ledState);

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

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

Do you have more than one device in your project in the app?

Can you post a screenshot of the widget in edit mode.

Pete.

Ok, I somewhat figured it out. I was under the impression that I needed to have the app buttons set to the pin on the Nano that the led is connected to. I changed my app button to V2 and it works on that one button exactly as it should. Now I just need to figure out how to duplicate that 2 more times. What is it in the code that attaches the V2 to the led? Like in that code, my led is on pin 7 of the Nano, but V2 on the app turns it on and off. I don’t see anything in the code for that to make sense

Also, to answer your question, only one device (Arduino Nano 33 IoT) and that is connected to a relay.

Hello friend, what you should do is use two more digital variables, as you did with V2. You could use V3 and V4. What if you should modify your schedule.
greetings, matias.

Well, the instructions in the sketch builder example are pretty clear…


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

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

V2 is attached to the Blynk button widget, and when the state of the widget changes it triggers the BLYNK_WRITE(V2) callback function.

In that function, the state of the widget button (on or off, 1 or 0) is obtained via the param.asInt() command and assigned to the `ledState’ variable.

This line of code inverts that state…

This is then used in a digitalWrite command to update the pin that the LED is attached to (pin 7, which is referenced as ledPin thanks to this line…

so, this line of code…

Writes the opposite of the switch value to the LED pin.

Pete.

I appreciate that info Pete. Some of it I had already made sense of, but that clears more of it up.

I’m struggling to see how it’s possible to add more virtual buttons and more Led pins.

It seems like in other sketches I have messed with, I will need ledpin1 ledpin2 ledpin3 and such. But then it’s attaching the virtual pins to those physical pins

SUCCESSSSS!!! Sort of. lol.

I got all 3 working exactly how I wanted them to, but one side effect of adding the other 2 lights and buttons is they flash when you hold the button. Before when it was just one it wouldn’t flash. If you pushed the physical button and held it, it would switch and stay that way. It wouldn’t be much of a problem except you have to time your pushes just right for the light to come on and stay on. Anything stand out in this code to explain that?



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

#include <SPI.h>
#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

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

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

// Set your LED and physical button pins here
const int ledPin = 7;
const int ledPin1 = 8;
const int ledPin2 = 9;
const int btnPin = 2;
const int btnPin1 = 3;
const int btnPin2 = 4;

BlynkTimer timer;
void checkPhysicalButton();

int ledState = LOW;
int btnState = HIGH;

// Every time we connect to the cloud...
BLYNK_CONNECTED() {
  // Request the latest state from the server
  Blynk.syncVirtual(V2);
  Blynk.syncVirtual(V3);
  Blynk.syncVirtual(V4);

  // Alternatively, you could override server state using:
  //Blynk.virtualWrite(V2, ledState);
}

// When App button is pushed - switch the state
BLYNK_WRITE(V2) {
  ledState = param.asInt();
  digitalWrite(ledPin, ledState);
}

BLYNK_WRITE(V3) {
  ledState = param.asInt();
  digitalWrite(ledPin1, ledState);
}
BLYNK_WRITE(V4) {
  ledState = param.asInt();
  digitalWrite(ledPin2, ledState);
}

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

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin, ledState);
      
      // Update Button Widget
      Blynk.virtualWrite(V2, ledState);
          }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
   if (digitalRead(btnPin1) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btnState != LOW) {

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin1, ledState);
      
      // Update Button Widget
      Blynk.virtualWrite(V3, ledState);
          }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
     if (digitalRead(btnPin2) == LOW) {
    // btnState is used to avoid sequential toggles
    if (btnState != LOW) {

      // Toggle LED state
      ledState = !ledState;
      digitalWrite(ledPin2, ledState);
      
      // Update Button Widget
      Blynk.virtualWrite(V4, ledState);
          }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
}

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

  Blynk.begin(auth, ssid, pass);

  pinMode(ledPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);
  digitalWrite(ledPin, ledState);
  pinMode(ledPin1, OUTPUT);
  pinMode(btnPin1, INPUT_PULLUP);
  digitalWrite(ledPin1, ledState);
  pinMode(ledPin2, OUTPUT);
  pinMode(btnPin2, INPUT_PULLUP);
  digitalWrite(ledPin2, ledState);

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

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