BLYNK
HOME       📲 GETTING STARTED       📗 DOCS       ❓HELP CENTER       👉 SKETCH BUILDER

Concurrent BLYNK_WRITE's


#13

“Parallel” is a poorly-chosen word here as it conjures-up “parallel processing” at the thread level. My apologies. I do not mean that.

I think “non-sequential” is better language perhaps? I will make a clean, simple example to help clarify (at least for myself!) what I thought was a change to how BLYNK_WRITE invocations now check to see if one is currently active and if so, queue-up a new request versus just embarking on a new instantiation and “inserting” a sub-process at the time of a new triggering event.


#14

There’s no such logic by default. You can build it on top, if you need this…


#15

Here is a complete example to use instead of my code fragment. You need a project with a button (V0) and a term window (V1). Just press the button a few times using 0.5.* libs vs. 0.4.* to see the different behavior that I have been trying to describe.


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

//Blynk setup
char ssid[] = "SSID";
char pass[] = "PWD";
char auth[] = "BlynkProjectToken";

WidgetTerminal blynkTerm(V1);

BLYNK_WRITE(V0) {
  if (param.asInt() == 1) { //if button pressed down
    displayNumbers();
  }
}

void displayNumbers() { 
 for (int i=1; i <= 5; i++){ //count to 5
   blynkTerm.println(i);
   blynkTerm.flush();
   myDelay(500);
 }
}

void myDelay(long ms){
   long stopWhen = ms + millis();
   while(millis() <= stopWhen){
       Blynk.run();
       yield(); //make this loop non-blocking so ESP can maintain WiFi
   }
}

void setup() {
    Blynk.begin(auth, ssid, pass);

    while (!Blynk.connected()) {
    }
}

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

My test ran on a NodeMCU v1.0.

Findings:
Using Blynk Lib ver 0.4.10:
Repeated button presses call BLYNK_WRITE in an event-driven fashion and does not yield to already-running BLYNK_WRITE instances. Many nested instances can run without locking or crashing.

Using Blynk Lib ver 0.5.3:
Two button strikes call BLYNK_WRITE in a sequenced fashion (queuing - the second press yields to an already-running BLYNK_WRITE instance). With 3 rapid button presses, the processing halts without crashing (“queued” calls are dropped and even the running instance is terminated).

I hope the code and your own experience can describe better than what I have tried to put into words!

I am not sure if the queuing and halting I experience is intentional in the 0.5.0 release, but I guess if this is just how it will work from now on, then we probably should limit blynk.run() usage to the void loop() and let the blynk server manage the queue of app events. However, this conclusion causes issues for applications that require blynk.delay() functionality.

I look forward to any comments on these findings / thoughts.

Thanks again!


#16

But blocking BLYNK_WRITE is something you should not do in first place…
Yes we can change something, but it is still not parallel.
You are calling terminal functions, which in some cases decides to call Blynk.run() internally.


#17

The 0.5.* library architecture is blocking BLYNK_WRITE’s, not me! :slight_smile: But, REALLY! There is now a limit of one concurrent instance of BLYNK_WRITE and a maximum of 1 BLYNK_WRITE in the queue. Those limits were introduced in 0.5.0. Anyway, you probably know all this better than anyone else here. If you actually think I am the cause of “the blockage”, then please let me know what I am missing.

It probably makes sense. Developers would want Blynk to respond immediately to BLYNK_WRITE events and not queue them up, disregard them or cause partial code execution. Perhaps a simple reversion to the 0.4.* behavior on these instantiations would be the quick, cheap medicine?

Agreed. I think “concurrent” might be a better description (I changed the thread title as well).

Yes. If you think we would benefit from a “Serial” example, I would be glad to remove the terminal widget and re-post. Just let me know.

Again, thanks!


#18

@CampHamp Perhaps you are running into the anti-flooding protection that was introduced into 0.5.0

It basically helps keep those that don’t use proper timing and logic from flooding and causing disconnections.

I had ran into some governor like loop issues with some of my very fast processing projects (only possible due to internal network and Local Server) and supposedly the bypass command that seemed to help is

#define BLYNK_MSG_LIMIT 0

You can try that, but it will not guaranty that your use of blocking processes will not continue to cause issues as more features are added into the library.


#19

Blocking means that something is causing another thing to timeout. Please point out the timeout condition and the suspect. I may just be missing some mysterious thing, but my logic says as long as we do Blynk.run() constantly and yield() to ESP WiFi, then we are OK.

Next topic: Anti-Flooding condition. Not sending much data and not too fast either, right? I put Serial on there just to be sure and see no errors.

