Need help with Blynk Project with devices that randomly go offline

I just recently worked on my first Blynk project and am having connectivity issues. For some reason, the BlynkEdgent ESP32 device will randomly go offline while running. This project is a pretty simple concept, we collect weight data from a scale and transmit differentials every minute. Whenever weight becomes unstable, we wait 30 seconds for stabilization and then restart the process. When the device was in my office, it stayed permanently online but keeps going offline at their facility. I thought it might be the signal, so I started checking the signal strength. I am attaching a picture below of the signal strength noticed while calling WiFi.RSSI(). At the facility, the average RSSI value is -67 which is not so bad. I’m thinking my device here at the office is not connected to their scales so doesn’t run the entire program, but possibly the program is getting stuck in an infinite loop when connected to a scale. I checked and double-checked but can’t find anything that would cause this in my code. The only thing I can think of is either while trying to submit an HTTPS request it freezes and times out or it gets stuck in another subroutine that I haven’t written. I am attaching the code below and some other relevant pictures and docs. Another thing I am not sure that I am doing right is running Blynk.run() in multiple places such as the secondary loop that is infinite until the weight has stabilized (stabilityWait()) and that might cause problems as well. I have omitted some of the variables due to sensitive IDs on our side, so the code will not compile just how it is below. Please let me know anything I can try from my side to resolve this issue or do further debugging and testing.

Side note: I tried resetting the device as well every time it goes offline or even reconnecting the WiFi and both have been unsuccessful.

I am using an ESP32-DevKitC-VIE Development Board

#define BLYNK_TEMPLATE_ID "" 
#define BLYNK_DEVICE_NAME ""
#define BLYNK_FIRMWARE_VERSION        "1.1.1"
#define RXD2 13
#define TXD2 12
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "BlynkEdgent.h"
#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
#define USE_WROVER_BOARD
//#define USE_TTGO_T7
const char* serverSensyr = "";
const int port = 443;
WiFiClientSecure client;

//Sensyrtech Certification

const char* ca_cert = \
                      "-----BEGIN CERTIFICATE-----\n" \
                      "-----END CERTIFICATE-----\n";


int incomValue = 0;
int conn;
float weightBufferVal = 0.6; // This is how much the weight needs to change to be considered unstable within the sampling rate
int sampleRate = 1000; // The sample rate defines how often we sample weight to see unstable data or a change in bucket
int startStabilityIncr = 30; // This is how many increments of seconds the weight has to be stable for the program to start 
int transmissIncr = 1; // how often will we transmit to the cloud in increments of realSampleIncr
int realSampleIncr = 60000;
float realBufferVal = 2;// This is how different the values have to be in proper sampling to be considered unstable
float lastWeight;
float currentWeight;
float weightSum;
String body;
int body_len;
String weightSensID = "";
String signalID = "";


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

  BlynkEdgent.begin();
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Starting weight tracking");
  client.setCACert(ca_cert);
  delay(2000);
  uploadData("stle84194fa7a000SIG", 2000); 
  
  //Make sure when the device is booted up first, it finds a valid value and then moves forward with the program and loops endlessly until
  stabilityWait();
 
}

void loop() {
  BlynkEdgent.run();  
  lastWeight = getWeight();
  if (lastWeight == -1)
  {
    stabilityWait();
    lastWeight = getWeight();
  }
  Serial.print("Last Weight: "); Serial.println(lastWeight);
  for (int i = 0; i < 60; i++)
  {
    BlynkEdgent.run(); //running Blynkedgent here again and in other loops so as not to go too long without cloud connection. One possible reason for it going offline 
    Serial.print("Second: "); Serial.println(i);
    delay(1000);
  }
  
  Serial.print("Actual Current Weight: "); Serial.println(getWeight());
  currentWeight = getWeight();
  Serial.print("Current Weight: "); Serial.println(currentWeight);

  if(currentWeight != -1) {
    if (abs(currentWeight - lastWeight) > realBufferVal)
    {
      stabilityWait();
    }
    else
    {
      Serial.println("Starting to send data");
      weightSum = lastWeight - currentWeight;
      if (weightSum >= 0)
      {
        if(weightSum <= 0.3)
        {
          weightSum = 0;
        }
        
        
      Serial.print("Weight Sum: " ); Serial.println(weightSum);
      uploadData(weightSensID,weightSum);
      uploadData(signalID,WiFi.RSSI());
    }
    else
    {
      Serial.println("Weight difference is too small to account for");
    }
    }
  }

}

