BLYNK_WRITE() Issue in a WiFi controlled relay

Hi everyone! I’m Maximiliano, and i need some help.
I’ve made a WiFi controlled relay, using a ESP-01 (Like a homemade Sonoff, maybe?)
The information for the project is in this list:

  • ESP-01 with WiFi connection
  • Blynk server. Blynk Library version : 0.61
  • Using tzapu WiFiManager library to save WiFi credentials, Blynk Token and Virtualpins

The issue

Working with the WiFiManager library i’ve managed to save and use the WiFi credentials, the Token and also the selected Virtual Pins (in INT variables), but when i try to use those virtual pins in BLYNK_WRITE() as an argument, the function does nothing.
The funny fact is that i have a synchronised physical button with the app and that button changes the app button state (and the output state) but this app button doesn’t change anything.
I’ve an idea of where is the problem (in the Char to Int conversion), but i don’t know why this is happening.

It works perfect if i choose an constant Virtual pin (like putting BLYNK_WRITE(Vpin) in the code), but i want to configure the argument without codding. Any idea?

  /* Librerias a usar */
#include <FS.h>                 //File System, para almacenar variables en memoria flash                       
#include <ESP8266WiFi.h>        //Header del ESP8266 y el control del WiFi
#include <DNSServer.h>          //Header auxiliar para el WiFiManager
#include <ESP8266WebServer.h>   //Header para montar un webserver en la red local
#include <WiFiManager.h>        //Manejo del WiFi sin modificacionen del codigo  
#include <ArduinoJson.h>        //Header para modificar archivos JSON
#include <BlynkSimpleEsp8266.h> 
//#define BLYNK_PRINT Serial    //Comment this out to disable prints and save space        

  /* Asignacion de pines GPIO */
const int LED1 = 3, LED2 = 1;
const int BT1 = 0, BT2 = 2;

  /* Variables globales auxiliares */
const bool ON = HIGH, OFF = LOW;
volatile bool L1State, L2State, BT1State, BT2State, Clear = false;
bool shouldSaveConfig = false;
volatile int relay1 = 0, relay2 = 0, lcdip = 0;
char blynk_token[34] = "";
char www_username[10] = "";
char www_password[10] = "";
char relay1vp[3] = "";
char relay2vp[3] = "";
char lcdvp[3] = "";

WidgetLCD lcd(lcdip);

  /* Funciones auxiliares de Blynk */
BLYNK_CONNECTED() {
  Blynk.syncVirtual(relay1);
  Blynk.syncVirtual(relay2);
  }

BLYNK_WRITE(relay1) {
  if (param.asInt() == ON) {digitalWrite(LED1, ON); LED1Status = "On";}
  else                     {digitalWrite(LED1, OFF); LED1Status = "Off";}
}
BLYNK_WRITE(relay2) {
  if (param.asInt() == ON) {digitalWrite(LED2, ON); LED2Status = "On";}
  else                     {digitalWrite(LED2, OFF); LED2Status = "Off";}
}

void saveConfigCallback();
void ICACHE_RAM_ATTR SyncBT1();
void ICACHE_RAM_ATTR SyncBT2();

