BLYNK_WRITE() triggered late

Hi,

I’m working on Wemos D1 temperature sensor project. I’ve removed any unnecessary code to clearly illustrate the issue. There are few steps supposed to be executed:

  • Wake up, connect to wifi and local Blynk server
  • Restore last min temperature value from Blynk server
  • Measure current temperature and update min temperature value (if needed)
  • Write to Blynk server current temperature and new min temperature
  • Go to deep sleep

See below the simplified sketch:

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include "WifiBlynkPass.h"	// wifi & local Blynk server parameter (e.g. wifi_ssid, my_ip, blynkServer)
#include <DHT.h>

DHT dht(D1, DHT11);

unsigned long prevMillis;
float curTemp = 0;
float minTemp = 99;

void setup() {
  Serial.begin(115200);
  pinMode(D1, INPUT);
  pinMode(D0, WAKEUP_PULLUP);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.config(my_ip, gateway, mask);
  Serial.println("\n01 System started, connecting WiFi ");
  WiFi.begin(wifi_ssid,wifi_pass);
  Blynk.config(blynkAuth,blynkServer,blynkPort);
  prevMillis = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - prevMillis < 7000) {
    delay(200);
  }
  Blynk.connect();
  if (Blynk.connected()) {
    Serial.println("02 Wi-Fi connected, Blynk connected");  
	TempUpdate();
    Blynk.run();
  }
  Serial.println("06 Going to sleep...");
  system_deep_sleep(10 * 1000 * 1000);
  delay(100);
}

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1);
  Serial.println("03 Blynk Connection Handler kicked off");
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("04 minTemp from Blynk server: " + String(minTemp));  
}

void TempUpdate() {
  delay(500);			// Added for testing only
  curTemp = dht.readTemperature();
  minTemp = min(curTemp, minTemp);
  Serial.println("05 CurTemp from Sensor: " + String(curTemp) + "˚C, Calculated MinTemp: " + String(minTemp) + "˚C");
  Blynk.virtualWrite(V0, curTemp);
  Blynk.virtualWrite(V1, minTemp);
}

void loop() {
}

I’ve added some serial output lines, and I was expecting them to be printed according to the numbering in the sketch, i.e.:

01 System started, connecting WiFi 
02 Blynk Connection Handler kicked off
03 minTemp read from Blynk server: 23.00˚C
04 Current Temp from sensor: 23.10˚C, Calculated Min Temp: 23.00˚C
05 Going to sleep...

Unfortunately, it looks like the BLYNK_WRITE(V1) function is triggered late, i.e., only after the current temperature was read from the sensor and the min temperature was calculated. See the actual serial output below:

01 System started, connecting WiFi 
02 Blynk Connection Handler kicked off
04 Current Temp from sensor: 23.10˚C, Calculated Min Temp: 23.10˚C
03 minTemp read from Blynk server: 23.00˚C
05 Going to sleep...

In result, the minTemp is not calculated correctly, additionally the calculated minTemp is then overwritten by the minTemp value that was received from Blynk server.

I don’t know what’s causing late triggering of BLYNK_WRITE(V1) function. I understand it should be triggered immediately after Blynk was connected. I thought there may be some delays in communication with Blynk server, so I’ve even added little delay before curTemp reading but it didn’t help - the minTemp value is always received from the Blynk server after curTemp was read.

Could you please help fixing the issue, i.e. making sure the last minTemp was restored from Blynk server immediately after Wemos was started and Blynk connected.

Thanks
Maciej

BLYNK_WRITE is a function called every time device gets an update of Virtual Pin value from the server or app. You should use BLYNK_CONNECTED function instead.

It seems slightly odd, but when you do the Blynk.connected() test it doesn’t actually mean that data is actually being exchanged between the device and the server, it simply means that the initial connection has been established and the Auth token validated.