float getWeight ()
{
  int weight [14];
  String strWeight;
  float dWeight = -1;
  Serial2.print('P');
  if (Serial2.available() > 0) {
    for (int i = 0; i < 14; i++)
    {
      weight[i] = Serial2.read();
      strWeight.concat(char(weight[i]));
      Serial.print(char(weight[i]));
      delay(10);
    }
    Serial.println("");
    if (strWeight.indexOf('l') > 0)
    {
      Serial.println("");
      dWeight = strWeight.toFloat();
      Serial.println(dWeight);
    }

  }
  return dWeight;
}

// Wait for the weight to become stable before continuing on with the program.
void stabilityWait()
{
  unsigned long startTime = millis();
  unsigned long sigStartTime = millis();
  float startLastWeight = -1;
  float startCurrentWeight;
   //This loop will run infinitely until the weight has stabilized and once stabilization starts, it will wait 30 seconds to return back to main loop. 
   for (int x = 0; x < startStabilityIncr; x ++)
  {
    BlynkEdgent.run(); // run Blynk edgent here to not go too long without having a connection to blynk cloud.
       Serial.print("RSSI: ");
  Serial.println(WiFi.RSSI());
    delay(sampleRate);
    startCurrentWeight = getWeight();
    if (startCurrentWeight == -1)
    {
      x = -1;
    }
    else {
      if (abs(startCurrentWeight - startLastWeight) > weightBufferVal)
      {
        x = -1;
      }
      startLastWeight = startCurrentWeight;
      

    }
    Serial.print("Second of Stability: "); Serial.println(x);
    //If more than 10 minutes have passed in the stabilization loop, send a data point of 0.
    if (millis() - startTime > 600000){
      startTime = millis();
      float offCount = 0;
      uploadData(weightSensID, offCount);
    }
    // Send signal strength data every minute for debugging purposes.
    if (millis() - sigStartTime > 60000)
    {
      sigStartTime = millis();
      uploadData(signalID,WiFi.RSSI());
    }
  }
  Serial.println("Weight Stabilized");

}

void uploadData(String sensorID, int val)
{
  String sensorStr;
  int sensorStrLen;
  sensorStr = "";
      Serial.println(sensorStr);
      sensorStrLen = sensorStr.length();
      Serial.println(".....");
      Serial.println(); Serial.print("For sending parameters for off state, connecting to "); Serial.println(serverSensyr);
      conn = client.connect(serverSensyr, port);

      if (conn == 1) {
        Serial.println(); Serial.print("Sending Parameters...");
        //Request
        client.println("POST INSERT LINK HERE HTTP/1.1");
        //Headers
        client.print("Host: "); client.println(serverSensyr);
        client.println("Authorization: bearer INSERT TOKEN HERE");
        client.println("Content-Type: application/json");
        client.print("Content-Length: "); client.println(sensorStrLen);
        client.println("Connection: Close");
        client.println();
        //Body
        client.println(sensorStr);
        client.println();
      } else {
        Serial.println("Connection Failed");
      }
      client.stop();
 
}

You should always keep your void loop clean, the ideal blynk void loop should look like this

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

and like this

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

When you use a timer.

Read this
https://docs.blynk.io/en/legacy-platform/legacy-articles/keep-your-void-loop-clean?q=Loop

2 Likes

