Blynk - MQTT Bridge - Use Blynk app for non-Blynk devices

Well, not all my devices run on Blynk. Most run on Tasmota or other software I developed. Also particularly Tasmota leaves no memory to include Blynk library on an ESP8266.
My wife likes the ease of use of the Blynk App despite its old fashioned design (I will suggest to the developer team to create some different and more exciting skins).
To combine the two requirements I run a Wemos D1 mini board to run Blynk for my non-Blynk devices. It communicates with the controlled devices through MQTT. Now I can power on or dim a light or change the scheme etc. with the Blynk GUI.
At the same time I can still operate these devices with Domoticz and other means.

My program operates as the GUI for one Arilux-LC01 and two ESP01s. As the Wemos has 127 virtual pins you may add more devices.

Arilux-LC01:
Video

Photo of Blynk App:

Program:

 Blynk to MQTT bridge
 Version 1.0     9. Feb 2018

 Funtion: Use Blynk GUI to control MQTT attached devices
 
Pin assignments:
* Wemos D1 mini

Blynk Virtual Pins: 127 pins available
1. Kitchen Top control (Arilux LC01 running Tasmota)
V0: ON OFF Button 
V1: Dimmer slider
V2: Speed slider
V3: Color select
V4: Fade switch
V5: Scheme slider

2. Kitchen top high (ESP01 running Tasmota)
V6: ON OFF Button upper row lights

3. Kitchen top low (ESP01 running Tasmota)
V7: ON OFF Button lower row lights

4. For own purposes
V13: ON OFF LED
V14: UP LED

Bill of material:
 -Wemos D1 mini
 -1000uF capacitor (I found that a capacitor around 5V and Ground increases stability of the Wemos D1)
 -5V 750mA Power Supply
*/

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

// Set ESP8266 Serial object
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
SimpleTimer timer;

// Blynk
//#define BLYNK_DEBUG
//#define BLYNK_PRINT Serial
int ONOFF_LED = V13;
int UP_LED = V14;
long int last_UP_change = millis();
bool runn = 1;
bool lamp_on;
bool lamp23_on;
bool lamp24_on;
int brightness;
int current_activity;
int standard_speed;
int counter = 0;

// Wireless settings
const char AUTH[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char SSID[] = "mmwireless"; 
const char PASSWORD[] = "xxxxxxxxxx";
IPAddress mqtt_server(192,168,178,59);
const char* mqtt_username = "mqtt";
const char* mqtt_password = "xxxx";
char* InTopic = "tele/arilux74/STATE"; //subscribe to topic to be notified about
char* InTopic1 = "tele/ESP23/STATE";
WiFiClient espClient;
PubSubClient client(espClient);


void setup() {
Serial.begin(115200);
Serial.println(F("setup start"));

//Blynk
WiFi.mode(WIFI_STA);
Blynk.begin(AUTH, SSID, PASSWORD,"192.168.178.59",8442);
  while (Blynk.connect() == false) {  // Wait until connected
    if ((millis() - last_UP_change) > 30000) { // 30s before reset
      Serial.println(F("resetting"));
      ESP.restart();
   }
 }
wait(10);
client.setServer(mqtt_server, 8883);
client.setCallback(callback);

//OTA
 // Port defaults to 8266
 // ArduinoOTA.setPort(8266);
 // Hostname defaults to esp8266-[ChipID]
 ArduinoOTA.setHostname("D1-MQTT_Bridge");
 // No authentication by default
 ArduinoOTA.setPassword((const char *)"xxx");
 ArduinoOTA.onStart([]() {
   Serial.println("Start");
 });
 ArduinoOTA.onEnd([]() {
   Serial.println("\nEnd");
 });
 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
   Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
 });
 ArduinoOTA.onError([](ota_error_t error) {
   Serial.printf("Error[%u]: ", error);
   if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
   else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
   else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
   else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
   else if (error == OTA_END_ERROR) Serial.println("End Failed");
 });
 ArduinoOTA.begin();

 Serial.println(F("Entering loop"));
 wait(200);
 timer.setInterval(2003L, blinkonoff);
 Blynk.virtualWrite(ONOFF_LED,0); 
 Blynk.virtualWrite(UP_LED,0); 
}


