Explain the Blynk.syncVirtual(V?) and how to repeat the same activity or stop the activity form a function that is called by a BLYNK_WRITE(V?) function

Hi @Gunner,
I’m reading your projects, first thanks for the share, those are great for new Blynk/Arduino fans like myself.
I totally get the timer class and objects, using the instances to perform actions at predefined intervals over and over.
I think I also understand the BLYNK_WRITE(V?) functions get called anytime a Blynk button is pressed for example, so no need to have those functions setup in timers or the main loop(), but where I’m struggling a little at the present time is to either repeat the same activity or stop the activity form a function that is called by a BLYNK_WRITE(V?) function.
For example, with the press of a button, I can blink a LED based on BLYNK_WRITE(V?), in a “for” loop for a duration of say 8 seconds. Then if I want to perform the same task again, I have to press the same button 2 or 3 times for it to start the blinking process again. So I’m wondering if you could explain the Blynk.syncVirtual(V?) function call, what is it used for and from your experience would it help with the above issue I’m seeing?
Also, my project would have to be able to “break” from a “for” loop, or somehow interrupt the blinking led process when another button is pressed. Again, I don’t think timers come into play here, since I only want to cause activity and stop activity when a user presses one button or another. What do you recommend? I don’t see any examples of these above mentioned concerns.
Thanks

Thanks @aclogics for your appreciation of my Code Examples topic.

I moved your post into its own topic for better discussion…

First, the Blynk.syncVirtual(vPin) command is basically the device code emulating your pressing a button or moving a slider, etc on the App.

So for example, you press a button (in switch mode & set to V8) to turn on an action… but you want to have the device be able to turn it off again after a set amount of time (in case you forgot or something :wink: )

So the sketch will use a timer… probably a Timeout, to run a Blynk.virtualWrite(V8, 0) to change the state of a button from ON to OFF but then need to follow up with a Blynk.syncVirtual(V8) to “act” as if you pressed it, and thus run the BLYNK_WRITE(V8) function to process the action.

1 Like

One way or repeating an action with a timer is to use a setTimer with a preset number of iterations

int setTimer(long d, timer_callback f, int n)
Call function f every d milliseconds for n times. The callback function must be declared as void f(). After f has been called the specified number of times, the interval is deleted, therefore the value timerId is no longer valid.

void repeatMeFiveTimes() {
    // do something
}

timerId = timer.setTimer(1000, repeatMeFiveTimes, 5);

As for all the different ways to use timers… well that is a whole lesson of it’s own… and one I am still learning :smile:

But you can enable, disable, restart and delete timers… All of this is sorta described in the SimpleTimer library page here:

https://playground.arduino.cc/Code/SimpleTimer

1 Like

Hi Gunner,
Just to be certain you understand my problem, looping or repeating is not a problem, my issue is that the trigger comes from Blynk_Write() function, based on the press of a virtual button. The first press seems to call the function right away, but after execution is finished, if I want to repeat the process it seems I have to press the same button 2 to 4 times for it to start again. That is problem #1.
Question #2 is, once a button press triggers a loop, can the press of another virtual button cancel or interrupt the loop logic?
Thanks

All comes down to how you code things…

For example, a press and release of a Button widget will actually call it’s associated BLYNK_WRITE() function twice, once for each state change. So you need to write all functions to account for that with if else logic.

BLYNK_WRITE(V0) // Button or Switch Widget
{
  ButtonState = param.asInt();
  if (ButtonState == 1) {
    // Start your thing
  } else {
    // Stop your thing
  }
}
BLYNK_WRITE(V0) // Button or Switch Widget
{
  ButtonState = param.asInt();
  if (ButtonState == 1) {
    // Do something only if Button ON
  }
}

These commands can also be shorthanded like this… but probably only for 0/1 logic

BLYNK_WRITE(V0) // Button or Switch Widget
{
  if (param.asInt()) { // proceed if 1
    // Do somthing only if Button ON
  }
}

As for needing to press multiple times… similar situation as above… each press and release calls the function, and if the device hasen’t finished whatever the function is doing the next time it gets called, it will try to double, triple, and so on, the actions until the cascading causes issues. The solution is to use comparison flags that prevent further processing until the initial one is completed.