@John93 Thank you for the response and the link as well. I was thinking that a one-second delay function couldn’t cause problems, but I guess I was wrong. The only thing that doesn’t make sense is that it was able to stay connected for more than a week continuously at the office even while running the delays, but disconnects at the facility. If it was a networking issue as well, how would I debug for that? I pulled RSSI but it doesn’t show any issues there. Is there anything else I could try to get more information on network-related issues?

There are lots of reasons why disconnections can occur, but it’s pointless trying to look for them when you have a code structure that is breaking all of the Blynk rules.

My guess is that this is the culprit…

During that process, you are serial printing your RSSI values, but not sending them to Blynk.
Have you checked the Event log to see if the device was showing as offline during these periods when no RSSI readings were being sent to Blynk?

This is what an offline period looks like in the event log…

Pete.

1 Like

@PeteKnight you are correct, after reading into it, the loops that I’ve created go against what Blynk recommends. I am restructuring it in the way that’s in their guides. But I still have to run a loop to continuously check if the weight has stabilized. If I run this in a timer function, would that still block the main loop from running or do both tasks work in parallel?

I will check the event log and share my findings here.

The reason I was asking for the network debugging was because I have that infinite loop running here at the office and it stayed online indefinitely. The reason the device stays connected is because I’m running Blynkedgent.run() inside that loop as well to maintain connection. My office has great WiFi but the facility’s has been known to be spotty. From what I saw in the RSSI, it doesn’t seem that way to me, but I could be missing other parameters to check to get an idea of network strength and reliability. Other than that, I am restructuring the code and will try again, but if there is anything that could help me debug network-related issues as well, I could run those tests in parallel while restructuring code.

Thank you,

You could bery easily run the stabilisation process as a non-blocking timeout timer, with a Boolean “stabilised” flag that’s set when stabilisation has occurred.

You can the check the flag in your other function, which takes and transmits the weight readings only if the flag is set to true.

More info on non-blocking Timeout timers half way through this tutorial:

And the use of flags here…

Yes, and until you come back with this info…

it’s impossible to know if you are actually seeing disconnections, or constant re-calibrations because the office cat decided to take a nap on the load cell.

Pete.

@PeteKnight Thanks for the tutorials. I checked the devices, and there are no logs. I don’t have any data coming into Blynk. I will need to get this enabled.

I see the heartbeat value here at 45, which confirms that it’s taking too long between pings for maintaining connection?
image

45 is the standard value.

I don’t understand your previous comment about…

If you go to Template > Events > Edit and click the Online event, do you see this…

with the “Send event to…” options enabled?

And the same for the “Offline” event?

Pete.

1 Like

@PeteKnight Yes, I see that. I didn’t have the online and offline events saved to send events. I have it enabled now.

Okay, time to re-test to see if the data outages correspond with offline events then.

Pete.

What am I looking for during these tests? If the RSSI values stop coming into our servers during the offline period?

At the moment, all you have is the lack of RSSI and weight data points in your chart.
You’re assuming that these are caused by the device going offline, but the way your code is structured the device could simply be stuck in a repeating loop of recalibrations.
During these recalibrations your code prints data to the serial monitor, but doesn’t post RSSI or weight data to Blynk.

You need to see if the events are reporting the device as being offline when these data gaps appear in the chart.

Pete.

Hi Pete, that was a very detailed post on timers which helped restructure my code. In the code below I have created 2 timers from which only one stays enabled at a time. If conditions are normal, then the weight differential is uploaded every minute and if the weight differential becomes unstable, the one minute timer disables itself and enables the stabilization timer to check every second and if the “stableCount” reaches 30, which means it’s been stable for 30 seconds, it disables the stabilization timer and again enables the 1 minute upload timer. I’ll OTA update this program and see how it works. Thank for your help so far!

#define BLYNK_TEMPLATE_ID ""
#define BLYNK_DEVICE_NAME ""
#define BLYNK_FIRMWARE_VERSION        "1.2"
#define RXD2 13
#define TXD2 12
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "BlynkEdgent.h"
#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
#define USE_WROVER_BOARD
//#define USE_TTGO_T7
const char* serverSensyr = "";
const int port = 443;
WiFiClientSecure client;
BlynkTimer timer;

//Sensyrtech Certification

const char* ca_cert = \
                      "-----BEGIN CERTIFICATE-----\n" \
                      "-----END CERTIFICATE-----\n";


int incomValue = 0;
int conn;
float weightBufferVal = 0.6; // This is how much the weight needs to change to be considered unstable within the sampling rate
int sampleRate = 1000; // The sample rate defines how often we sample weight to see unstable data or a change in bucket
int startStabilityIncr = 30; // This is how many increments of seconds the weight has to be stable for the program to start
int transmissIncr = 1; // how often will we transmit to the cloud in increments of realSampleIncr
int realSampleIncr = 60000;
float realBufferVal = 2;// This is how different the values have to be in proper sampling to be considered unstable
float lastWeight;
float currentWeight;
float weightSum;
String body;
int body_len;
String weightSensID = "";
String signalID = "";
int stableState = 0;//0 is unstable weight, 1 is stable weight
int stableCount = 0;
float startLastWeight = -1;
float startCurrentWeight;
int checkWeightID,stabilizationWaitID, unstableDataUploadID;
void setup()
{
  Serial.begin(115200);
  delay(100);

  BlynkEdgent.begin();
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Starting weight tracking");
  client.setCACert(ca_cert);
  timer.setTimeout(3600000L, [] () {} );
  checkWeightID = timer.setInterval(60000L, checkWeight);
  stabilizationWaitID = timer.setInterval(1000L, stabilizationWait);
  unstableDataUploadID = timer.setInterval(600000L, unstableDataUpload);
  delay(100);

  //Make sure when the device is booted up first, it finds a valid value and then moves forward with the program and loops endlessly until
  timer.disable(checkWeightID);

}

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

void unstableDataUpload ()
{
  uploadData(weightSensID, 0);
  uploadData(signalID, -1);
}

void checkWeight()
{
  Serial.print("Actual Current Weight: "); Serial.println(getWeight());
  currentWeight = getWeight();
  Serial.print("Current Weight: "); Serial.println(currentWeight);
  if (abs(currentWeight - lastWeight) > realBufferVal || currentWeight == -1)
  {
    timer.enable(stabilizationWaitID);
    timer.disable(checkWeightID);
    timer.enable(unstableDataUploadID);
  }
  else
  {
    Serial.println("Starting to send data");
    weightSum = lastWeight - currentWeight;
    if (weightSum >= 0)
    {
      if (weightSum <= 0.3)
      {
        weightSum = 0;
      }
      else
      {
        lastWeight = currentWeight;
      }


      Serial.print("Weight Sum: " ); Serial.println(weightSum);
      uploadData(weightSensID, weightSum);
      uploadData(signalID, currentWeight);
    }
    else
    {
      Serial.println("Weight difference is too small to account for");
    }
  }

}

float getWeight ()
{
  int weight [14];
  String strWeight;
  float dWeight = -1;
  Serial2.print('P');
  if (Serial2.available() > 0) {
    for (int i = 0; i < 14; i++)
    {
      weight[i] = Serial2.read();
      strWeight.concat(char(weight[i]));
      Serial.print(char(weight[i]));
      delay(10);
    }
    Serial.println("");
    if (strWeight.indexOf('l') > 0)
    {
      Serial.println("");
      dWeight = strWeight.toFloat();
      Serial.println(dWeight);
    }

  }
  return dWeight;
}
// Wait for the weight to become stable before continuing on with the program.
void stabilizationWait()
{
  startCurrentWeight = getWeight();
  if ( startCurrentWeight == -1)
  {
    stableCount = 0;
  }
  else if (abs(startCurrentWeight - startLastWeight) > weightBufferVal)
  {
    startLastWeight = startCurrentWeight;
        stableCount = 0;

  }
  else
  {
  stableCount++;
  startLastWeight = startCurrentWeight;
  }
  Serial.print("Second of Stability: "); Serial.println(stableCount);
  if (stableCount == 30)
  {
    Serial.println("Weight Stabilized");
    timer.disable(stabilizationWaitID);
    timer.enable(checkWeightID);
    timer.disable(unstableDataUploadID);
    lastWeight = getWeight();
  }

}