I think what we see is just a design decision that the handler not allow soft-interruption of BLYNK_WRITE. Each event is discreet and must complete before another event is handled. Sounds like the very abstract FIFO description to me in the release notes.

It essentially makes the system queue-based and could provide for course-grain, asynchronous communication. My issue is the upgrade impact is not clear, if you rely on the event-driven interrupts then they will need to be fixed (be made queue-based as well) and the event handler queue is tiny (1 event) and is not graceful when overfilled.


#20

As stated before, I have many projects, some with way too much going on (just code testbenchs) and I have no problems running multiple button, slider, timer called BLYNK_WRITE() functions “simultaneously”… AKA as fast as I can possibly press and adjust widgets.

BLYNK_WRITE() functions in of them selves are not blocking… but if they contain blocking code (AKA something that prevents the MCU from responding to normal stimuli) then that is the issue, not the packaging.

Instead of this cyclical argument… can you provide a sketch and QR code that can definitively show your repeatable issue… without actually using blocking processes like delay() and such? So far what you have provides has programmatic issues (when used in a Blynk based IoT communicative type sketch) that have been referenced by myself or the developers.


#21

I already did that. There is no delay() in the code I provided. Easy to read, install and reproduce. Go for it!


#22

image

Sorry, I missed pasting this part…

image

and this part…

image

Not sorry for the “crayon” writing… that was just for my fun :stuck_out_tongue_winking_eye:


#23

2.5 seconds of what? blynking!


#24

Well, I am wasting more time than that, which is “blocking” my own projects, while dealing with this senseless argument :stuck_out_tongue:

Program smarter or complain about the tools provided… I will leave you to your choices.

https://www.google.ca/search?q=what+does+delay+do+to+an+arduino


#25

Wow. Nice.


#27

To those who have read this far, thanks. I am a user, a client and a huge fan of Blynk and am motivated in my discussion only with its improvement.

I created a useful wood stove controller that uses a stepper motor to open/close the air flow. I can set a target room temp, stove temp or just choose the air flow % manually.

Here’s the motor, wearing a stainless hat that plugs the air intake:

Now that it is freezing cold in New Hampshire, I dusted off the equipment added some minor code tweaks and reinstalled the controller. When I went to calibrate the actuator, the “Calibrate” button failed to work because of the change in the Blynk Library. I am sure of that and it’s no big deal - I easily could work around it. I was just looking for advice on the cause before I figured it out through my test script.

What I found was somewhat interesting, more from an academic/design perspective than “Oh my god! Help me fix this!”.

If you use a button to send an event to a device, let’s say “calibrate”, then you want to have another button (or the same button in my case) that sends an event to “confirm” (and then another event that says “goHigherUp”, etc), there are different ways to handle that sequence. One method is to call a calibrate() function right from the BLYNK_WRITE method on the button press.

But while your code is twiddling around with the motor, it is not running Blynk.run()… so the device will never receive new events and the device will not get a new signal to “confirm”. So, let’s put Blynk.run() into the calibrate() loop, so it can get that “confirm” event (which is received through the same BLYNK_WRITE function and just flags that the button was pressed again). That worked perfectly well for me until the 0.5.* lib, now I see that Blynk.run() will only run a single BLYNK_WRITE at a time. I never got that confirmation button press, even while looping on Blynk.run().

So, the solution is to leave the BLYNK_WRITE methods in a hurry! You can do that by calling functions using the timer.setTimeout(10,calibrate) technique that I mentioned earlier. This will launch the function through a queue manager and the BLYNK_WRITE function is finished – no strings attached.

Is this the “best practice”? Under these library conditions, I think it is. Can I live with the library change? Sure, now that I know what I am dealing with.

Am I blocking? I don’t think so!

Hope that helps others understand what happens “under the hood”.

-Jamie


#28

OK, I am a bit bored… and loose focus too often sometimes, thus the movie is on pause :stuck_out_tongue_winking_eye:

Here is a nice little sketch with three simultaneously running BLYNK_WRITE() functions, each doing their own thing…

  1. Increment and display a number every 100ms on the Terminal if the White button is ON, reset when OFF.

  2. Flashing one of Blynk’s new large LED’s (BETA App at time of this post) depending on the frequency set by the Slider Widget (AKA my variable timer) 100ms-5000ms range.

  3. Increment/Decrement a number, based on the Step Widget… as fast as you can press.

And as I kept recommending to avoid, wherever possible due to their blocking nature… not a single delay(), for() or while() is to be found… and only one Blynk.run() command required… thus no function is blocking the others.

