Physical button on board A to trigger action on Board B through Bridge

Hello Everyone,

I am finishing up a project and after doing some extensive research I have not been able to find the solution for this, I would appreciate if anyone can direct me in the right direction and I will see how to get this working.

Okay what I am trying to do sounds simple, I hope it is. I have a NodeMCU controlling a light bulb and it is able to trigger the light either by a physical button or by a widget in the blynk app. I am trying to add a second physical button which would send a trigger to another NodeMCU to open my garage door. So basically the end product will be one box with 2 buttons, one for the light bulb (currently working) and the other button to trigger the relay on a separate NodeMCU connected through wifi.

Here is the code being used for the light bulb

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
// #define BLYNK_PRINT Serial // Defines the object that is used for printing
// #define BLYNK_DEBUG        // Optional, this enables more detailed prints

#define VPIN V2

char auth[] = "xxxx"; //blynk auth token

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

void lightOn();
void lightOff();

boolean LampState = 0;
boolean SwitchReset = true;

const int TacSwitch = D5; 
const int RelayPin = D6; 

SimpleTimer timer;
WidgetLED VLED(V12);

void setup()      
{
  Serial.begin(115200);
  pinMode(RelayPin, OUTPUT);
  digitalWrite(RelayPin, HIGH);
  pinMode(TacSwitch, INPUT_PULLUP);
  delay(10);
  Blynk.begin(auth, ssid, pass);
  timer.setInterval(100, ButtonCheck);
}
void loop()
{
  Blynk.run();
  timer.run();
}
void ButtonCheck() {
  boolean SwitchState = (digitalRead(TacSwitch));
  if (!SwitchState && SwitchReset == true) {
    if (LampState) {
      lightOff();
    } else {
      lightOn();
    }
    SwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    SwitchReset = true;
  }
}
void ToggleRelay() {
  LampState = !LampState;
  if (LampState) {
       lightOn();
  }
  else lightOff();
}
void lightOn() {
    digitalWrite(RelayPin, LOW);
    LampState = 1;
    Blynk.virtualWrite(VPIN, HIGH); 
    VLED.on();
}
void lightOff() {
    digitalWrite(RelayPin, HIGH);
    LampState = 0;
    Blynk.virtualWrite(VPIN, LOW); 
    VLED.off();
}
BLYNK_WRITE(VPIN) {
  int SwitchStatus = param.asInt();
    if (SwitchStatus == 2){
    ToggleRelay();
  }
  else if (SwitchStatus){
    lightOn();
  }
  else lightOff();
}

Thank you before hand to everyone who helped me and the great founders of Blynk.

Did your extensive research include the bridge option? Or perhaps the search feature :wink:

Thank you @Gunner, I guess I was using the wrong keywords.

I am trying to add that into the code I have, and the code compiles but I know it won’t work, because I am not telling the bridge to take the input from the physical button and then trigger the other device through the bridge. How can I tell the code to take the input from TacSwitch2 and send it through the bridge to device B.

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
// #define BLYNK_PRINT Serial // Defines the object that is used for printing
// #define BLYNK_DEBUG        // Optional, this enables more detailed prints

#define VPIN V2

char auth[] = "xxxx"; //blynk auth token

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

void lightOn();
void lightOff();

boolean LampState = 0;
boolean SwitchReset = true;

const int TacSwitch = D5; 
const int TacSwitch2 = D7; 
const int RelayPin = D6; 

WidgetBridge bridge1(V6); //Initiating Bridge Widget on V1 of Device A

SimpleTimer timer;
WidgetLED VLED(V12);

void setup()      
{
  Serial.begin(115200);
  pinMode(RelayPin, OUTPUT);
  digitalWrite(RelayPin, HIGH);
  pinMode(TacSwitch, INPUT_PULLUP);
  delay(10);
  Blynk.begin(auth, ssid, pass);
    while (Blynk.connect() == false) {
        // Wait until Blynk is connected
    }
    bridge1.digitalWrite(V1, HIGH); // will trigger V1 HIGH on Device B. No code on Device B required

  timer.setInterval(100, ButtonCheck);
}

BLYNK_CONNECTED() {
  bridge1.setAuthToken("OtherAuthToken"); // Token of the hardware B
}

