Blynk.run() needed?

I’m working on a battery powered data logger that at given intervals sends data to a private Blynk server and receives data/commands from the Android app.
For the rest of the time the device (Wemos D1 mini based) is in DeepSleep. So the loop() routine is empty and there is no main Blynk.run() loop.

It may be worth to underline that my sketch only uses virtual pins .
At every cycle it calls Blynk.syncAll() to collect possible new data from app and uses virtualWrite() to update all variables.

Do I really need to ever call Blynk.run() in such situation?
At present, since it doesn’t harm :grin:, I call it here and there, when there is the time (for example in waiting loops), but I’m not really sure if it’s needed at all.

Anybody can clarify this, please?

Not really needed and I’m always surprised when I see sketches sprinkled with Blynk.run() commands.

Probably becasue that is what is implied in the Docs… admittedly without clarification of that need only in special, long running loops… or poor coding :stuck_out_tongue_winking_eye:

Most sketches should only need a single Blynk.run() in loop(). Good coding should eliminate the requirement elsewhere unless you have a very complex function.

1 Like

yup

So, if I got it right,if I have the following code fragment, in which the device is waiting for some input from the user (for example a click on a button widget)

void setup() {
  bool button_click=false;

  .
  //Blynk connection stuff
  .
  .

  while (!button_click) {
    yield();
  }
  .
  .
  //do stuff
  .
  .
}

BLYNK_WRITE(V1)
{
  if (param.asInt()==1)
    button_click=true;
}

This code would NOT work, because without a Blynk.run() the BLYNK_WRITE() callback wouldn’t have a chance to run, right?
So would the following change to the code do the trick?

void setup() {
  bool button_click=false;

  .
  //Blynk connection stuff>
  .
  .

  while (!button_click) {
    yield();
    Blynk.run();
  }
  .
  .
  //do stuff
  .
  .
}

BLYNK_WRITE(V1)
{
  if (param.asInt()==1)
    button_click=true;
}

As an alternative (in this example), could I just call Blynk.syncVirtual(V1) instead of Blynk.run()?

Why would you have the button_click in setup()? Is it really needed there?

Costas, that was just a simple example to better ask my question, the same code fragment could have been included inside another function, do you think it matters ?

The important point here is that it would never be inside the loop() routine, as it is empty in my case (see my first post)

Very bad example. You shouldn’t use a while() function in setup() and best avoided anywhere.
That is why you have the BlynkTimer to check for events at intervals, not check indefinitely with while().

Maybe I’ll look through this thread again and see where it’s going.

Do you an example of a waiting loop in plain English, not in code format?

It’s rare for a project that uses deepSleep to have a waiting loop and they should generally be avoided in all projects.

If you need to send a signal to the MCU can’t you simply set a timer i.e. if no button pressed in 10s then device goes into deepSleep?

Are your buttons virtual or physical?

Very bad example

The example was not meant to show the best possible programming practices, only to better explain my question without distracting with unnecessary details.

You shouldn’t use a while() function in setup() and best avoided anywhere.

Sorry, I can’t agree with such a general statement. I guess 99.99% of programmers are happily using while() in their programs. Like in any other iterative programming constructs, the programmer is responsible to ensure that there is a way out of the loop. That’s the main concern. Often, a millis()-based timeout is used for this.

setup() IMHO has nothing special when compared to any other function that is called in the sketch, except it is the function that’s executed at first. Really, I’m missing your point here. Maybe you should better contextualize your statement against usage of while() instruction.

Do you an example of a waiting loop in plain English, not in code format?

Well, an application interactively waiting for an input from the user (to act accordingly afterwards), may be a good example of a waiting loop. While the user decides what to do, the program has nothing better to do than waiting.
It used to be called “polling” (still is?). In other words, you wait (do nothing) until you get what you need. I agree that it is not considered the most efficient programming practice, it should be avoided in all situations where the CPU has a better way to spend its time than doing nothing, but in some situations it can’t be avoided. For example, if you have an application that works on a wifi connection, you can’t go on exchanging data on the network if you didn’t connect to WiFi before. So I can’t see what other you can do than waiting while the connection is being established (the classic
while(!WiFi.status() == WL_CONNECTED) { } you see everywhere ) .
And YES, adding a timeout to this while() would be appropriate too!

If you need to send a signal to the MCU can’t you simply set a timer i.e. if no button pressed in 10s then device goes into deepSleep?

I could reply by simply asking you what would the sketch be supposed to do while the 10s pass (other than a waiting loop), but I want to give you a more useful answer.

I’m doing things more complex than sending a signal to the MPU. For example, I have a calibration procedure in my sketch, in which the sketch prompts the user to input several numeric values in succession. So each step requires a waiting loop, I can’t go in DeepSleep in the middle of such interactive procedure! So, I DO need waiting loops here! What else I can do?

However, you are right where you suggest that if the user doesn’t input any data in a “long” time, a timeout should allow the execution to go on, and finally jumping into the DeepSleep that is at the end of the setup() routine. It is exactly what I’m doing. But this doesn’t save me from the while() loops for the “normal” delays when the user is “thinking”, don’t you agree?
Since I don’t see while() instructions as evil, I’m not worried about using them, only concern is if it is required to call Blynk.run() inside them, to keep the whole Blynk environment “alive”.

Are your buttons virtual or physical?

As I wrote in my first post, I’m only using virtual pins.
Not just buttons though, I’m also using several types of widgets, including terminal, history graphs, menu, lcd display, RTC…