void setup()
{
  /* Config de Puerto Serial y GPIO */
  Serial.begin(115200);
  Serial.println();
  pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(BT1, INPUT); pinMode(BT2, INPUT);
  digitalWrite(LED1, OFF); digitalWrite(LED2, OFF);
  attachInterrupt(digitalPinToInterrupt(BT1), SyncBT1, FALLING);
  attachInterrupt(digitalPinToInterrupt(BT2), SyncBT2, FALLING);

  /* Operacion con el SPIFFS para obtener credenciales WiFi, Token, etc */
  if (SPIFFS.begin()) {
    if (SPIFFS.exists("/config.json")) {
      File configFile = SPIFFS.open("/config.json", "r");
        if (configFile) {
          size_t size = configFile.size();
          std::unique_ptr<char[]> buf(new char[size]);
          configFile.readBytes(buf.get(), size);
          DynamicJsonBuffer jsonBuffer;
          JsonObject& json = jsonBuffer.parseObject(buf.get());
          json.printTo(Serial);
            if (json.success()) {
              strcpy(blynk_token, json["blynk_token"]);
              strcpy(www_username, json["www_username"]);
              strcpy(www_password, json["www_password"]);
              strcpy(relay1vp, json["relay1vp"]);
              strcpy(relay2vp, json["relay2vp"]);
              strcpy(lcdvp, json["lcdvp"]);
            } 
        }
     }
  } 
  
  /* Config. de parametros especiales del WiFiManager */
  WiFiManagerParameter custom_blynk_token("blynk", "Token", blynk_token, 33);
  WiFiManagerParameter custom_username("localusername", "Local Username", www_username, 8);
  WiFiManagerParameter custom_password("localpassword", "Local password", www_password, 8);
  WiFiManagerParameter custom_relay1("relay1vp", "Relay 1 VirtualPin", relay1vp, 1);
  WiFiManagerParameter custom_relay2("relay2vp", "Relay 2 VirtualPin", relay2vp, 1); 
  WiFiManagerParameter custom_lcd("lcdvp", "LCD VirtualPin", lcdvp, 1);   
  WiFiManager wifiManager;                  //Instancia para manejo del WiFi 
  wifiManager.setSaveConfigCallback(saveConfigCallback);
  wifiManager.setConfigPortalTimeout(180);  //3 minutos de espera de conexion antes del reinicio
  wifiManager.addParameter(&custom_blynk_token);
  wifiManager.addParameter(&custom_username);
  wifiManager.addParameter(&custom_password);
  wifiManager.addParameter(&custom_relay1);
  wifiManager.addParameter(&custom_relay2);
  wifiManager.addParameter(&custom_lcd);         
  if (!wifiManager.autoConnect("ESP8233", "87654321")) {
      delay(3000);
      ESP.reset();
      delay(5000);
  }
  strcpy(blynk_token, custom_blynk_token.getValue());
  strcpy(www_username, custom_username.getValue());
  strcpy(www_password, custom_password.getValue());
  strcpy(relay1vp, custom_relay1.getValue());
  strcpy(relay2vp, custom_relay2.getValue());
  strcpy(lcdvp, custom_lcd.getValue());

  /* Rutina auxiliar de almacenamiento de credenciales */
  if (shouldSaveConfig) {      
      DynamicJsonBuffer jsonBuffer;
      JsonObject& json = jsonBuffer.createObject();
      json["blynk_token"] = blynk_token;
      json["www_username"] = www_username;
      json["www_password"] = www_password;
      json["relay1vp"] = relay1vp;
      json["relay2vp"] = relay2vp; 
      json["lcdvp"] = lcdvp;        
      File configFile = SPIFFS.open("/config.json", "w");
      json.printTo(Serial);
      json.printTo(configFile);
      configFile.close(); 
  }

  relay1 = atoi(relay1vp); 
  relay2 = atoi(relay2vp);
  lcdip = atoi(lcdvp);
  
  Blynk.config(blynk_token); //Configuracion y conexion 
  Blynk.connect();           //del servicio Blynk

  /* Widget de LCD 16x2 virtual, en Blynk */
  lcd.clear(); 
  lcd.print(4, 0, "IP Local");
  lcd.print(2, 1, WiFi.localIP().toString());
  
}

void loop(){
   Blynk.run();           //Inicializacion del sistema Blynk
   if (Clear == true) {
      WiFi.disconnect(); 
      delay(3000);
      ESP.reset();
      delay(5000);
      }
}

void saveConfigCallback() 
{shouldSaveConfig = true;} //Bandera para guardar nueva informacion

void SyncBT1()
{
  delayMicroseconds(100000);
  if (digitalRead(BT2) == LOW) Clear = true;
  if (digitalRead(LED1) == ON) {L1State = OFF; LED1Status="Off";}
  else                         {L1State = ON; LED1Status="On";}   
    digitalWrite(LED1, L1State);
    Blynk.virtualWrite(relay1, L1State);          
}

void SyncBT2()
{
  delayMicroseconds(100000);
  if (digitalRead(BT1) == LOW) Clear = true;
  if (digitalRead(LED2) == ON) {L2State = OFF; LED2Status="Off";}
  else                         {L2State = ON; LED2Status="On";}   
    digitalWrite(LED2, L2State);
    Blynk.virtualWrite(relay2, L2State);          
}

PD: Sorry if i’ve made some writing mistakes, i’m not a native english talker. Thanks everyone!

Are you storing things like “V1” and “V2” in these custom parameters?