BLYNK_WRITE(V0) // Switch Widget
{
  ButtonState = param.asInt();
  if (ButtonState == 1 & FlagState == 0 {  // Run only if Switch ON and Flag set to 0
    FlagState = 1;  // Set flag to prevent multiple occurrences.
    // Start your thing and let it finish
    // Example; a possible repeating timer
    // NOTE: these following three commands will run even if your timer has not completed
    // (becasue it is non-blocking)... so you may need to code them differently, like in the
    // other timer called function that only processes them when it is completed.
    FlagState = 0;  // Reset flag
    Blynk.virtualWrite(V0, 0);  // Set Switch OFF
    Blynk.syncVirtual(V0);  // Reprocess this function
  } else { // Run if Switch OFF
    // Stop/interrupt your thing (if possible)
    // Example; disable/delete the timer if it is still running.
  }
}

As for interrupting a sequence… well depends on how the sequence runs, and if it is blocking or not… but yes, there are lots of different ways to do that.

Hard to provide much clarity for generic questions as there are usually many ways to program the same thing.

2 Likes

Thanks Gunner, that level of detailed explanation is extraordinary, much appreciated.
Here is what I wrote based on your feedback and my needs, if you have a minute to read through this perhaps something I missed or something doesn’t make sense? The code is short and sweet, but I haven’t had a chance to try this code yet, will do that soon.
Thanks again!

#define BLYNK_RED "#D3435C"
#define BLYNK_GREEN "#23C48E"

#include <SoftwareSerial.h>

#include <BlynkSimpleStream.h>
#include <SimpleTimer.h>

char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

int TimerID = 0;
int numbTimers = 0;
int numLoop = 0;
SimpleTimer Timer;

void acty_on(){
  Blynk.setProperty(V29, "color", BLYNK_RED);led29.on();  // Activity Status Red On while working
}

void acty_off(){
  Blynk.setProperty(V29, "color", BLYNK_GREEN);led29.on();  // Activity Status Green On while on Standby
}

// Draw Red square while on Standby
void stop_on(){
  //light red LED
}

// Erase Red square before Drawing arrows 
void stop_off(){
  // erase/blank red LED
}

// Blink LED 
void ArrowDown(){
  for (int x=0;x < 8;x++)      {
          Blynk.virtualWrite(V12, 1023);      
          Blynk.virtualWrite(V12, 0);         
     }
     Blynk.virtualWrite(V31, 0); //change PIN state
     Blynk.syncVirtual(V31); // force state change
     stop_on();
     acty_off();
}

// Interrupt Activity when Stop button pressed
BLYNK_WRITE(V1){
        int pinValue = param.asInt(); // assigning incoming value from pin V1 to a variable
        if (pinValue == 1){
          stop_on();
          numbTimers = Timer.getNumTimers();
          for(int i = 0;i<=numbTimers;i++){
            Timer.deleteTimer(i);
          }
          if (numLoop == 1){
            Blynk.virtualWrite(V31, 0);
            Blynk.syncVirtual(V31); 
          }
          else if (numLoop == 2){
            //future option
          }
          numLoop = 0;
          acty_off();
    }
}

// Call Function to Blink LED
BLYNK_WRITE(V31){
      int pinValue = param.asInt(); // assigning incoming value from pin V31 to a variable
      if (pinValue == 1){
        acty_on();
        stop_off();
        numLoop = 1;
        TimerID = Timer.setTimeout(100,ArrowDown);
      }
}

void setup(){
  Serial.begin(9600);
  Blynk.begin(Serial, auth);
}

// This should execute upon connecting to Blynk server
BLYNK_CONNECTED(){
  stop_on();    
  acty_off();

}

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

I have never grouped commands on the same line like this… don’t know if that works or not.

In all your Blynk Functions you are using local variables… as long as you only need that variable within the function it is fine, otherwise you should declare them as Global (in your pre-setup) and use discrete naming as needed.

https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/scope/

1 Like

@Gunner, thanks for the feedback, I will let you know how it works once I get a chance to test this.

The semicolon acts as end of command, so should totally be ok, if I base my assumption on the fact C/C++ works like this.

And for now, those variables are not needed outside the scope of the Blynk functions, but if the need arises I’ll be sure to change them.

Thanks again! I’m especially anxious to see how the logic of the Blynk functions calling timers and if the interrupt button will work at deleting the active timer(s). :weary: