Non-Blocking Edgent Examples

Good Morning Everyone,

I’ve run some searches, and while I found some “old Blynk” posts and documents, I haven’t come up with something concrete using Edgent.

Before Edgent, there were workarounds to ensure a lost or non-existent internet connection wouldn’t block your main code, ensuring your device is still operating properly even in an “offline” mode. With Edgent, everything is much more integrated and I’ve been having a more difficult time figuring out a successful way for my code to run even when Blynk is not connected.

I’ve stumbled across some conversation regarding using the app_loop function but I am not having any success adding my own functions to this call. I’ve also tried using FreeRTOS with Blynk on one core and my application on another but I seem to be running into issues with Blynk not receiving the proper data from my application when accessing a variable where the value was put there by the other core.

Does anyone have any example code they have had luck with while using Edgent?
I know I don’t “have” to use Edgent, but I find the provisioning and OTA updates very handy to have.

Thanks in advance!

I have the same problem. If the internet connection is lost the sketch just locks up. Seems that the reconnection function is blocking. Any way to detect connection lost in this situation and have sketch take action to safe operation ?

I haven’t had any luck with a solution yet.
I ended up running into a weird provisioning issue that was just fixed with the most recent Blynk App update so now that I have that resolved I’m hoping to be able to come back to this problem.

I feel that there is definitely a solution in the app_loop function in BlynkEdgent.h but I haven’t been able to successfully put together a sketch that compiles properly yet.

If/when I figure out a solution I will be sure to update this post. Maybe now that more people have seen it someone will swing by with a solution they have figured out.

In theory, the solution should be the same as non-blocking code when using Blynk.config and Blynk.connect in a non-Edgent sketch.
That is to ensure that you don’t execute Blynk.run() unless you’ve first checked that Blynk.connected() is true.

Exactly how you implement that successfully, and periodically try to do a re-connection attempt with Edgent, is something that you’d need to play around with.

Pete.

Hey Pete,

You are absolutely correct, but in my experience so far that has been easier said than done. I haven’t found a way yet to implement a method of confirming that Blynk is connected within the Edgent framework without breaking many things. The app_loop in BlynkEdgent.h appears to be called regularly, even if Blynk is not connected and that’s why I’ve been focusing on it but adding functions to the app_loop hasn’t been as straightforward as I’ve been hoping either.

I should probably re-visit Blynk.run and Blynk.connected within Edgent and see if anything stands out at me now that I’ve been exploring other options for a while. Sometimes re-visiting with fresh insight leads to fresh thinking.

That’s right. The app_loop function in the Blynk Edgent should be called periodically, even when BlynkEdgent.run() is blocking. But you shouldn’t call any blocking functions in app_loop. You should also keep in mind that there’s no guarantee this function will be called frequently, sometimes it can skip a few seconds.

Using the second core of the esp32 is the best approach.

Hey John!

I’ve also attempted a dual core solution but I run into really odd issues that lead me to believe that portions of Blynk Edgent are using the second core in ways I can’t figure out.

Using FreeRTOS in addition to Blynk I can get a sketch to successfully compile and upload OTA. However after that I am unable to properly pull values from any of my sensors and I lose the ability to perform further OTA updates using Blynk.Air.

I haven’t found any reason for this examining all the different .h files involved in Blynk but there does appear to be dual core usage with Blynk already and it causes issues when trying to use the second core using FreeRTOS.

I’ve also ensured none of my functions in app_loop are blocking but I still seem to have issues. It’s probably a “me” issue to be honest and so far that route has seemed to be the most viable path forward for me so I’m still aiming in that direction. A couple skipped seconds isn’t an issue in my application as long as the overall system is still operating, even if somewhat delayed.

I’m going to re-write my entire program from scratch with app_loop utilization in mind. Currently I’ve been trying to adapt my pre-existing sketch but I think I will have better luck with a fresh start.

I’ll give it a try and see how it goes.

1 Like

Awesome, hopefully you have more success than I have so far!

1 Like

I don’t believe that Edgent is using both cores. It also depends exactly what you mean by the “second core”. Does this mean core 0 or core 1 ?

Does this mean that you are placing your own code within the app_loop rather than within the void loop?

The Edgent examples use Blynk.connect(0); in ConfigMode.h
This (in theory at least) specifies a 0 millisecond timeout for all attempts to connect to the Blynk server.
In practice, the minimal timeout is several seconds at least. Every time Blynk.run is executed, if the device isn’t connected to the Blynk server it will make an attempt to connect, then this will abort after the timeout period has passed.
If no timeout period is specified then the default is about 18 seconds.
So, with the timeout set to 0 milliseconds, and the actual timeout in this situation being (let’s say) 3 seconds, every time the void loop executes the following happens…

  • BlynkEdgent.run() is executed
  • app_loop is executed
  • runBlynkWithChecks() is executed and therefore
  • Blynk.run is executed.
  • If there’s no connection to the server then there is a 3 second blocking timeout occurs
  • The void loop, and therefore BlynkEdgent.run() is executed again