I see that you’re using char variable types for this, which may be the issue.
You can just reference the virtual pins as integers (1, 2 etc) and drop the leading “V” if its easier:

ETA - You have a lot of delays in your code, and your void loop isn’t exactly clean. You may experience some problems as a result.

Pete.

1 Like

Hi Pete! Thanks for the reply!
I managed to fix the issue using the BLYNK_WRITE_DEFAULT function, like the example given for @Gunner in this post:

(I’ve reach there from your link, and is basically the same that you posted)

Shall I post the fixed code or edit the original one with the new code?
Thanks! Maximiliano

Share your latest code as a post on the end of this topic, then people can make sense of and learn from the comments and responses.

Pete.

I tried to organice better the code, deleting some unnecessary delays. This is it!

  /* Librerias a usar */
#include <FS.h>                 //File System, para almacenar variables en memoria flash                       
#include <ESP8266WiFi.h>        //Header del ESP8266 y el control del WiFi
#include <DNSServer.h>          //Header auxiliar para el WiFiManager
#include <ESP8266WebServer.h>   //Header para montar un webserver en la red local
#include <ArduinoOTA.h>         //Header de "Over The Air", usado para autenticacion
#include <WiFiManager.h>        //Manejo del WiFi sin modificacionen del codigo  
#include <ArduinoJson.h>        //Header para modificar archivos JSON
#include <BlynkSimpleEsp8266.h> //Header para la utilizacion del servicio Blynk       
#include <Ticker.h>             //Header del control del timer1

  /* Definicion de pines GPIO y virtuales */
#define RL1   3     //RX-GPIO3
#define RL2   1     //TX-GPIO1
#define BT1   0     //GPIO0
#define BT2   2     //GPIO2
#define ON    1     //Estado de encendido para las salidas
#define OFF   0     //Estado de apagado para las salidas

  /* Variables globales auxiliares */
volatile bool RL1Output = OFF, RL2Output = OFF, BT1State, BT2State;
int WiFiClear = 0, VRL1 = 0, VRL2 = 0, VLCD = 0;
bool shouldSaveConfig = false;
String RL1Status = "Off", RL2Status = "Off";
char blynk_token[34] = "";
char local_username[10] = "";
char local_password[10] = "";
char RL1VP[4] = "", RL2VP[4] = "", LCDVP[4] = "";

ESP8266WebServer server(80);    //Puerto para comunicacion HTTP
Ticker blinker;                 //Instancia para el timer1

  /* Funciones auxiliares de Blynk */
BLYNK_CONNECTED() {Blynk.syncAll();}
BLYNK_WRITE_DEFAULT() {
  int pin = request.pin;
  if (pin == VRL1){
    if (param.asInt() == ON) {digitalWrite(RL1, ON); RL1Status = "On";}
    else                     {digitalWrite(RL1, OFF); RL1Status = "Off";}    
  }
  else if (pin == VRL2){
    if (param.asInt() == ON) {digitalWrite(RL2, ON); RL2Status = "On";}
    else                     {digitalWrite(RL2, OFF); RL2Status = "Off";}   
  }
  else {Blynk.virtualWrite(VLCD, WiFi.localIP().toString());}
}

void saveConfigCallback();
void ICACHE_RAM_ATTR SyncBT1();
void ICACHE_RAM_ATTR SyncBT2();

void setup()
{
  /* Config de Puerto Serial y GPIO */
  pinMode(RL1, OUTPUT); pinMode(RL2, OUTPUT); 
  pinMode(BT1, INPUT); pinMode(BT2, INPUT);
  digitalWrite(RL1, OFF); digitalWrite(RL2, OFF);
  attachInterrupt(digitalPinToInterrupt(BT1), SyncBT1, FALLING);
  attachInterrupt(digitalPinToInterrupt(BT2), SyncBT2, FALLING);

  /* Operacion con el SPIFFS para obtener credenciales WiFi, Token, etc */
  if (SPIFFS.begin()) {
    if (SPIFFS.exists("/config.json")) {
      File configFile = SPIFFS.open("/config.json", "r");
        if (configFile) {
          size_t size = configFile.size();
          std::unique_ptr<char[]> buf(new char[size]);
          configFile.readBytes(buf.get(), size);
          DynamicJsonBuffer jsonBuffer;
          JsonObject& json = jsonBuffer.parseObject(buf.get());
          json.printTo(Serial);
            if (json.success()) {
              strcpy(blynk_token, json["blynk_token"]);
              strcpy(local_username, json["local_username"]);
              strcpy(local_password, json["local_password"]);
              strcpy(RL1VP, json["RL1VP"]);
              strcpy(RL2VP, json["RL2VP"]);
              strcpy(LCDVP, json["LCDVP"]);
            } 
        }
     }
  }
    
  /* Config. de parametros especiales del WiFiManager */
  WiFiManagerParameter custom_blynk_token("blynk", "Token", blynk_token, 33);
  WiFiManagerParameter custom_username("localusername", "Local Username", local_username, 8);
  WiFiManagerParameter custom_password("localpassword", "Local password", local_password, 8);
  WiFiManagerParameter custom_relay1vp("relay1vp", "Relay 1 Virtual Pin", RL1VP, 2);
  WiFiManagerParameter custom_relay2vp("relay2vp", "Relay 2 Virtual Pin", RL2VP, 2);
  WiFiManagerParameter custom_lcdvp("lcdvp", "IP LCD Virtual Pin", LCDVP, 2);
  
  /* Config. generales del WiFi Manager, definiendo su instancia, 
     el tiempo de timeout (3m), los parametros agregados, y su inicio */
  WiFiManager wifiManager;                  
  wifiManager.setSaveConfigCallback(saveConfigCallback);
  wifiManager.setConfigPortalTimeout(180);  
  wifiManager.addParameter(&custom_blynk_token);
  wifiManager.addParameter(&custom_username);
  wifiManager.addParameter(&custom_password);
  wifiManager.addParameter(&custom_relay1vp);  
  wifiManager.addParameter(&custom_relay2vp);
  wifiManager.addParameter(&custom_lcdvp);    
  if (!wifiManager.autoConnect("ESP8266", "87654321")) {
      delay(3000);
      ESP.reset();
      delay(5000);
  }
  /* Adquisicion de parametros almacenados en memoria Flash */
  strcpy(blynk_token, custom_blynk_token.getValue());
  strcpy(local_username, custom_username.getValue());
  strcpy(local_password, custom_password.getValue());
  strcpy(RL1VP, custom_relay1vp.getValue());
  strcpy(RL2VP, custom_relay2vp.getValue());
  strcpy(LCDVP, custom_lcdvp.getValue());
  
  /* Rutina auxiliar de almacenamiento de credenciales en memoria Flash */
  if (shouldSaveConfig) {      
      DynamicJsonBuffer jsonBuffer;
      JsonObject& json = jsonBuffer.createObject();
        json["blynk_token"] = blynk_token;
        json["local_username"] = local_username;
        json["local_password"] = local_password;
        json["RL1VP"] = RL1VP;
        json["RL2VP"] = RL2VP;
        json["LCDVP"] = LCDVP;     
      File configFile = SPIFFS.open("/config.json", "w");
      json.printTo(Serial);
      json.printTo(configFile);
      configFile.close(); 
  }

  ArduinoOTA.begin(); // Inicializacion de "Over The Air"
  
  /* Asignacion de rutinas para cada llamado HTTP recibido, segun header */
  server.on("/", handle_OnConnect);   server.onNotFound(handle_NotFound);
  server.on("/RL1/on", handle_RL1On); server.on("/RL1/off", handle_RL1Off);
  server.on("/RL2/on", handle_RL2On); server.on("/RL2/off", handle_RL2Off);
  server.begin(); // Inicializacion del servidor local
  
  /* */
  VRL1 = atoi(RL1VP);
  VRL2 = atoi(RL2VP);
  VLCD = atoi(LCDVP);
  
  /*Configuracion y conexion e impresion del IP LOCAL en servicio Blynk */
  Blynk.config(blynk_token);
  Blynk.connect();           
  blinker.attach(1.0, ClearWiFi);
}

void loop(){
   Blynk.run();           //Inicializacion del sistema Blynk
   ArduinoOTA.handle();   //Inicializacion del servicio Over The Air
   server.handleClient(); //Espera de comunicaciones al servidor
   /* Eliminacion de credenciales WiFi, si fuese necesario */
   if (WiFiClear >= 5) {
      blinker.detach();
      WiFi.disconnect();  delay(3000);
      ESP.reset(); delay(5000);}
}