void uploadData(String sensorID, int val)
{
  String sensorStr;
  int sensorStrLen;
  sensorStr = "";
  Serial.println(sensorStr);
  sensorStrLen = sensorStr.length();
  Serial.println(".....");
  Serial.println(); Serial.print("For sending parameters for off state, connecting to "); Serial.println(serverSensyr);
  conn = client.connect(serverSensyr, port);

  if (conn == 1) {
    Serial.println(); Serial.print("Sending Parameters...");
    //Request
    client.println("POST INSERT LINK HERE HTTP/1.1");
    //Headers
    client.print("Host: "); client.println(serverSensyr);
    client.println("Authorization: bearer INSERT TOKEN HERE");
    client.println("Content-Type: application/json");
    client.print("Content-Length: "); client.println(sensorStrLen);
    client.println("Connection: Close");
    client.println();
    //Body
    client.println(sensorStr);
    client.println();
  } else {
    Serial.println("Connection Failed");
  }
  client.stop();

}

Hi Pete,

I restructured the code as recommended and the device was online for 2-3 days with slight interruptions, 9 seconds - 1 minute long, but now the device has gone offline again and has been more than 24 hours. I confirmed that the power supply has not been touched and neither has the device. I am attaching the events and the historical data for weight.




I see this data coming into our server. Note: This time shown below is PST and time shown above in images is CST

It seems data is coming into our server while the Blynk device is still showing offline.

ESP32 chip disconnection should be a common phenomenon. I guess the main reason is that this board does not have an external clock. Once there is a statement that occupies the internal clock for a long time in the program, it will cause wifi disconnection, because wifi also needs the internal clock to keep the connection. In addition, although the quality of the wifi signal in the office is very good, due to too many connected devices, sometimes multiple devices will preempt the IP address, which will also cause the ESP32 to disconnect. The solution is to join the reconnection when it detects that the network is not connected. (I use python, arduino also has the same function statement)

@blynk.handle_event("connect")
def connect_handler():
    print(CONNECT_PRINT_MSG)
    print('Sleeping 2 sec in connect handler...')
    time.sleep(2)


@blynk.handle_event("disconnect")
*def disconnect_handler():*
    print(DISCONNECT_PRINT_MSG)
    print('Sleeping 4 sec in disconnect handler...')
    time.sleep(4)
    ***blynk.connect()***
print("connect ready")

——————————————————————————————————————

There is a HandleDisconnect function in blynk-library may be useful

 if (WiFi.status() != WL_CONNECTED)
  {
    // (optional) "offline" part of code

    // check delay:
    if (millis() - lastConnectionAttempt >= connectionDelay)
    {
      lastConnectionAttempt = millis();

      // attempt to connect to Wifi network:
      if (pass && strlen(pass))
      {
        WiFi.begin((char*)ssid, (char*)pass);
      }
      else
      {
        WiFi.begin((char*)ssid);

The rest of your information is somewhat irrelevant without seeing the new code.

Pete.

Hi @PeteKnight , I pasted the code in post #14, but I’ll quote it here again.

I noticed something strange on my dashboard that could be the problem. All the devices that are connected show the same IP Address. I don’t know how that’s possible, but IP Address conflicts could be occurring and disconnecting the devices? I’ll post some pictures below the code.



The snippet of code shown above will be allowed by Blynk.edgent since it has its own connection protocols through SPIFFS and set up through the mobile app? The WiFi.begin would override how Blynk.edgent tries to connect right?

Sorry, I didn’t realise that this was the code you were using.

That’s the public IP address, so you’d expect it to be the same for all devices connected via that same incoming network connection.

Sorry, I don’t understand the question.

Pete.