Small Disclaimer… I am messing heavily with Blynktimers here, and not really paying attention to giving each timed action enough ‘time’ to complete, so there can be some slight degradation (AKA slowdown) when running the variable timed function at fast rates.

However, the BLYNK_WRITE() function containing the simple Step Widget and indicating Display widget is completely unaffected by these slight timer degradations.

Yep, with smarter coding practice, multiple BLYNK_WRITE() functions working concurrently as normal :stuck_out_tongue_winking_eye:


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

//Blynk setup
char ssid[] = "SSID";
char pass[] = "PASS";
char auth[] = "AUTH";

long variableTime;
int number;
int varTimer;  // Setup Timer ID
int numTimer;  // Setup Timer ID
int flashTimer;  // Setup Timer ID

//  WidgetTerminal blynkTerm(V1);  // Not required as I am using direct Blynk.virtualWrite() commands to the terminal
BlynkTimer timer;

void setup() {
  Blynk.begin(auth, ssid, pass);  // Blynk.begin() is a blocking function until connected, so no need to have extra connection check delays
}

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

BLYNK_CONNECTED() {
  Blynk.syncVirtual(V0);
  Blynk.syncVirtual(V3);
}


BLYNK_WRITE(V0) {  // Switch Widget for incremental counting to terminal
  if (param.asInt() == 1) { //if button pressed down
    Blynk.virtualWrite(V1, 0);  // Send number to Terminal
    // Timed Lambda Function - LED Flash
    numTimer = timer.setInterval(100L, []() {
      number++; // Increment number
      Blynk.virtualWrite(V1, "-");  // Send number to Terminal
      Blynk.virtualWrite(V1, number);  // Send number to Terminal
    });  // END Timer Function
  } else {
    timer.deleteTimer(numTimer);  // Cancel previous Timeout Timer
    number = 0;  // Reset Number
  }
}



BLYNK_WRITE(V3) { // Slider Widget for interval timing
  timer.deleteTimer(varTimer);  // Cancel previous Timeout Timer
  Blynk.virtualWrite(V2, 0);  // Turn OFF LED
  variableTime = param.asInt();  // Get new interval time
  if (variableTime <= 100) { // prevents a timer from becoming 100 or less
    variableTime = 100;
  }
  Blynk.virtualWrite(V6, variableTime);
  timerLoop();  // Call your timed loop
}



BLYNK_WRITE(V4) {  // Increment/Decrement a number, based on the Step Widget
  Blynk.virtualWrite(V5, param.asInt());
}



void timerLoop() {  // This is my, adjustable, variable timer setup flashing an LED
  timer.deleteTimer(varTimer);  // Cancel existing Timeout Timer
  Blynk.virtualWrite(V2, 255);  // Turn ON LED
  // Timed Lambda Function - LED Flash OFF
  flashTimer = timer.setTimeout(50L, []() {
    Blynk.virtualWrite(V2, 0);  // Turn OFF LED
  });  // END Timer Function
  varTimer = timer.setTimeout(variableTime, timerLoop);  // Set new Timeout timer and call this function again in X seconds
}

And for others to check out… I have also used various timer methods in many code examples - C++ Blynk - Code Examples for Basic Tasks (Work in Progress)


Led controller disconnects
#29

Just because there’s a mess of crazy going on doesn’t mean any two BLYNK_WRITE’s are running concurrently.

You do know that, right?


#30

Single core MCUs don’t actually multitask like real SOC or computers… they just calculate really fast and give that sense… You know that, right?

My point is that your arguments blaming the library can be proven false when using proper programming methods recommended by Blynk.

If it can calculate faster then I can push buttons, and quick enough to do the job (I have Rovers and other fast motor controlled projects that work just fine)… who cares how the library processes the code.


#31

So what were you try to prove then?! You’re just not following this thread. This is not about multitasking, but you could start a new thread if you want to discuss that instead.

I’m examining the effect of a library update. That’s all. You’re getting all emotional – it’s kind of weird. I am not blaming anyone. Please, go enjoy your movie.

You should close this thread before you embarrass yourself any further.


#32

One that is 11 months old… way to keep current :stuck_out_tongue_winking_eye:

Not as weird as you thinking you know my mood… I CAN (sometimes) multitask and was doing other stuff in-between typing as my thought processes came back to this non-issue… I enjoy the intellectual challenges… PS movie was great :oncoming_police_car::moneybag::moneybag::moneybag::gun:

Not embarrassed at all… I have been doing this forum thing for a long time… and as indicated by the Blynk developers themselves, my explanations were more on-track than yours. Sorry if you can’t get it to work anymore, try some of my programming methods :wink:

But good idea on the thread… it has reached a conclusion, so closing it as requested.


closed #33