void loop() {
 Blynk.run();
 if(!Blynk.connected()) {
   Serial.println(F("Resetting in loop"));
   ESP.restart();
 }
 timer.run();
 if (!client.connected()) {
   reconnect();
  }
 client.loop();
 ArduinoOTA.handle();
}


void wait (int ms) {
 long current_time = millis();
 long end_time = current_time + ms; 
 while (current_time < end_time) {
   current_time = millis();
 }
}


void blinkonoff(){
// Turn runn LED on/off
  Blynk.virtualWrite(UP_LED,runn * 255);  // turn Up off
  runn = !runn;
  last_UP_change = millis();  
}

BLYNK_WRITE(V0) { //ON Off switch
   if (param.asInt()) {
     client.publish("cmnd/arilux74/power","1");
     lamp_on = 1;
   }
   else {
     client.publish("cmnd/arilux74/power","0");
     lamp_on = 0;
   }
   Blynk.virtualWrite(ONOFF_LED,lamp_on * 255);  
}

BLYNK_WRITE(V1) { // Dimmer 0-100
   brightness = param.asInt();
   char bright[4];
   dtostrf(brightness, 3, 0, bright);
   client.publish("cmnd/arilux74/Dimmer",bright);
}

BLYNK_WRITE(V2) { // Speed 0-100
 standard_speed = param.asInt();
 char speed[4];
 dtostrf(standard_speed, 3, 0, speed);
 client.publish("cmnd/arilux74/speed",speed);
}

BLYNK_WRITE(V3) { //Color select 0-255 each
  char hex[7] = {0};
  sprintf(hex,"%02X%02X%02X",param[0].asInt(),param[1].asInt(),param[2].asInt()); //convert to an hexadecimal string. Lookup sprintf for what %02X means.
  client.publish("cmnd/arilux74/color",hex);
}

BLYNK_WRITE(V4) { // Fade switch
   if (param.asInt()) client.publish("cmnd/arilux74/fade","1");
   else client.publish("cmnd/arilux74/fade","0");
}

BLYNK_WRITE(V5) { //Scheme slider 0-4
  current_activity = param.asInt();
  char activity[2];
  dtostrf(current_activity, 1, 0, activity);
  client.publish("cmnd/arilux74/scheme",activity);
}


BLYNK_WRITE(V6) { //ON Off upper lights
   if (param.asInt()) {
     client.publish("cmnd/ESP23/power","1");
     lamp23_on = 1;
   }
   else {
     client.publish("cmnd/ESP23/power","0");
     lamp23_on = 0;
   }
}


BLYNK_WRITE(V7) { //ON Off lower lights
   if (param.asInt()) {
     client.publish("cmnd/ESP24/power","1");
     lamp24_on = 1;
   }
   else {
     client.publish("cmnd/ESP24/power","0");
     lamp24_on = 0;
   }
}


void reconnect() {
 // Loop until we're reconnected
 while (!client.connected()) {
   Serial.print("Attempting MQTT connection...");
   // Attempt to connect
   if (client.connect("BlinkMQTTBridge",mqtt_username,mqtt_password)) {
     Serial.println("connected");
     counter = 0;
     // ... and resubscribe
     client.subscribe(InTopic);
     client.subscribe(InTopic1);
   } else {
     Serial.print("failed, rc=");
     Serial.print(client.state());
     Serial.println(" try again in 0.3 second");
     ++counter;
     if (counter > 180) ESP.reset();
     // Wait .3 seconds before retrying
     delay(300);
   }
 }
}

void callback(char* topic, byte* payload, unsigned int length) {
 StaticJsonBuffer<450> jsonBuffer;
 //const char* json = "{"Time":"2018-02-09T14:55:30","Uptime":1,"Vcc":3.180,"POWER":"ON","Dimmer":73,"Color":"BA3E00","Scheme":0,"Fade":"OFF","Speed":1,"LedTable":"OFF","Wifi":{"AP":1,"SSId":"mmwireless","RSSI":66,"APMac":"0E:41:58:01:03:F0"}}";
 JsonObject& root = jsonBuffer.parseObject((char*)payload);
 const char* Time = root["Time"]; // "2018-02-09T14:55:30"
 int Uptime = root["Uptime"]; // 1
 float Vcc = root["Vcc"]; // 3.18
 const char* POWER = root["POWER"]; // "ON"
 int Dimmer = root["Dimmer"]; // 73
 const char* Color = root["Color"]; // "BA3E00"
 int Scheme = root["Scheme"]; // 0
 const char* Fade = root["Fade"]; // "OFF"
 int Speed = root["Speed"]; // 1

 //here you can use this information (optional)
} ```
7 Likes

Kind of hardware bridge. Nice!

Interesting.
I use MQTT to control my devices but I use an RPI and Node-Red in my setup, but I’d wondered about the possibility of a more “lightweight” setup using a Wemos as a the controller.
It opens-up a different way to deploy a simple solution in a new location, which could be very handy.

I notice that you don’t have any debounce code on your button widgets - doesn’t this cause you a problem?

Pete.

How in the name of physics does a virtual button “bounce”? And how would you "debounce’ it anyhow?

Well, I guess i mean a virtual bounce :wink:
Tapping a switch widget connected to a virtual pin sometimes gives me the equivalent of a switch bounce in Node-Red, so I have to do a bit of debouncing to desentise the button.
I guess it may be a quirk of how Node-Red integrates with Blynk, and I don’t currently use any devices that run Blink in the ‘normal’ way, hence my interest in whether this is an issue when using this system.

Pete.

@PeteKnight, I guess this may be due to some unwanted (or improperly handled) feedback. I had it once, exactly when combining Blynk with MQTT using Node-red. You may want to check your flows…

1 Like

I see… unless the Button Widget is set to SWITCH mode, then each and every tap WILL provide two states 1 & 0 in quick succession… the BLYNK_WRITE() functions recognise that and it can be used to differentiate options or “debounced” to ignore one or the other state.

BLYNK_WRITE(vPin) {
  if (param.asInt()) { // Check state of button as integer
    // Do something here if State is 1
  }
  else {
    // Do something here if State is 0
  }
}
1 Like

Yes, it’s easy to get into a loop like that, depending on how you structure the flows.
Even taking care not to get into that sort of situation, I still get the odd bounce issue - but it’s easy enough to deal with once you realise what’s happening.

Pete.

2 Likes

Hi mrohner,
Thanks for your interesting programme. I want to use it, but discovered that, because Json has changed to version 6, the void callback (etc…) doesn’t compile. I am not familiar to Json, so I didn’t understand the info about what/how to change the programme. Can yuo help me?
Thanks in advance!

Downgrade your installed ArduinoJson library to version 5.13.5

Pete.

That’s true
New Json library is buggy idk why

Thanks; downgraded and now it compiles fine.

Good

Not sure about it being buggy, I’ve never used it, but much of the syntax was changed in V6, so code written for V5 or earlier tries to use methods that are illegal in V6.
You could spend a lot of time trying to re-write code written for V5 so that it works with V6, or simply keep using the V5 library with V5 code.

Pete.

1 Like

If you allow me: one more question. In the program “Blynk-MQTT Bridge” one has to provide the IPaddress of the mqtt_server, and in the statement Blynk.begin also an IP hs to be provided. In the example both are the same. Is this the IP of the local mqtt broker?

Hi, Yes mosquitto(mqtt) and blynk server runs on same Orange Pi hardware in my installation.

It seems that @mrohner is running a local Blynk server at 192.168.178.59 and presumably the same hardware is also acting as the MQTT server.

I take a different approach and use the Blynk cloud server, but run a Raspberry Pi as my MQTT and Node-Red server. Node-Red acts as the Blynk to MQTT bridge using the Blynk Websockets plugin for Node-Red.
I guess I could also run Blynk local server on the same Raspberry Pi, but the cloud server suits my needs better at the moment.

Pete.

1 Like

Thanks. I was able to use the Blynk cloud server (Blynk.begin(AUTH, SSID, PASSWORD); without server IP) together with a local MQTT-server on a PC.

1 Like

yes Pete , I have the same issue , so I downgrade to V5.

1 Like

I’ve just released my C# app based on python script mentioned above.

Grab and have fun! Tested on Linux (mono) and windows

2 Likes