void saveConfigCallback() 
{shouldSaveConfig = true;} //Bandera para guardar nuevas credenciales

void ClearWiFi()
{
  if ((digitalRead(BT1) == LOW) or (digitalRead(BT2) == LOW)) WiFiClear++;
  else                                                        WiFiClear = 0;
}

/* Rutina de interrupcion por BT1, cambiando el estado de la salida RL1, 
   sincronizada con el servidor web y el servicio Blynk */
void SyncBT1()
{
  delayMicroseconds(100000);
  if (digitalRead(RL1) == ON)  {RL1Output = OFF; RL1Status="Off";}
  else                         {RL1Output = ON; RL1Status="On";}   
    digitalWrite(RL1, RL1Output);
    Blynk.virtualWrite(VRL1, RL1Output);          
}

/* Rutina de interrupcion por BT1, cambiando el estado de la salida RL1, 
   sincronizada con el servidor web y el servicio Blynk */
void SyncBT2()
{
  delayMicroseconds(100000);
  if (digitalRead(RL2) == ON)  {RL2Output = OFF; RL2Status="Off";}
  else                         {RL2Output = ON; RL2Status="On";}   
    digitalWrite(RL2, RL2Output);
    Blynk.virtualWrite(VRL2, RL2Output);          
}

void handle_NotFound()
{server.send(404, "text/plain", "Not found");}

void handle_RL1On()
{
     if(!server.authenticate(local_username, local_password))
     return server.requestAuthentication();
  RL1Status = "On";
  digitalWrite(RL1, ON);
  Blynk.virtualWrite(VRL1, ON);
  server.send(200, "text/html", SendHTML(RL1Status,RL2Status));
}

void handle_RL1Off()
{
     if(!server.authenticate(local_username, local_password))
     return server.requestAuthentication();
  RL1Status = "Off";
  digitalWrite(RL1, OFF);
  Blynk.virtualWrite(VRL1, OFF);
  server.send(200, "text/html", SendHTML(RL1Status,RL2Status));
}

void handle_RL2On()
{
     if(!server.authenticate(local_username, local_password))
     return server.requestAuthentication();  
  RL2Status = "On";
  digitalWrite(RL2, ON);
  Blynk.virtualWrite(VRL2, ON);
  server.send(200, "text/html", SendHTML(RL1Status,RL2Status));
}

void handle_RL2Off()
{
     if(!server.authenticate(local_username, local_password))
     return server.requestAuthentication();    
  RL2Status = "Off";
  digitalWrite(RL2, OFF);
  Blynk.virtualWrite(VRL2, OFF);
  server.send(200, "text/html", SendHTML(RL1Status,RL2Status));
}

void handle_OnConnect()
{
   if(!server.authenticate(local_username, local_password))
   return server.requestAuthentication();
   server.send(200, "text/html", SendHTML(RL1Status,RL2Status)); 
}

String SendHTML(String RL1Status,String RL2Status)
{
   String str = "<!DOCTYPE html><html>";
          str += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
          str += "<title>SmartRelay V1.1</title>";
          str += "<link rel=\"icon\" href=\"data:,\">";
          str += "<style>html {font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}";
          str += ".button {background-color: #195B6A; border: none; color: white; padding: 16px 40px;";
          str += "text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}";
          str += ".button2 {background-color: #77878A;}</style></head>";
          str += "<body><h1>SMART RELAY V1.1</h1>";
          str += "<h2>Control local del dispositivo, en caso de fallas en la conexion</h2>";
          str += "<h3>Version de hardware: 1.1, Version del Firmware 1.2</h3>";
          str += "<p>Estado de RL1 <b>";
          str += RL1Status;
          str += "</b></p>";
           if (RL1Status=="Off") str += "<p><a href=\"/RL1/on\"><button class=\"button\">ON</button></a></p>";
           else          str += "<p><a href=\"/RL1/off\"><button class=\"button button2\">OFF</button></a></p>";
          str += "<p>Estado de RL2 <b>";
          str += RL2Status; 
          str += "</b></p>";
            if (RL2Status=="Off") str += "<p><a href=\"/RL2/on\"><button class=\"button\">ON</button></a></p>";
            else         str += "<p><a href=\"/RL2/off\"><button class=\"button button2\">OFF</button></a></p>";         
          str += "</body></html>\n";
          return str;
}

Later, when I finish it, i’ll post the whole project. Thanks!