I would do this without any while statements, a single Blynk.run() in loop() and BlynkTimer. If you want to use while statements that’s entirely your choice. To answer your question yes you will need to sprinkle your sketch with Blynk.run() as you will miss the heartbeat timeout in your while statements and be disconnected from the server.

You don’t have that problem with the BlynkTimer.

Hey, great! Care to share some more details about how would you manage it? But please remember that in my context I can’t use the loop() function. It would be nice to learn from your techniques, nevertheless.

Ok, fair enough. But if you could show me how to better do the same things without using while()s, I wouldn’t have any problem in changing my current approach.

This answers my question and confirms what I suspected! Thank you!

Still struggle to understand how a synchronous tool like a timer would help in a live interaction with a human (that is totally asynchronous). Again, some deeper explaination/examples would be appreciated!

The assumption with battery operated deepSleep projects is that you want the batteries to last as long as possible and therefore you can’t give users an indefinite amount of time to enter the parameters.

If this assumption is wrong for your project please advise why.

If the assumption is correct then I would have thought that the use of BlynkTimer is obvious.

I see no reason why loop() can’t be used in your project from the details you have provided. It doesn’t mean the loop() will continue indefinitely and that is where BlynkTimer comes in to call deepSleep().

If you require further details please indicate:

  1. Are the parameters independent of each other or are they in some way linked?
  2. Does the user need to enter the parameters every time the MCU wakes?
  3. How long do you expect the user to need to enter each parameter?

My device is a variant of this one: Ispindel
The original project supports a number of IOT services, but not Blynk.
I wrote an extension to support Blynk, after this, as Blynk has really good interactive widgets, I extended the original software with new features, most of them only possible because of Blynk. At the current stage, the application is Blynk-only.

It is a device that is immersed in fermenting beer and is able to measure density through its tilt angle, by using an accelerometer. It also has a temperature sensor, and optionally a timer, and a micro SD card (slightly different hardware prototypes).
A fermentation process usually takes 1 to 2 weeks, during this time the device is immersed in the wort and hopefully it should not be touched.
So the battery needs to be able to survive for up to two weeks. Currently, with the sleep interval set to 15 minutes, my prototypes are doing much better (losing approx 0.15V/week), so no real concern.
A data collection cycle typically takes something between 5 to 7 seconds.
The main calibration is the tilt angle calibration, and it is usually done offline and once, before immersing the device into the wort. So battery consumption during calibration is not a real issue, because I could always re-charge the battery after the calibration and before putting the device into the liquid . However I found this not really necessary as this calibration doesn’t require much time, and battery consumption during this operation is negligible.

Sorry I am still missing how to use loop() here. Typical cycle is: wake up - collect sensor data - connect to Blyink - check if any control variable has changed - send data to Blynk- write data (and any changed parameter) to SD/SPIFFS - check if user has required interaction - go to sleep.
loop() is useful when you have a sequence to repeat, here between DeepSleeps there is only one cycle.

In some cases parameters are not independent. For example, for tilt angle calibration the first parameter is the number of sample points the user is going to supply to calibrate (the higher the number, the better the calibration), so the number of subsequent prompts by the program depends on this first parameter.

Surely not. Parameters are stored in SD/SPIFFS and read at every cycle. Calibration is usually made once for every fermentation

If Blynk had direct numeric input widgets (PLEASE DO IT!!!), it would take a couple of seconds. With buttons (that is what I’m currently using) it may require 20 seconds or so (by average). For tilt calibration I’m supplying 3 parameters for each calibration point. So a 4-points calibration may take about 4 minutes.

So it’s not Blynk related and that’s why you didn’t understand the use of loop() and BlynkTimer.
Not sure why you mentioned users entering parameters and your while loop waiting for the data to be entered when you are not using Blynk to enter the parameters.

Maybe by “usually” you mean before you discovered the power of Blynk.

On that basis, with Blynk the pseudo code I would use without any while statements is

void loop(){
  if(parameters_set == true){
    readSensors();
  }
  else{
    Blynk.run();
    timer.run();  // used to read parameters from Blynk widgets
  }
}

void readSensors(){
  // read the sensors
  // virtualWrite sensor details to server
  // deepSleep
}

Understand?

No, it is implemented using Blynk. The interaction is made by an interface (in a specific Blynk Tab), which includes a menu, a LCD widget and 5 buttons.

The confusion may have been generated by my usage of the word “offline” I just meant that the operation is not typically done while the device is already immersed int the wort.

OK but do you now see how useful Bylnk.run() and Blynk.timer() are in loop() to collect the parameters without while statements even in a deepSleep project?

I surely find Blynk a really powerful tool, else I wouldn’t have created a custom Blynk-only version of the spindle, I would have just continued using UBIDOTS.
But here, by “usually” I just meant “usually”. That is, while the software allows to calibrate the device while it is already in the fermenting wort, it is usually not necessary since you have already done the calibration before.

You are not demonstrating anything here, but I believe it may be due to the misunderstanding about the interactive calibration.

Since the readSensors() part is always executed only once, your pseudo code looks equivalent to this one:

void setup() {
          if(parameters_set == true){
            readSensors();
          }
}

void loop(){
            Blynk.run();
            timer.run();  // used to read parameters from Blynk widgets
 }

 void readSensors() {
      // read the sensors
      // virtualWrite sensor details to server
      // deepSleep
  }

But I could have missed your point here, what is supposed to happen inside the loop()? Just the calibration routine?