Need help with Blynk Project with devices that randomly go offline

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.

I was asking since we connect a blynk.edgent program to the wifi through the mobile app, can we connect it directly through the firmware as well by setting ssid and password information?

But that question diverts from the main topic. What could be possible reasons for it disconnecting now? I don’t have any blockers in the code now and everything is running on timers. Any further recommendations on what to try next or what could be causing the device to randomly go offline?

Thank you.

Those details are stored in EEPROM on the device. Do you have a method to write this configstore data as part of this process?

TBH, its very difficult to un-pick your code, as there isn’t much in the way of in-code comments. Enabling and disabling timers in this way isn’t my favourite approach, as it is difficult to follow at the best of times.

A couple of observations

By default, Serial2 on the ESP32 is on pins 16 & 17. You are using pins 13 & 12, but pin 12 is a potentially problematic pin. If it’s pulled HIGH at boot, the board won’t go in to run mode, instead it will sit in programming code, awaiting code to be uploaded.
As the Edgent sketch has a routine which will do an ESP.restart if it can’t connect to WiFi or Blynk, its possible that the board is being placed into programming mode on these restarts by the sensor connected to pin 12.

Also, have you tried commenting-out the uploadData process? It’s possible that this is interfering with the Blynk communications.
If you’re doing an HTTPS API call then these can be quite slow. Have you put some serial print statements in there to see exactly how long this function takes to complete?

Blynk has a Webhook function which allows the Blynk server to make the API call for you, rather than doing it directly from the board, but before you start investigating that I’d do some experimenting with timings and se if it still goes offline with the API call disabled.

Pete.

I did not know that about pin 12, that was good information. The sensor I have connected to doesn’t send any data until I write the character ‘P’ to it. Is it still possible for that sensor to pull that pin high on boot without receiving a ‘P’?

What I have done right now is uploaded a blank edgent template which just has edgent.run and edgent.begin functions to one of the devices to see if it stays online. Then I can enable one module at a time to see which one causes the disconnects. If it is truly their network disconnecting my devices or blocking me, then I would know from the disconnect on the blank edgent template on that device. This will be a bit of a slow process, but will help me get a solution remotely.

I have Serial.print functions but have not logged the times before. What is the max time a process should take to be considered a blocker? I know if it’s longer than 10 seconds, Blynk considers the device offline.

Yes. Even pulling the pin top an intermediate “floating” state can be enough to prevent booting.

Good idea.

Anything that’s approaching 10 seconds is potentially a worry.

In this topic, I was doing some tests of HTTP versus HTTPS calls to the Blynk server to use the Blynk API as a method of transferring data between devices (like the old Bridge functionality in Legacy).
As you’ll see, HTTPS API calls could take between 2.5 and 40+ seconds, whereas HTTP API calls were taking sub 100ms…

The delays come from the negotiation/authentication process necessary with HTTPS connections.

Pete.

1 Like

It’s possible if the internet is slower than in my office + the other 100s of devices connected to their network taking up bandwidth could cause the API calls to take longer to process. How do I get the data to the Blynk cloud and then to my servers? From what I saw, webhooks are only for change in user information.

Also, isn’t it unsecure to send data with HTTP protocol? But I’m guessing Blynk allows it for faster communication like what you showed in your tests?

Not sure I understand the question, especially not the “change in user information” bit.

Have you read the webhook docs?…

Yes, of course, but not all hardware or environments allow HTTPS Comms.

Pete.

I saw the trigger events on the docs and they only specify trigger events as changes in users within the org. It doesn’t say anything about sending data as webhooks from sensors or peripherals connected to the devices.
image

But I took a look at an actual webhook implementation within the console and it says device datastreams

If you change from GET to POST then you’ll see how you can build a JSON or plain text command with data inserted from virtual pin values etc.

Pete.

BlynkEdgent.h has indeed replaced the above functions and U can ignore the above statements

1 Like

It turns out, that the device I uploaded with this code went offline as well. It could still be the issue with pin 12 since the device is connected to the sensor, but why would the device restart randomly if the network connection is good? Is there any way for me to remotely check if the pin is the issue without me having to tell someone over there to remove the wiring?

#define BLYNK_TEMPLATE_ID ""
#define BLYNK_DEVICE_NAME ""
#define BLYNK_FIRMWARE_VERSION        "1.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  HTTP/1.1");
    //Headers
    client.print("Host: "); client.println(serverSensyr);
    client.println("Authorization: bearer ");
    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();

}
*/

Not really.

Pete.