Blynk components not running simultaneously

So I am having a little bit of trouble with my project. I am using an ultrasonic HCSR-04 to detect objects and then send a notification to my phone, all while the servo is simply pivoting or sweeping and an LED blinks. I want to get all of these to work simultaneously but right now, the servo completes its sweep, then the LED blinks once, then the ultrasonic detects an object and then I receive the notification. This won’t work as I need the notification as soon as the ultrasonic detects the object, it can’t wait until the servo and LED have finished their functions. (Here is a video of my testing to hopefully help understand the situation better: “https://www.youtube.com/watch?v=jfmx9rcqlw4”). Is this a problem to do with the coding? Or is it because the NodeMCU simply can’t power all these components and must do it individually? Much help would be appreciated. Thanks!

(p.s. I left out my auth token and SSID name and password for obvious reasons)

Hardware: NodeMCU-12E, Servo and HCSR04
Software: Using IOS 13.3.1 (Blynk App)

#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Servo.h>
#define TRIGGERPIN D1
#define ECHOPIN    D2
Servo myservo;  // create servo object to control a servo

int pos = 0;    // variable to store the servo position

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "RandomNumbersAndLetters";

char ssid[] = "Wi-FiNetwork";// Your WiFi credentials.
char pass[] = "Password";// Set password to "" for open networks.

WidgetLCD lcd(V1);
int LED = 15;

void setup() {
  pinMode(LED, OUTPUT);
  myservo.attach(0);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
pinMode(TRIGGERPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);
  Blynk.begin(auth, ssid, pass);
  // You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442);

  lcd.clear(); //Use it to clear the LCD Widget
  lcd.print(0, 0, "Distance in cm"); // use: (position X: 0-15, position Y: 0-1, "Message you want to print")
  // Please use timed events when LCD printintg in void loop to avoid sending too many commands
  // It will cause a FLOOD Error, and connection will be dropped
}

void loop() {
  digitalWrite(LED, HIGH);
  delay(500);
  digitalWrite(LED, LOW);
  delay(500);

    for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  
  lcd.clear();
  lcd.print(0, 0, "Distance(cm)"); // use: (position X: 0-15, position Y: 0-1, "Message you want to print")
  long duration, distance;
  digitalWrite(TRIGGERPIN, LOW);  
  delayMicroseconds(3); 
  
  digitalWrite(TRIGGERPIN, HIGH);
  delayMicroseconds(12); 
  
  digitalWrite(TRIGGERPIN, LOW);
  duration = pulseIn(ECHOPIN, HIGH);
  distance = (duration/2) / 29.1;
  Serial.print(distance);
  Serial.println("Cm");
  lcd.print(7, 1, distance);
  Blynk.run();
if (distance < 5){
  Blynk.notify("Notification Testing");
}
  delay(500);
}

All the function needs to be called with Blynktimer
Having code running inside loop will cause connection issues with Blynk server.
And no not use delay

delay() is a blocking function that completely stops your MCU for a specified time before resuming the loop execution.

Providing power to the components isn’t an issue, but the MCU is a single core, single threaded processor and a s result it can only do one thing at a time.
The workaround for this is to to do these things repetitively and quickly, so it appears that they are happening simultaneously. Obviously this only works to a certain degree, and it relies on well structured and tight code.
As you now know, you cant put all of the code in your void loop, and you cant use delays. You’ll also see in the “keep your void loop() clean” document that you cant do Blynk writes from the void loop and this also applies to Blynk notifications. In fact, notifications are limited to pone every 5 seconds, and as they are sent via a third party service that can actually take a while to arrive - depending to a degree on the priority settings you’ve used.

https://docs.blynk.cc/#widgets-notifications-push-notifications

Pete.

Ok cheers guys, I understand how this works now! Thanks for the help

So @PeteKnight, if I call a timer for a certain function such as sending notifications when the ultrasonic reads below a certain value and I run the timer (set to one second intervals) inside the void loop alongside a sweeping servo code, why don’t I receive the notification until the servo has finished its sweep? Is the timer basically just defining a variable and running it inside the void loop?

#define TRIGGERPIN D1
#define ECHOPIN    D2

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

BlynkTimer timer; 
Servo myservo;  
WidgetLCD lcd(V1);

int pos = 0;    

char auth[] = "";
char ssid[] = "";
char pass[] = ""; 

void setup() {
  myservo.attach(0); 
  Serial.begin(9600);
pinMode(TRIGGERPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);
  Blynk.begin(auth, ssid, pass);

  lcd.clear(); 
  lcd.print(0, 0, "Distance in cm"); 
 timer.setInterval(1000L, sensorDataSend); 
}

void sensorDataSend(){
  lcd.clear();
  lcd.print(0, 0, "Distance(cm)"); 
  long duration, distance;
  digitalWrite(TRIGGERPIN, LOW);  
  delayMicroseconds(3); 
  digitalWrite(TRIGGERPIN, HIGH);
  delayMicroseconds(12); 
  digitalWrite(TRIGGERPIN, LOW);
  duration = pulseIn(ECHOPIN, HIGH);
  distance = (duration/2) / 29.1;
  Serial.print(distance);
  Serial.println("Cm");
  lcd.print(7, 1, distance);
  if (distance < 5){
  Blynk.notify("Notification Testing");}
}


void loop() {
  for (pos = 0; pos <= 180; pos += 1) { 
    myservo.write(pos);            
    delay(15);                     
  }
  for (pos = 180; pos >= 0; pos -= 1) { 
    myservo.write(pos);              
    delay(15);                     
  } 

  Blynk.run();
  timer.run();
}```

I just need to receive the notification while the servo is sweeping, not after the servo has finished its sweep. How do I get around this? Much help would be appreciated!
Cheers, Lucas

I don’t think you’e grasped the “A single threaded processor can only do one thing at once” concept, or the “keep your void loop clean” concept either.

Your MCU will execute the 0-180 sweep, which will take a minimum of 180 x 15ms (2.7 seconds) to complete.
It will then execute the 180-0 sweep, taking another 2.7 seconds.
It will then execute the Blynk.run command, which allows the Blynk library to perform a handshake with the Blynk server and get any updated widget values.
It then executes the timer.run command, which checks if any timers are due to be executed. It will see that it’s at least 5.4 seconds since the sensorDataSend function was called (overdue by 4.4 seconds) so it will run that timer and execute the function.

In addition, your sensorDataSend function, which will send a Blynk notification once every second if distance < 5, so will max-out this limit and 80% of your notifications will be dropped when this situation is encountered.

If you want the notification to be sent mid-way between the 0-180 and 180-0 sweeps of your servo then that’s where you must put that command and it should probably be accompanied by a Blynk.run command.

But, non of this belongs in the void loop - it should be in a function that is called with a timer. Even then, there is a large risk of your device regularly disconnecting from the Blynk server, as the handshake handled by the Blynk.run command needs to be successful at least once every 10 seconds. At the moment, if one unsuccessful hands occurs then 10.8 seconds will have elapsed between successful handshakes and the Blynk server will decide that your MCU is Missing In Action and show it as disconnected. A re-connection process then needs to be completed before Blynk communications can recommence.

I also think that your using notifications in totally the wrong way. A notification should be an exceptional situation, normally used to tell you that something went wrong or that an unusual event has occurred. Other widgets are much more suited to observing the mid-way sweep of a servo.

Pete.