You’d be better putting all of your important code in BLYNK_CONNECTED so that it executes after data is actually being transferred between server and device.
You may also want to put your deep sleep call in the BLYNK_WRITE(V1) callback so that you 100% know that that has been triggered.

I’d also put Blynk.run(); in your void loop so that the Blynk library functions are being triggered siring these small waiting periods.

Pete.

Thanks John93 for the reply

Actually, I’m using both BLYNK_CONNECTED and BLYNK_WRITE in the sketch but it seems my comment was confusing. My understanding is that once the device connected to Blynk server, BLYNK_CONNECTED is being called and pin V1 is being synced with the value from Blynk server. Once the value of pin V1 was updated then BLYNK_WRITE is being called. Is it correct understanding of the process?

Thanks
Maciej

Thanks Pete for the reply.

I followed your advice and moved the ‘important code’, i.e. TempUpdate() to BLYNK_CONNECTED function. I’ve also put system_deep_sleep callout there as well.

Note please that I can’t put deep sleep in the BLYNK_WRITE as suggested, because it’d be called before all remaining code was executed. I’m expecting the following event order:

  • Connect to Blynk server
  • Sync min temperature value from Blynk server to pin V1 (it’s done within BLYNK_CONNECTED function)
  • Assign V1 pin value to minTemp variable (it’s done within BLYNK_WRITE function)
  • Measure current temperature, calculate new min temperature and write both values to Blynk server

Last but not least, putting Blynk.run() in void loop caused it’s never being called so I moved it to BLYNK_CONNECTED.

See my updated sketch below:

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include "WifiBlynkPass.h"				// wifi and Blynk parameter definitions (e.g. wifi_ssid, my_ip, blynkServer)
#include <DHT.h>

DHT dht(D1, DHT11);

unsigned long prevMillis;
float curTemp = 0;
float minTemp = 99;

void setup() {
  Serial.begin(115200);
  pinMode(D1, INPUT);
  pinMode(D0, WAKEUP_PULLUP);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.config(my_ip, gateway, mask);
  Serial.println("\n01 System started, connecting WiFi ");
  WiFi.begin(wifi_ssid,wifi_pass);
  Blynk.config(blynkAuth,blynkServer,blynkPort);
  prevMillis = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - prevMillis < 7000) {
    delay(200);
  }
  Blynk.connect();
}

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1);
  Serial.println("02 Blynk Connection Handler kicked off");
  TempUpdate();
  Blynk.run();
  Serial.println("05 Going to sleep...");
  system_deep_sleep(10 * 1000 * 1000);
  delay(100);
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("03 minTemp read from Blynk server: " + String(minTemp) + "˚C");  
}

void TempUpdate() {
  delay(500);
  curTemp = dht.readTemperature();
  minTemp = min(curTemp, minTemp);
  Serial.println("04 Current Temp from sensor: " + String(curTemp) + "˚C, Calculated Min Temp: " + String(minTemp) + "˚C");
  Blynk.virtualWrite(V0, curTemp);
  Blynk.virtualWrite(V1, minTemp);
}

void loop() {
}

Unfortunately, either I didn’t understand your suggestions well or they didn’t fix the issue. I still can see incorrect serial output order:

01 System started, connecting WiFi 
02 Blynk Connection Handler kicked off
04 Current Temp from sensor: 22.60˚C, Calculated Min Temp: 22.60˚C
03 minTemp read from Blynk server: 22.50˚C
05 Going to sleep...

Any other tips?

Thanks
Maciej

Once your void setup has completed, you should find that the void loop is being executed several times before BLYNK_CONNECTED executes.

You can have multiple Blynk.run commands dotted around your code if you wish, it doesn’t do any harm.

In that case, put all of your important code, and your deep sleep command in BLYNK_WRITE(V1) instead.

Pete.

I tried updating my sketch following the tips provided by John93 and Pete. Unfortunately, my target sketch includes more BLYNK_WRITE() functions for various pins and I wasn’t sure in which order they’ll be called and in which BLYNK_WRITE() instance the deep sleep command should be put. I’ve spent some time on testing various scenarios and It looks like I found the working solution without any excessive code listed in BLYNK_WRITE(). Actually, I’ve made only 3 changes to the initial sketch that was posted at the beginning of this topic:

  • I’ve added delay(100) just after Blynk.connect() - it’s crucial and without it the printed sequence is still wrong
  • I’ve moved Blynk.run() before TempUpdate() function
  • I’ve added another Blynk.run() at the end of TempUpdate() function to synchronize data with Blynk server after temp measurement/calculation:

Before applying the above 3 changes the Serial output looked as follows (steps 05 is before 04, which is incorrect):

01 System started, connecting WiFi 
02 Wi-Fi connected, connecting Blynk
03 Blynk Connection Handler kicked off
05 CurTemp from Sensor: 24.70˚C, Calculated MinTemp: 24.70˚C
04 minTemp from Blynk server: 23.20
06 Going to sleep...

after applying the above 3 changes the output looks fine and all the steps are in order as expected:

01 System started, connecting WiFi 
02 Wi-Fi connected, connecting Blynk
03 Blynk Connection Handler kicked off
04 minTemp from Blynk server: 23.20
05 CurTemp from Sensor: 24.60˚C, Calculated MinTemp: 23.20˚C
06 Going to sleep...

Unfortunately, I don’t fully understand how exactly the applied changes fixed my issue. Nevertheless, after extensive testing, I can confirm the above fix works like a charm.

The full Sketch is listed below, I hope it may be helpful for anyone facing the same issues:

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include "WifiBlynkPass.h"	// wifi & local Blynk server parameter (e.g. wifi_ssid, my_ip, blynkServer)
#include <DHT.h>

DHT dht(D1, DHT11);

unsigned long prevMillis;
float curTemp = 0;
float minTemp = 99;

void setup() {
  Serial.begin(115200);
  pinMode(D1, INPUT);
  pinMode(D0, WAKEUP_PULLUP);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.config(my_ip, gateway, mask);
  Serial.println("\n01 System started, connecting WiFi ");
  WiFi.begin(wifi_ssid,wifi_pass);
  Blynk.config(blynkAuth,blynkServer,blynkPort);
  prevMillis = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - prevMillis < 7000) {
    delay(200);
  }
  Serial.println("02 Wi-Fi connected, connecting Blynk");  
  Blynk.connect();
  delay(100);
  Blynk.run();
  TempUpdate();
  Serial.println("06 Going to sleep...");
  system_deep_sleep(10 * 1000 * 1000);
  delay(100);
}

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1);
  Serial.println("03 Blynk Connection Handler kicked off");
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("04 minTemp from Blynk server: " + String(minTemp));  
}

void TempUpdate() {
  curTemp = dht.readTemperature();
  minTemp = min(curTemp, minTemp);
  Serial.println("05 CurTemp from Sensor: " + String(curTemp) + "˚C, Calculated MinTemp: " + String(minTemp) + "˚C");
  Blynk.virtualWrite(V0, curTemp);
  Blynk.virtualWrite(V1, minTemp);
  Blynk.run();
}

void loop() {
}

Thanks again guys for your help.

Best regards
Maciej

Me neither!

I’m rather surprised, and I think there are better ways of doing this to 100% ensure the results you want.

In whatever sequence the Blynk.syncVirtual(vPin) commands are arranged in BLYNK_CONNECTED()

Personally I’d call TempUpdate(); as the last command in BLYNK_WRITE(V1)

and I’d still recommend having Blynk.run() in your void loop in addition to its current occurrences.

Pete.

Thanks Pete for the reply.

I’ve spent some more time on testing and it looks like it’s still tricky for me. Initially, I followed your tips: just moved TempUpdate() call out to BLYNK_WRITE(V1) function and added BlynkRun() in void loop(). The sketch worked well.

Then I’ve added V2 pin sync and new BLYNK_WRITE(V2) instance, as below:

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1, V2);
  Serial.println("03 Blynk Connection Handler kicked off");
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("04 minTemp from Blynk server: " + String(minTemp));  
  TempUpdate();
}

BLYNK_WRITE(V2) {
  maxTemp = param.asFloat();
  Serial.println("04 maxTemp read from Blynk server: " + String(maxTemp) + "˚C");  
}

Unfortunately, the order was incorrect: TempUpdate() was called out from BLYNK_WRITE(V1) and was executed before BLYNK_WRITE(V2) - it’d be understood assuming TempUpdate() should be called out from the very last BLYNK_WRITE() instance in in order to get all pin values before it was called.

Keeping that in mind, I moved TempUpdate() call out from BLYNK_WRITE(V1) to BLYNK_WRITE(V2), see the updated sketch below:

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include "WifiBlynkPass.h"	// wifi & local Blynk server parameter (e.g. wifi_ssid, my_ip, blynkServer)
#include <DHT.h>

DHT dht(D1, DHT11);

unsigned long prevMillis;
float curTemp = 0;
float minTemp = 99;
float maxTemp = -99;

void setup() {
  Serial.begin(115200);
  pinMode(D1, INPUT);
  pinMode(D0, WAKEUP_PULLUP);
  dht.begin();
  WiFi.mode(WIFI_STA);
  WiFi.config(my_ip, gateway, mask);
  Serial.println("\n01 System started, connecting WiFi ");
  WiFi.begin(wifi_ssid,wifi_pass);
  Blynk.config(blynkAuth,blynkServer,blynkPort);
  prevMillis = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - prevMillis < 7000) {
    delay(200);
  }
  Serial.println("02 Wi-Fi connected, connecting Blynk");  
  Blynk.connect();
  delay(100);
  Blynk.run();
  Serial.println("06 Going to sleep...");
  system_deep_sleep(10 * 1000 * 1000);
  delay(100);
}

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1, V2);
  Serial.println("03 Blynk Connection Handler kicked off");
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("04 minTemp from Blynk server: " + String(minTemp));  
}

BLYNK_WRITE(V2) {
  maxTemp = param.asFloat();
  Serial.println("04 maxTemp read from Blynk server: " + String(maxTemp) + "˚C");  
  TempUpdate();
}

void TempUpdate() {
  curTemp = dht.readTemperature();
  minTemp = min(curTemp, minTemp);
  maxTemp = max(curTemp, maxTemp);
  Serial.println("05 Current Temp from sensor: " + String(curTemp) + "˚C, Calculated Min Temp: " + String(minTemp) + "˚C");
  Blynk.virtualWrite(V0, curTemp);
  Blynk.virtualWrite(V1, minTemp);
  Blynk.virtualWrite(V2, maxTemp);
  Blynk.run();
}

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

The above code is executed in expected order, i.e.: BLYNK_WRITE(V1) → BLYNK WRITE(V2) → TempUpdate(). Unfortunately, I have 2 concerns:

  1. I don’t know if BLYNK_WRITE() functions are always executed in the same order (i.e. BLYNK_WRITE(V1) first then BLYNK_WRITE(V2) and so on). If that’s not the case then the code may or may not run in expected order.
  2. Calling out TempUpdate() from BLYNK_WRITE() makes the code a bit challenging to maintain: each time new BLYNK_WRITE() function was added or removed, then the TempUpdate() may need to be moved to the very last BLYNK_WRITE() instance. If BLYNK_READ() was also used then TempUpdate() would need to be moved either to the very last BLYNK_READ() or very last BLYNK_WRITE() instance depending which is executed last.

I really appreciate your support and I don’t want to be the smartest one here but it seems that keeping TempUpdate() in void setup() instead of one of BLYNK_WRITE() instances may be easier to maintain, especially when the code may grow or be reused on other projects.

