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.
Could you please provide further recommendations, since I already implemented following of your advice:
I got rid of the while() loops to wait for events and use only the Blynk timers.
I got rid of blocking functions like Blynk.begin and manage both the WiFi and Blynk.connect separately.
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.
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
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.
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.
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.