The result is one three second blocking delay, followed by another three second blocking delay, followed by another three second blocking delay……… etc etc etc.
This appears to the end user as one single continuous blocking delay.

This is why, before Blynk.run() is executed you need to do a Blynk.connected() test.

But, as I’ve said before, it’s more complicated than that with Edgent, as you also need to manage re-connection attempts every so often.

Pete.

1 Like

Seems to me that best solution would be for Edgent to manage an offline status itself, with a callback or similar so that application actions can be taken. Asking users to modify framework code or do head stands to do such a basic task seems convoluted. Blynk apps must exist in a world that is discontinuous and multimodal (Wifi, BLE, Cell) so we need our core framework to support this.

Hey Pete, thanks for the detailed reply.

Yes, I mean core 0 and 1. Depending on how my cores were configured I would either lose the ability to retrieve data from my DS18B20 sensor and DHT22 or I would lose the ability to OTA over Blynk.Air and the device would go offline however it would function in its “offline mode” in regards to any functions that don’t require temperature readings. The analogRead photocell sensor I use for light sensing was unaffected on either core, same with some simple limit switches and the ability to send driver commands to a motor driver.

Thank you for this breakdown, it’s the best layout I’ve seen to help me understand the background of Edgent more clearly. I’ll spend some more time here looking in ConfigMode.

I love the provisioning and OTA of Edgent but it sure can be a labyrinth for me sometimes.

The Edgent example is just that - an example. It’s not part of the library, so it’s there to give an out of the box working showcase of Provisioning and Blynk.Air.
What you do with it after that is up to you.

Pete.

I agree it’s definitely up to the user to adapt/create things to their need.

That being said, I do find it surprising that the example code has blocking code such as it does. So far it has been making it tricky to keep all the functionality of Edgent combined with non-blocking code in the case of a disconnect or no connect.

I’m sure I/We will all get to the bottom of it and find a nice easy to implement solution but it would be nice if it wasn’t needed in the first place.

That being said, I assume the devs have more mission critical stuff they are working on.

1 Like

I’m sure that the devs who are still living in the Ukraine have more pressing things than Blynk to worry about!

Pete.

No argument there! I am perfectly content to try and puzzle through this. There are far more important things in this world than if my chicken coop goes offline and stops working!

I know many of the devs are in Ukraine, I wish nothing but the best for everyone there and I absolutely don’t expect much Blynk development for a while based on that, like you say, far more pressing things!

2 Likes

Hey @hms11 I just did a quick test, and everything seems to be working as expected.
Here’s an example you can try. In this example, you should be able to control a relay module with or without an internet connection.

#define BLYNK_TEMPLATE_ID "Your_template_ID"
#define BLYNK_DEVICE_NAME "Your_device_name"

#define BLYNK_FIRMWARE_VERSION        "0.1.0"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_WROVER_BOARD
//#define USE_TTGO_T7
//#define USE_ESP32C3_DEV_MODULE
//#define USE_ESP32S2_DEV_KIT

#include "BlynkEdgent.h"

const int relayPin = 23;
const int btnPin = 13;

int relayState = HIGH;
int btnState = LOW;


void TaskCheck( void *pvParameters );

void setup()
{
  Serial.begin(115200);
  delay(100);

  pinMode(relayPin, OUTPUT);
  pinMode(btnPin, INPUT_PULLUP);

  
  xTaskCreatePinnedToCore(
    TaskCheck
    ,  "TaskCheck"
    ,  4096
    ,  NULL
    ,  1
    ,  NULL 
    ,  ARDUINO_RUNNING_CORE);


  BlynkEdgent.begin();
}

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



BLYNK_WRITE(V0) {
  relayState = param.asInt();
  digitalWrite(relayPin, relayState);
}

void TaskCheck(void *pvParameters)
{
  (void) pvParameters;

  for (;;)
  {
    if (digitalRead(btnPin) == LOW) {
    
    if (btnState != LOW) {

      // Toggle LED state
      relayState = !relayState;
      digitalWrite(relayPin, relayState);

      // Update Button Widget
      Blynk.virtualWrite(V0, relayState);
    }
    btnState = LOW;
  } else {
    btnState = HIGH;
  }
    vTaskDelay(100);
    
  }
}
2 Likes

Hey John, thank you for this! I’ll play around with it today and see how it works adapting my sketch to it.
Thanks again!

1 Like

Hey John,

I’ll update tonight with actual serial monitor logs but this appears to break something in the OTA portion of Edgent. I loaded a blank edgent sketch on a device and then did an OTA update to your example sketch. The device never came back online after pushing the update through.

I’ll have to go back through my notes, but I feel this was one of the issues I ran into when attempting FreeRTOS solutions myself.