void loop()
{
  Blynk.run();
  timer.run();
}
void ButtonCheck() {
  boolean SwitchState = (digitalRead(TacSwitch));
  if (!SwitchState && SwitchReset == true) {
    if (LampState) {
      lightOff();
    } else {
      lightOn();
    }
    SwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    SwitchReset = true;
  }
}
void ToggleRelay() {
  LampState = !LampState;
  if (LampState) {
       lightOn();
  }
  else lightOff();
}
void lightOn() {
    digitalWrite(RelayPin, LOW);
    LampState = 1;
    Blynk.virtualWrite(VPIN, HIGH); 
    VLED.on();
}
void lightOff() {
    digitalWrite(RelayPin, HIGH);
    LampState = 0;
    Blynk.virtualWrite(VPIN, LOW); 
    VLED.off();
}
BLYNK_WRITE(VPIN) {
  int SwitchStatus = param.asInt();
    if (SwitchStatus == 2){
    ToggleRelay();
  }
  else if (SwitchStatus){
    lightOn();
  }
  else lightOff();
}

Garage door opener code

char auth[] = "token";


void setup()
{
Serial.begin(9600);
Blynk.begin(auth);
pinMode(D0, OUTPUT);
pinMode(D3, OUTPUT);
}
void loop()
{
    Blynk.run();    
}

I am too exhausted to do any code spelunking today, but I recommend starting with some example sketches that use bridge. Once you get the hang of that, merging it into your code will be much easier. Don’t forget to include the widget in your app project.

http://examples.blynk.cc/?board=NodeMCU&shield=ESP8266%20WiFi&example=Widgets%2FBridge

okay thank you. I am trying to understand that code and is not too complicated, but I am trying to figure out how to apply it to a physical button. I don’t need to know what status de switch is on like its set up for Tacswitch. I just need device A to know when TacSwitch2 is pressed and send the signal to PinMode(D0,OUTPUT) in device B.

I will see if i can find something related to it and see how to adapt it to my code.

Read up on attaching interrupts to a pin, ie code that will be called when an predefined event occurs. Pin goes low to high or high to low…

For this you need to debounce the function calls to avoid flood. It’s a bit sensitive working with interrupts from what I’ve read. Debounce with simpletimer library.

Something like this for debounce

SimpleTimer timer;
boolean debounce=false;

// call this on interrupt, do code once, max every 300ms to avoid bouncing from using interrupts 
void sendButtonPress() 
{
   if (!debounce)
   {
       debounce = true;
       //do bridge code
      
      timer.setTimeout(300, debounced);
   } 
} 

void debounced()
{
   debounce = false;
} 

@hgomez809 here is also nice tutorial with Bridge. In general what would you need is just:

WidgetBridge bridge1(V20);

//called when you trigger button in app
BLYNK_WRITE(V2) {
   bool isLampOn = checkLamp();
   if (isLampOn) {
       bridge1.digitalWrite(0, HIGH);
   }   
}

BLYNK_CONNECTED() {
  // Place the AuthToken of the second hardware here
  bridge1.setAuthToken("tttttttttttttttttttttttttttttttt"); 
}

Not sure if I am wrong but what I can tell is that in the code you provided you are setting the bridge widget virtual pin and creating a virtual pin for a in app button.
I am trying to get the signal from a physical button to trigger the relay on a separate board by using the bridge on blynk app.

i have been reading for the last few hours but I haven’t found a post with an example like the one I am looking for.

In short

From docs: Bridge widget takes a virtual pin, and turns it into a channel to control another device.

WidgetBridge bridge1(V20); // The virtual pin used for sending instructions
bridge1.setAuthToken("OtherAuthToken"); // Identifier written on device A for device B so that A can send instructions to B
bridge1.virtualWrite(V1, "hello"); // the inscrution to be sent from device A to device B

When you press a physical button you need to react to the button press. Use interrupts with my debounce example.

Declare bridge as global variable

WidgetBridge bridge1(V20); 

in setup assign identifier of your second device and attach interrupt to your button pin.
If you use a pullup resistor to the button you need falling edge detection

void setup()
{
   bridge1.setAuthToken("OtherAuthToken");
   attachInterrupt(yourButtonPin, sendButtonPress, FALLING) // when yourButtonPin goes from 1 to 0 call function sendButtonPress
}
SimpleTimer timer;
boolean debounce=false;

// call this on interrupt, do code once, max every 300ms to avoid bouncing from using interrupts 
void sendButtonPress() 
{
   if (!debounce)
   {
       debounce = true;
       bridge1.digitalWrite(pinNoOnOtherMCU, HIGH);
      
      timer.setTimeout(300, debounced);
   } 
} 

void debounced()
{
   debounce = false;
}

@Dmitriy Am I understanding this usage correct? I have never played with bridge, this is PURELY from REEEEEEAAAAAAAAADIIIIIIIIIING docs example :slight_smile:

Thank you @Fettkeewl I will check it out in the AM. By the way, I am really trying here, definitely reading a lot, slowly learning the programming basics that are already easy for others. I do appreciate you taking the time to help me with this. I will make sure to give back to the community with a well detailed tutorial for easy understanding for those who may be interested in doing this and don’t know how to.

1 Like

Let me know if I can further explain anything in my previous answer

Do you understand most of what I wrote?

not sure if I should open another topic for this, please correct me if i need to.

Last night everything was working fine with the Arduino IDE, everything was compiling fine, and something popup about updating the libraries which I did, now I can’t compile anything. I am trying to use a working code which compiled fine last night. I get this error everytime. I noticed the additional boards url was missing so I re-added it, but no luck.

Arduino: 1.8.1 (Windows 10), Board: "NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)"

In file included from C:\Users\hgome\Documents\Arduino\libraries\Blynk\src/BlynkSimpleEsp8266.h:18:0,

                 from C:\Users\hgome\Documents\Arduino Projects\On.Off wifi and physical switch\ESP8266_Standalone_blynk_on_off_wifi_physical\ESP8266_Standalone_blynk_on_off_wifi_physical.ino\ESP8266_Standalone_blynk_on_off_wifi_physical.ino.ino:2:

C:\Users\hgome\Documents\Arduino\libraries\Blynk\src/BlynkApiArduino.h: In member function 'void BlynkApi<Proto>::sendInfo()':

C:\Users\hgome\Documents\Arduino\libraries\Blynk\src/BlynkApiArduino.h:72:40: error: 'BLYNK_CMD_HARDWARE_INFO' was not declared in this scope

     static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_INFO, 0, profile, profile_len);

                                        ^

exit status 1
Error compiling for board NodeMCU 1.0 (ESP-12E Module).

Solved, I downgraded to an older version of the blynk library and everything compiles now.

@hgomez809 did you fully remove prev. version of library?

Yes, it is working fine now.

I have worked with the code some more and I think bridge is implemented in the code but it is not working.

I am leaving it here in case anyone has any input.

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
// #define BLYNK_PRINT Serial // Defines the object that is used for printing
// #define BLYNK_DEBUG        // Optional, this enables more detailed prints

#define VPIN V2

char auth[] = "Token device A"; //blynk auth token

char auth2[] = "Token B (Garage door)"; //Auth Token for the additional project that you would like to control

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

//Bridge Widget on virtual pin 1 (not currently required in the app)
WidgetBridge bridge1(V1);

void lightOn();
void lightOff();

boolean LampState = 0;
boolean SwitchReset = true;
boolean RemoteSwitchReset = true;

const int TacSwitch = D5; 
const int RelayPin = D6; 
const int RemoteSwitch = D4; // Connect a physical button to this pin

SimpleTimer timer;
SimpleTimer timer2;
WidgetLED VLED(V12);

void setup()      
{
  Serial.begin(115200);
  pinMode(RelayPin, OUTPUT);
  digitalWrite(RelayPin, HIGH);
  pinMode(TacSwitch, INPUT_PULLUP);
  pinMode(RemoteSwitch, INPUT_PULLUP);
  delay(10);
  Blynk.begin(auth, ssid, pass);
  timer.setInterval(100, ButtonCheck);
  timer2.setInterval(100, RemoteButtonCheck);
  
  while (Blynk.connect()) {  
     // Wait until connected   
  }
  bridge1.setAuthToken(auth2); // Connect via bridge to another device
}
void loop()
{
  Blynk.run();
  timer.run();
}
void ButtonCheck() {
  boolean SwitchState = (digitalRead(TacSwitch));
  if (!SwitchState && SwitchReset == true) {
    if (LampState) {
      lightOff();
    } else {
      lightOn();
    }
    SwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    SwitchReset = true;
  }
}
void RemoteButtonCheck() {
  boolean SwitchState = (digitalRead(RemoteSwitch));
  if (!SwitchState && RemoteSwitchReset == true) {
    bridge1.digitalWrite(0, HIGH);  // Activate PIN D0 in another device
    RemoteSwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    RemoteSwitchReset = true;
  }
}
void ToggleRelay() {
  LampState = !LampState;
  if (LampState) {
       lightOn();
  }
  else lightOff();
}
void lightOn() {
    digitalWrite(RelayPin, LOW);
    LampState = 1;
    Blynk.virtualWrite(VPIN, HIGH); 
    VLED.on();
}
void lightOff() {
    digitalWrite(RelayPin, HIGH);
    LampState = 0;
    Blynk.virtualWrite(VPIN, LOW); 
    VLED.off();
}
BLYNK_WRITE(VPIN) {
  int SwitchStatus = param.asInt();
    if (SwitchStatus == 2){
    ToggleRelay();
  }
  else if (SwitchStatus){
    lightOn();
  }
  else lightOff();
}

We might need to see your receiving code from the other device as well, to better determine what might be the issue.

This seems a bit odd to me at first glance, digitalRead returns 0 or 1, not a boolean value. Some type of autocast here?

I have updated the code, it now compiles and also works like it used to, however, I tried to implement the second button to trigger my garage door controlled by another device to no luck. Also got OTA upgrade now :smiley: Little by little I am getting the hang of this.

If anyone has any input in order to make ‘RemoteSwitch’ trigger pin D0 from another NodeMCU by using the bridge feature in blynk, I would gratefully appreciate it.

Well I want to make it work with bridge, but if anyone is able to help me implement the garage door relay by a physical button in this code I am fine with uploading the same code into 2 boards and just use different pins for different relays outputs and/or button inputs.

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <WiFiUdp.h> //OTA NEEDED
#include <ArduinoOTA.h> //OTA NEEDED

#define VPIN V2

char auth[] = "xxxx"; //blynk auth token for Main device
char auth2[] = "xxxx"; //Auth Token for the additional project that you would like to control

// Your WiFi credentials.
char ssid[] = "xxxx"; //Wifi Name
char pass[] = "xxxx"; //Wifi Password // Set password to "" for open networks.

//Bridge Widget on virtual pin 1 (not currently required in the app)
WidgetBridge bridge1(V3);

void lightOn();
void lightOff();

boolean LampState = 0;
boolean SwitchReset = true;
boolean RemoteSwitchReset = true;

const int RelayPin = D1; 
const int TacSwitch = D2; //Relay Physical On/Off Button
const int RemoteSwitch = D3; // Garage Door Physical Button

SimpleTimer timer;
SimpleTimer timer2;
WidgetLED VLED(V12);

void setup()      
{
  Serial.begin(115200);
  pinMode(RelayPin, OUTPUT);
  digitalWrite(RelayPin, LOW);
  pinMode(TacSwitch, INPUT_PULLUP);
  pinMode(RemoteSwitch, INPUT_PULLUP);
  delay(10);

  // OTA CODE NEEDED //
  ArduinoOTA.setHostname("Garage Light WemoD1"); //Device Name
  ///ArduinoOTA.setPassword((const char *)""); // Device Password for OTA Upgrades
  ArduinoOTA.begin(); 
  // OTA CODE NEEDED ENDS //
    
  Blynk.begin(auth, ssid, pass);
  timer.setInterval(100, ButtonCheck);
  timer2.setInterval(100, RemoteButtonCheck);
}

BLYNK_CONNECTED() {
  bridge1.setAuthToken(auth2); // Connect via bridge to another device
}

void loop()
{
  ArduinoOTA.handle(); //OTA NEEDED
  Blynk.run();
  timer.run();
}
void ButtonCheck() {
  boolean SwitchState = (digitalRead(TacSwitch));
  if (!SwitchState && SwitchReset == true) {
    if (LampState) {
      lightOff();
    } else {
      lightOn();
    }
    SwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    SwitchReset = true;
  }
}
void RemoteButtonCheck() {
  boolean SwitchState = (digitalRead(RemoteSwitch));
  if (!SwitchState && RemoteSwitchReset == true) {
    bridge1.digitalWrite(D0, HIGH);  // Activate PIN D0 in another device
    RemoteSwitchReset = false;
    delay(50);
  }
  else if (SwitchState) {
    RemoteSwitchReset = true;
  }
}
void ToggleRelay() {
  LampState = !LampState;
  if (LampState) {
       lightOn();
  }
  else lightOff();
}
void lightOn() {
    digitalWrite(RelayPin, HIGH);
    LampState = 1;
    Blynk.virtualWrite(VPIN, HIGH); 
    VLED.on();
}
void lightOff() {
    digitalWrite(RelayPin, LOW);
    LampState = 0;
    Blynk.virtualWrite(VPIN, LOW); 
    VLED.off();
}
BLYNK_WRITE(VPIN) {
  int SwitchStatus = param.asInt();
    if (SwitchStatus == 2){
    ToggleRelay();
  }
  else if (SwitchStatus){
    lightOn();
  }
  else lightOff();
}

This is the code that is controlling the garage door, really simple just to trigger the relay. It is missing the libraries and wifi auth.

char auth[] = "token";


void setup()
{
Serial.begin(9600);
Blynk.begin(auth);
pinMode(D0, OUTPUT);
pinMode(D3, OUTPUT);
}
void loop()
{
    Blynk.run();    
}

Hello everyone! Could someone please use this bridge code? I would love to use it.