Could you please provide any other tips that’d help fixing my issue, while keeping all BLYNK_WRITE() instances clean and executing TempUpdate() from void setup() instead.

Maybe you (or someone else) could share any piece of working sketch that I’d adapt to my needs. I don’t think what I’m trying to achieve is really unusual. I just need to execute the following steps in the order exactly as outlined below:

  1. Wake up ESP8266
  2. Read few pin values from Blynk server
  3. Process the values taken from Blynk server in any other functions
  4. Go to sleep

Thanks
Maciej

Of course - why would you expect anything else?

Yes.

As I said before, they will be called…

So if your BLYNK_CONNECTED() function calls Blynk.syncVirtual(V99) before Blynk.syncVirtual(V1) then they’ll trigger in the sequence V99 followed by V1.

So why not call TempUpdate() as the last item in BLYNK_CONNECTED() ?
I only suggested calling it as the last item in BLYNK_WRITE(V1) because you hadn’t explained the requirement for your other BLYNK_WRITE(vPin) functions, and that they need to execute before TempUpdate() is called.

I’ve never understood the need for the BLYNK_READ() command to exist, and have never found a situation where it is needed in Blynk IoT.

Absolutely not. You lose all control over the sequence if you do that.

What you have is 99% there.

Pete.

Thanks Pete again for very good explanation, I understand now the order in which BLYNK_WRITE() instances are supposed to be called out depending on Blynk.syncVirtual() commands.Unfortunately, either I’m still missing something or there’s any bug in legacy Blynk server that I’m using.

I followed your advise and moved TempUpdate() to BLYNK_CONNECT(), my code looks now as follows (It’s simplified sketch with just single pin sync):

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V1);
  Serial.println("03 Blynk Connection Handler kicked off");
  TempUpdate();
}

BLYNK_WRITE(V1) {
  minTemp = param.asFloat();
  Serial.println("04 minTemp read from Blynk server: " + String(minTemp));  
}

void TempUpdate() {
  curTemp = dht.readTemperature();
  minTemp = min(curTemp, minTemp);
  Serial.println("05 Current Temp from sensor: " + String(curTemp) + "˚C, Calculated Min Temp: " + String(minTemp) + "˚C");
  Blynk.virtualWrite(V0, curTemp);
  Blynk.virtualWrite(V1, minTemp);
  Blynk.run();
}

Based on the sketch I’d expect first BLYNK_WRITE() to be called out by Blynk.sync.Virtual(V1) and then TempUpdate() to be called. Unfortunately the functions are being called in wrong order:

03 Blynk Connection Handler kicked off
05 Current Temp from sensor: 23.20˚C, Calculated Min Temp: 23.20˚C
04 minTemp read from Blynk server: 22.90

I’ve tried adding delay() before TempUpdate(), I’ve also tried adding Blynk.run() there, but unfortunately neither of the changes fixed the issue. The BLYNK_WRITE() is always executed after TempUpdate().

It seems there’s any dependency or trigger in calling out BLYNK_WRITE() that I’m missing. It’s causing BLYNK_WRITE() being delayed and executed only after TempUpdate() function. Any idea what could be holding BLYNK_WRITE() execution or where/how to investigate it?

Thanks
Maciej

@maciejz99 Please edit your post, using the pencil icon at the bottom, and add triple backticks at the beginning and end of your code so that it displays correctly.
Triple backticks look like this:
```

Copy and paste these if you can’t find the correct symbol on your keyboard.

Pete.

Okay, it looks like your TempUpdate() function will need to be called from your final BLYNK_WRITE function.

Pete.

Pete,

While I still don’t understand why the simple code is not behaving as expected, I’ll stop digging in it for now and just follow your recommendation as the workaround for the issue I’m facing.

Many thanks for all your support.
Maciej