Virtual pins stopped syncing

Dear Pete, could you please check and give the final recommendation? Otherwise I will wait two weeks and regard the topic as closed with a final conclusion of the topic. The newly updated code below works well:

#define BLYNK_TEMPLATE_ID           "xxx"
#define BLYNK_TEMPLATE_NAME         "xxx"
#define BLYNK_AUTH_TOKEN            "xxx"

#include <WiFi.h>
#include <WiFiClient.h>
#include <esp_wifi.h>
#include <BlynkSimpleEsp32.h>
#include <TimeLib.h>

#define SERIAL_BAUD 115200

int checkst = 0; 
int sens = 0;                                  
String CheckTime;
long randN;
BlynkTimer timer;                                  
int error_count = 0;
bool receive = true;  //This indicates which cycle is active: when device wakes it first receives the data (true) and then sends a new sensor value (false)
bool send_or_receive = true;  //This indicates send or receive cycle for the function sending and checking the data from the server: send (true), receive (false)
int SleepInterval = 10; //Set sleep cycle interval in seconds

void setup() 
{
  sens = Sensors_Read();  //This function simulates a sensor reading, it generates a random integer value from 1 to 100
  Serial.begin(SERIAL_BAUD);
  Serial.println("The device woke up, trying to connect to Blynk..");
  if(!Connect_Blynk()) {
    Switch_Relay(60);  //If connection to Blynk failed the relay should be 'on'.
    go_to_sleep();     //Go to sleep if Blynk is not connected
  }
  while(receive){Blynk.run();} //if connection is there, wait until data arrives from the server and then send the new data
  Send_data(sens);
  if(WiFi.status() == WL_CONNECTED) WiFi.disconnect();
  go_to_sleep(); //Data sent, the device goes to sleep
}

void Switch_Relay(int sw)
{
  if(sw > 50){
    Serial.println("The relay is ON!");
  }
  else{
    Serial.println("The relay is OFF!");
  }
}

void Send_data(int dat)
{
  unsigned long TimerStart = 0;
  receive = false;
  timer.setInterval(150L, send_and_receive);
  TimerStart = millis(); //Timer starts
  //Serial.println("Starttimer = " + String(TimerStart));
  while((millis() - TimerStart < 1000) && checkst != sens) 
  {
    timer.run();
    Blynk.run();  //Data will be sent during 1s, if unsuccessful, the device will report an error and go to sleep, if successful the device will report the new value sent and will go to sleep
  }
  if(checkst != sens) Serial.println("Data haven't reached the server but the time has run out."); else Serial.println("The data has successfully reached the server! Sensor's new value = " + String(dat));
}

void send_and_receive()
{
  if (send_or_receive)
  {
    Serial.println("Sending the new sensor value = " + String(sens));
    Blynk.virtualWrite(V1, sens);
    send_or_receive = false;
  }  
  else 
  {
    Blynk.syncVirtual(V1);
  }
}

int Sensors_Read()
{
  return(random(99)+1);
}

bool Connect_Blynk() 
{
  char ssid[] = "xxx";
  char pass[] = "xxx";
  unsigned long TimerStart = 0;
  WiFi.begin(ssid, pass);
  TimerStart = millis();
  //15s to try to connect to WiFi
  while (WiFi.status() != WL_CONNECTED && (millis() - TimerStart < 15000)) timer.run();
  //if successful attempt to connect to Blynk
  if(WiFi.status() == WL_CONNECTED){
    Blynk.config(BLYNK_AUTH_TOKEN);
    TimerStart = millis();
    while (!Blynk.connected() && (millis() - TimerStart < 15000)) {Blynk.connect(1000);}
    if(Blynk.connected()){
      Serial.println("Connected to Blynk!");
      return(true);
    } 
    else{
      Serial.println("Was not able to connect to Blynk");
      if(WiFi.status() == WL_CONNECTED) WiFi.disconnect();
      return(false);
    }
  }
  //if not successful print the message and go to sleep
  else{
    Serial.println("Was not able to connect to WiFi");
    return(false);
  }
}

void go_to_sleep()
{
  //Go to sleep
  Serial.println("Going to sleep..");
  esp_sleep_enable_timer_wakeup(1000000ULL * SleepInterval);
  esp_deep_sleep_start();
}

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

BLYNK_WRITE(V1)
{
  checkst = param.asInt(); // Get value as integer
  if(receive) //The next block is only active if the data should be received immediately after the device wakes up
  {
    if(checkst == 0)
    {
      //If the data is not received checkst should be equal to 0
      Serial.println("The data was not recieved correctly! The relay stays as was.");
    }
    else
    {
      Serial.println("Received data from Blynk! Sensor's old value = " + String(checkst));
      Switch_Relay(checkst);  //This function switches relay 'on' if the value read from Blynk > 50 and switches it 'off' if the value is < 50;
    }
    
    receive = false;
  }
  else //This block is only active during the data transmission to Blynk after the sensors have been read
  {
    send_or_receive = true;
  }
}

BLYNK_CONNECTED()
{
  Blynk.syncVirtual(V1);
}

If it works for you then stick with it.
As Iā€™ve said before, the code structure isnā€™t what Iā€™d use for a deep sleep sketch, but if it meets your needs then thatā€™s the important thing.

Pete.

Dear Pete,

Could you please provide further recommendations, since I already implemented following of your advice:

  1. I got rid of the while() loops to wait for events and use only the Blynk timers.
  2. I got rid of blocking functions like Blynk.begin and manage both the WiFi and Blynk.connect separately.
  3. The device goes to sleep in the following cases (aligned with your recommendations above):
    a. the device fails to connect to WiFi
    b. 1. the device fails to connect to Blynk
    c. 1. the device has connected to Blynk and BLYNK_WRITE() has been executed and a reading has been taken and uploaded, given that the maximum timeout of 2s for the data to be sent

I spent some time implementing the recommendations and it would be a pity if I somehow did it inefficiently. Thank you in advance!

#define BLYNK_TEMPLATE_ID           "xxx"
#define BLYNK_TEMPLATE_NAME         "xxx"
#define BLYNK_AUTH_TOKEN            "xxx"

#include <WiFi.h>
#include <WiFiClient.h>
#include <esp_wifi.h>
#include <BlynkSimpleEsp32.h>
#include <TimeLib.h>

#define SERIAL_BAUD 115200

int checkst = 0; 
int sens = 0;                                  
String CheckTime;
long randN;
BlynkTimer timer;                                  
int error_count = 0;
bool receive = true;  //This indicates which cycle is active: when device wakes it first receives the data (true) and then sends a new sensor value (false)
bool send_or_receive = true;  //This indicates send or receive cycle for the function sending and checking the data from the server: send (true), receive (false)
int SleepInterval = 10; //Set sleep cycle interval in seconds

void setup() 
{
  sens = Sensors_Read();  //This function simulates a sensor reading, it generates a random integer value from 1 to 100
  Serial.begin(SERIAL_BAUD);
  Serial.println("The device woke up, trying to connect to Blynk..");
  if(!Connect_Blynk()) {
    Switch_Relay(60);  //If connection to Blynk failed the relay should be 'on'.
    go_to_sleep();     //Go to sleep if Blynk is not connected
  }
  while(receive){Blynk.run();} //if connection is there, wait until data arrives from the server and then send the new data
  Send_data(sens); //This sets 2s time out, during which the Send_data function tries to send the data
  timer.setTimeout(2000, []()  
  {  
    // When the timer completes, any code here will be executed
    if(checkst != sens) Serial.println("Data hasn't reached the server but the time has run out."); else Serial.println("The data has successfully reached the server! Sensor's new value = " + String(sens));
    if(WiFi.status() == WL_CONNECTED) WiFi.disconnect();
    go_to_sleep(); //The device goes to sleep after timer waited for 2s, independently from the fact if the data has been sent successfully
  });
}

void Switch_Relay(int sw)
{
  if(sw > 50){
    Serial.println("The relay is ON!");
  }
  else{
    Serial.println("The relay is OFF!");
  }
}

void Send_data(int dat)
{
  receive = false;
  timer.setInterval(150L, send_and_receive);
}

void send_and_receive()
{
  if (send_or_receive)
  {
    Serial.println("Sending the new sensor value = " + String(sens));
    Blynk.virtualWrite(V1, sens);
    send_or_receive = false;
  }  
  else 
  {
    Blynk.syncVirtual(V1);
  }
}

int Sensors_Read()
{
  return(random(99)+1);
}

bool Connect_Blynk() 
{
  char ssid[] = "xxx";
  char pass[] = "xxx";
  unsigned long TimerStart = 0;
  WiFi.begin(ssid, pass);
  TimerStart = millis();
  //15s to try to connect to WiFi
  while (WiFi.status() != WL_CONNECTED && (millis() - TimerStart < 15000)) timer.run();
  //if successful attempt to connect to Blynk
  if(WiFi.status() == WL_CONNECTED){
    Blynk.config(BLYNK_AUTH_TOKEN);
    Blynk.connect(10000);
    if(Blynk.connected()){
      Serial.println("Connected to Blynk!");
      return(true);
    } 
    else{
      Serial.println("Was not able to connect to Blynk");
      if(WiFi.status() == WL_CONNECTED) WiFi.disconnect();
      return(false);
    }
  }
  //if not successful print the message and go to sleep
  else{
    Serial.println("Was not able to connect to WiFi");
    return(false);
  }
}

void go_to_sleep()
{
  //Go to sleep
  Serial.println("Going to sleep..");
  esp_sleep_enable_timer_wakeup(1000000ULL * SleepInterval);
  esp_deep_sleep_start();
}

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

BLYNK_WRITE(V1)
{
  checkst = param.asInt(); // Get value as integer
  if(receive) //The next block is only active if the data should be received immediately after the device wakes up
  {
    if(checkst == 0)
    {
      //If the data is not received checkst should be equal to 0
      Serial.println("The data was not recieved correctly! The relay stays as was.");
    }
    else
    {
      Serial.println("Received data from Blynk! Sensor's old value = " + String(checkst));
      Switch_Relay(checkst);  //This function switches relay 'on' if the value read from Blynk > 50 and switches it 'off' if the value is < 50;
    }
    receive = false;
  }
  else //This block is only active during the data transmission to Blynk after the sensors have been read
  {
    if(checkst == sens)
    {
      Serial.println("The data has reached the server, checkst = " + String(checkst));
      if(WiFi.status() == WL_CONNECTED) WiFi.disconnect();
      go_to_sleep(); //The device goes to sleep since the data reached the server
    }
    send_or_receive = true;
  }
}

BLYNK_CONNECTED()
{
  Blynk.syncVirtual(V1);
}

Weā€™ve had quite long discussions about your code structure and you donā€™t seem interested in taking onboard my comments about that.
Much of your current code is taken from the example I wrote to disprove your assertion that there are issues with the Blynk server. This has no place in your final deepsleep sketch, and I made this clear at the time and subsequentlyā€¦

Youā€™re still using BlynkTimer in your deepsleep sketch and youā€™ve structured your code to work that way, rather than taking the advice I gave beforeā€¦

So, as I said, if your code works for you then stick with it.
If you want something different then maybe you should re-read this topic from the beginning and take onboard the comments Iā€™ve made.
Thereā€™s no benefit to me to critique your code line by line when Iā€™ve been through that process before without any success.

Iā€™m not going to write your code for you, and Iā€™m not going to keep repeating my advice, so my input into this topic is ended.

Pete.

Dear Pete,

I am really thankful for the time you spent assisting me, nevertheless ignoring the problem does not help resolving it. I tested your code and sent the terminal output with the error yet in October, but somehow you do not wish to acknowledge it. Could it because of your association with Blynk?

It does not make sense sending a device to sleep mode, after a data exchange failed. If you believe you may provide an alternative solution to control for a potential error, please give me an example.

I am not a developer but out of pure logic it is unclear to me why Blynk in so many years failed to implement simple and necessary updates to some of its functions, e.g. controlling of data transmission for errors and implementing feedback of a data transfer. To me it looks like an inefficient management since it is the management of the company who must orchestrate developerā€™s work and give them right incentives to improve the quality of the product. Unfortunately the ostrich tactics only aggravates the problem.

By helping to expose a problem you will help Blynk rather than harm it. I hope for your understanding.

I didnā€™t ignore ā€œthe problemā€. I gave you feedback on why ā€œthe problemā€ isnā€™t a problem with Blynk server or libraries, but a problem with the way that you are using these tools, and once again, itā€™s you who chose to ignore feedback.

What association do you think I have with Blynk?

I never suggested that you should.

Iā€™m not gong to write your code for you, as I already said. Iā€™ve discussed in depth what the issues with your code are, and the problems that you are creating with the way that youā€™re using (or not using) the tools at your disposal within the Blynk library.

Iā€™ve discussed this issue before, and my answer is the sameā€¦

As I said before, thatā€™s something youā€™d need to take-up with Blynk.
My thoughts on the subject - for what they are worth, areā€¦

  • If this ā€œproblemā€ was actually a problem then Blynk would have taken steps to resolve it

  • There are tools available to allow Blynk users to verify the data that has been written to the server - as Iā€™ve demonstrated in my example code

  • Implementing a system which echoed-back every Blynk.virtualWrite and validated that the returned value matched the sent value, and re-sending the value until it does match would dramatically increase server traffic and eat-up valuable resources at both the server and the MCU side of the process. 99.9999% of users would have no use for this functionality. The 0.0001% if users who require this functionality could use the workaround to do this check within their sketch.

  • Blynk is primarily an online control and UI system which expects devices to be online constantly so that they can be controlled. Utilising deepsleep is contrary to the basic tenants of the Blynk architecture, so isnā€™t directly supported. Once again, there are workarounds to this, and tools within the Blynk server-side system which accommodate this, but itā€™s not the core mode of operation. Hence, why you donā€™t see Blynk example sketches that utilise deepsleep. If you want to use deepsleep effectively (which really means having your device awake for the shortest possible length of time) then you have to structure your code differently - thinking ā€œoutside of the boxā€ as far as code structure is concerned. Iā€™ve done quite a bit of work in this area, and have shared my thoughts on the b
    best way to do this - but as Iā€™ve already said this advice has been ignored. If there are ostriches in the room then maybe youā€™ll see them by looking in the mirror :wink:

Pete

Dear Pete,

Now I believe you are contradicting to yourself:

How come it is not a problem with Blynk server or libraries, if the data I send and the data I get back is not the same in less than 27k tries of sending few bytes of data? Could you imagine a ā€˜reliableā€™ way of data transfer, say for payment transactions, that makes so many errors possible? It all happened with the code you wrote yourself, not me.

Now I admit you imply that I may solve this problem by sending and receiving the data and comparing it. This is exactly what I tried to achieve with my, as you call it, ā€˜marginalā€™ code. True, you provided much better solution, but then you wrote that it is not compatible with the deep sleep mode. You wrote that the majority of the code is likely to live in BLYNK_CONNECTED() and BLYNK_WRITE(), which I tried. Unfortunately I do not have any idea, how I may check/control for the errors without using either of timers, millis, comparisons, while loops or delays. I already acknowledged multiple times that my code is not optimal and came to you for the support, so it is definitely not me who should look in the mirror. I also do not ask you to write code for me, but just give me an idea. If you do not have better idea (which I doubt) just say so and we are done.

Your feedback on my code wasā€¦

thenā€¦

As the code was sending data every 400ms thatā€™s one error in every 13,500 attempts.
I then suggested an improvementā€¦

I have no idea what the ā€œless than 27k triesā€ you mention actually means, but itā€™s not empirical test data that youā€™ve shared before as far as I can see.

What I was saying is that you had gone down a rabbit hole with chasing a non-existent issue and that the code I wrote to demonstrate this was not relevant to your overall goal of using deep sleep.
If youā€™ve tested the approach of placing the majority of the code in BLYNK_CONNECTED() and BLYNK_WRITE() but donā€™t then know how to retrieve the data and validate it without using loops, delays, millis comparisons etc then the sensible thing to do would be to ask, the solution is actually very simple.

Anyhow, Iā€™m tired of attempting to provide assistance when it is clearly isnā€™t appreciated. Iā€™ll use my time helping others who appreciate the input I provide. Maybe other Blynk community members will step-in and help you to create a more optimal codebase if thatā€™s what you are really hoping to achieve.

Good luck with your project.

Pete.

You are absolutely correct, this is 13.5k attempts! Why is it relevant that it is ā€˜not empirical test dataā€™, I do not have any idea, since the same may happen with any data.

This is clearly not true. I tested it, see the last example of code and also asked you ā€˜Could you please provide further recommendations?ā€™ I also was polite with you all the time writing ā€˜I appreciate your help, thank you, etcā€¦ā€™ Unfortunately I cannot characterize your replies similarly. Writing ā€˜I am tired fromā€¦ā€™ , or ā€˜your code is very oddā€™, using such words as ā€˜marginalā€™ is condescending and unprofessional. Iā€™m grateful for the help you provided, but I would refrain from further communication with you.