Electron Resets every 10 minutes

Hi all,
I am pushing 16 data points using 2 webhooks on to thingspeak every one minute. For some reason the electron resets every 10 minutes and looses a minute of data (one data point) in the process. I have tried changing the pushing frequency to once every 2 minutes and it didn’t help either.

Can someone answer why this is happening ?

WIthout seeing your code it’s not possible to answer.

Sorry about that,it is my first time posting in the forums.My code is a little messy.

const size_t READ_BUF_SIZE = 256;
unsigned long lastTime = 0;
unsigned int lastPublish = 0;
unsigned long now;
// Forward declarations
void processBuffer();

const String key = "xxxxxxxxxxxxxxxxxx"; // 
const String key1 = "xxxxxxxxxxxxxxxxx"; //  slave for bins 8-15
const String key2="xxxxxxxxxxxxxxxxxx"; 
// Global variables

char readBuf[READ_BUF_SIZE];
size_t readBufOffset = 0;
int ctr=0;
int good_data_counter=0;
long int bavg[16];

//Get battery life

double batteryLife = 0;
FuelGauge fuel;
double ts;
void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  Particle.variable("Bin0", &bavg[0], INT);
  Particle.variable("Bin1", &bavg[1], INT);  
  Particle.variable("Bin2", &bavg[2], INT);
  Particle.variable("Bin3", &bavg[3], INT);
  Particle.variable("Bin4", &bavg[4], INT);
  Particle.variable("Bin5", &bavg[5], INT);
  Particle.variable("Bin6", &bavg[6], INT);
  Particle.variable("Bin7", &bavg[7], INT);
  Particle.variable("Bin8", &bavg[8], INT);
  Particle.variable("Bin9", &bavg[9], INT);  
  Particle.variable("Bin10", &bavg[10], INT);
  Particle.variable("Bin11", &bavg[11], INT);
  Particle.variable("Bin12", &bavg[12], INT);
  Particle.variable("Bin13", &bavg[13], INT);
  Particle.variable("Bin14", &bavg[14], INT);
  Particle.variable("Bin15", &bavg[15], INT);
  Particle.variable("Time_unix", &ts, DOUBLE);
  Particle.variable("BatL", &batteryLife, DOUBLE);
}

void loop() {
  now = millis();
  while(Serial1.available()) {
      
    if (millis() - lastTime >= 1000) {
	lastTime = millis();
		//Serial.println("called once per second");
    }
    if (readBufOffset < READ_BUF_SIZE) {
      char c = Serial1.read();
      if (c != '\n' ) {
        readBuf[readBufOffset++] = c;   // Add character to buffer
      }
      else {
        readBuf[readBufOffset] = 0;     // End of line character found, process line
        processBuffer();
        readBufOffset = 0;
        //delay(1000);
      }
    }
    else {
      readBufOffset = 0;                //Serial.println("readBuf overflow, emptying buffer");
    }
  }
}

void processBuffer()
 {
    int i=0;
    int j;
    int z;
    int num[16];  //Local storage variable
    char *p;
    const char* strtpt="512,";            //Marker to get the bin data
    p=strstr(readBuf,strtpt);             //Gives the starting address of 512 in the system memory 
    z=(int) (p - readBuf);                //Position of 512,  with respect to the start address of received data
    char *rawdata=readBuf+z+4;            //New char array starting with bin0 till bin16
    //Serial.println(rawdata);              //Printing just the bin data
    char *token=strtok(rawdata,",");        //Split comma seperated bin data 
    while (token!=NULL)                   //Converting individual bin data into integers
    {
        num[i]=atoi(token);  
        token=strtok(NULL,",");
        i++;
    }

    if(num[0]<=10000 && num[1]<=10000 && num[2]<=10000 && num[3]<=10000 && num[4]<=10000 && num[5]<=10000 && num[6]<=10000 && num[7]<=10000 && num[8]<=10000 && num[9]<=10000 && num[10]<=10000 && num[11]<=10000 && num[12]<=10000 && num[13]<=10000 && num[14]<=10000 && num[15]<=10000 )
    {
    for (i=0;i<16;i++)
    {
        
        bavg[i]=bavg[i]+num[i];
    }
    good_data_counter=good_data_counter+1;
    }
    ctr=ctr+1;
    //if(ctr==60)
    if((now-lastPublish)>=60000 || good_data_counter==60)
    {
        time_t time = Time.now();
        ts=Time.now();
        batteryLife = fuel.getSoC();
        ts=ts-60;
       // Serial.print("Time now is ");Serial.println(ts);Serial.print("  Battery level ");Serial.println(batteryLife);
       // Serial.print("Avg data  ");
        for(j=0;j<16;j++)
        {
            bavg[j]=bavg[j]/good_data_counter;
           // Serial.print(bavg[j]);Serial.print(",");
        }
            Particle.publish("thingSpeakWrite_All", "{ \"1\": \"" + String(bavg[0]) + "\"," +
            "\"2\": \"" + String(bavg[1]) + "\"," +
            "\"3\": \"" + String(bavg[2]) + "\"," +
            "\"4\": \"" + String(bavg[3]) + "\"," +
            "\"5\": \"" + String(bavg[4]) + "\"," +
            "\"6\": \"" + String(bavg[5]) + "\"," +
            "\"7\": \"" + String(bavg[6]) + "\"," +
            "\"8\": \"" + String(bavg[7]) + "\"," +
            "\"k\": \"" + key + "\" }", PRIVATE);
            
            Particle.publish("thingSpeakWrite_Slave", "{ \"1\": \"" + String(bavg[8]) + "\"," +
            "\"2\": \"" + String(bavg[9]) + "\"," +
            "\"3\": \"" + String(bavg[10]) + "\"," +
            "\"4\": \"" + String(bavg[11]) + "\"," +
            "\"5\": \"" + String(bavg[12]) + "\"," +
            "\"6\": \"" + String(bavg[13]) + "\"," +
            "\"7\": \"" + String(bavg[14]) + "\"," +
            "\"8\": \"" + String(bavg[15]) + "\"," +
            "\"k\": \"" + key1 + "\" }", PRIVATE);
            Particle.publish("thingSpeakWrite_extra", "{ \"1\": \"" + String(ts) + "\"," +
            "\"2\": \"" + String(batteryLife) + "\"," +
            "\"3\": \"" + String(good_data_counter) + "\"," +
            "\"k\": \"" + key2 + "\" }", PRIVATE);
        //Serial.print("Number of good data points in 60 seconds= ");Serial.println(good_data_counter);    
        for(j=0;j<16;j++)
        {
            bavg[j]=0;
        }        
        ctr=0;
        good_data_counter=0;
       // Serial.println();
        lastPublish=now;
        
    }

    }

The modern syntax for this would be

Particle.variable("Bin0", bavg[0]);

Unix timestamps are actually int not double.

Your processBuffer() assumes there will be a substring "512," but since your loop() doesn't really seem to enforce consistency of readBuf that might not necessarily be the case but I can't make out any guard against this case.

Here is no guard against i exceeding the size of the array - never rely on the incoming data to not violate the expected format.

You are using lots of String objects which may - over time - lead to heap fragmentation and consequently crash or stall the program.
snprintf() is a better way of handling this.

3 Likes

Hi , I changed my code according to your feedback except for the snprintf() usage. What string objects should I avoid in order to avoid heap fragmentation?

All of these

            Particle.publish("thingSpeakWrite_All", "{ \"1\": \"" + String(bavg[0]) + "\"," +
            "\"2\": \"" + String(bavg[1]) + "\"," +
            "\"3\": \"" + String(bavg[2]) + "\"," +
            "\"4\": \"" + String(bavg[3]) + "\"," +
            "\"5\": \"" + String(bavg[4]) + "\"," +
            "\"6\": \"" + String(bavg[5]) + "\"," +
            "\"7\": \"" + String(bavg[6]) + "\"," +
            "\"8\": \"" + String(bavg[7]) + "\"," +
            "\"k\": \"" + key + "\" }", PRIVATE);
            
            Particle.publish("thingSpeakWrite_Slave", "{ \"1\": \"" + String(bavg[8]) + "\"," +
            "\"2\": \"" + String(bavg[9]) + "\"," +
            "\"3\": \"" + String(bavg[10]) + "\"," +
            "\"4\": \"" + String(bavg[11]) + "\"," +
            "\"5\": \"" + String(bavg[12]) + "\"," +
            "\"6\": \"" + String(bavg[13]) + "\"," +
            "\"7\": \"" + String(bavg[14]) + "\"," +
            "\"8\": \"" + String(bavg[15]) + "\"," +
            "\"k\": \"" + key1 + "\" }", PRIVATE);
            Particle.publish("thingSpeakWrite_extra", "{ \"1\": \"" + String(ts) + "\"," +
            "\"2\": \"" + String(batteryLife) + "\"," +
            "\"3\": \"" + String(good_data_counter) + "\"," +
            "\"k\": \"" + key2 + "\" }", PRIVATE);

Each of those String() conversions creates a temporary object and the string concatenations do that too, so you are producing dozens of temporary objects which will inevitably lead to heap fragmentation and quickly too.

Excatly that's why I suggested using snprintf() instead.

3 Likes

See this link for using snprintf() with a ThinkSpeak Webhook to avoid Strings:
Start at Post #7

You will remove the comments and extra spaces that I added to the snprintf() to help me understand - once you get it working (As per ScruffR’s suggestions in the linked Thread).

1 Like

Hi ,
I changed the code based on your inputs but I am still missing every 10th data point.
This is the updated code.

// Buffers and Constants
const size_t READ_BUF_SIZE=512;
char readBuf[READ_BUF_SIZE];
size_t readBuffOffset=0;
//Time Variables
unsigned long lasttime=0;
unsigned int lastpublish=0;
unsigned long now;
int ts;
//Battery Variables
int batteryLife=0;
FuelGauge fuel;

//Global variables
int ctr=0;
int good_data_counter=0;
long int bavg[16]={0};
long int bavg_ctr[16]={0};


//Thingspeak 
char msg1[128];
char msg2[128];
char msg3[128];
const char * eventName1 = "thingSpeakWrite_All";  
const char * eventName2 = "thingSpeakWrite_Slave";
const char * eventName3 = "thingSpeakWrite_extra";

const char * key1 = "XXXXXXXXXXXXXX"; // 
const char * key2 = "XXXXXXXXXXXXXX"; //  slave for bins 8-15
const char * key3 = "XXXXXXXXXXXXXX"; 

// Forward declarations
void processBuffer();

void setup()
{
    Serial.begin(9600);
    Serial1.begin(9600);
     
     //Particle cloud variables
    Particle.variable("Bin0",bavg[0]);
    Particle.variable("Bin1",bavg[1]);  
    Particle.variable("Bin2",bavg[2]);
    Particle.variable("Bin3",bavg[3]);
    Particle.variable("Bin4",bavg[4]);
    Particle.variable("Bin5",bavg[5]);
    Particle.variable("Bin6",bavg[6]);
    Particle.variable("Bin7",bavg[7]);
    Particle.variable("Bin8",bavg[8]);
    Particle.variable("Bin9",bavg[9]);  
    Particle.variable("Bin10",bavg[10]);
    Particle.variable("Bin11",bavg[11]);
    Particle.variable("Bin12",bavg[12]);
    Particle.variable("Bin13",bavg[13]);
    Particle.variable("Bin14",bavg[14]);
    Particle.variable("Bin15",bavg[15]);
    Particle.variable("Time_unix",ts);
    Particle.variable("BatL",batteryLife);
}

void loop()
{
    now=millis();
    if (now-lasttime>750) //Read every second
    {
        while(Serial1.available())
        {
            if(readBuffOffset < READ_BUF_SIZE)
            {
                char c=Serial1.read();
                if(c !='\n')
                {
                    readBuf[readBuffOffset++]=c;
                }
                else
                {
                    readBuf[readBuffOffset] = 0;     // End of line character found, process line
                    processBuffer();
                    readBuffOffset = 0;
                    lasttime=now;
                }
            }
            else
            {
                readBuffOffset=0;
                lasttime=now;
            }
        }
    }
}


//Processing the input data
void processBuffer()
{
    //Constants
    int i=0;int j;int z;
    int num[16]={0};
    char *p;
    int num_v1[16];
    const char* startpoint="512,";
    p=strstr(readBuf,startpoint);
    z=(int) (p-readBuf);
    char *rawdata=readBuf+z+4;
    //Serial.println(readBuf);
    //Serial.println(rawdata);
    char *token=strtok(rawdata,",");
    while (token!=NULL && i<=16)
    {
        num[i]=atoi(token);
        token=strtok(NULL,",");
        i++;
    }
    
    for(i=0;i<=15;i++)
    {
        num_v1[i]=num[i];
    }   
    if((0<num_v1[0]<=10000) && (0<num_v1[1]<=10000) && (0<num_v1[2]<=10000) && (0<num_v1[3]<=10000) && (0<=num_v1[4]<=10000) && (0<=num_v1[5]<=10000) && (0<=num_v1[6]<=10000) && (0<=num_v1[7]<=10000) && (0<=num_v1[8]<=10000) && (0<=num_v1[9]<=10000) && (0<=num_v1[10]<=10000) && (0<=num_v1[11]<=10000) && (0<=num_v1[12]<=10000) && (0<=num_v1[13]<=10000) && (0<=num_v1[14]<=10000) && (0<=num_v1[15]<=10000) )
    {
        for (i=0;i<=15;i++)
        {
            bavg_ctr[i]=bavg_ctr[i]+num_v1[i];    
        }
        good_data_counter=good_data_counter+1;
    }
    
    if((now-lastpublish)>=60000||good_data_counter==60)
    {
        ts = Time.now();
        ts=ts-60;
        //batteryLife = fuel.getSoC();
        for(j=0;j<=15;j++)
        {
            bavg[j]=bavg_ctr[j]/good_data_counter;
        }
        
        //PUBLISH TO THINGSPEAK
        snprintf(msg1,sizeof(msg1), 
                "{\"1\":\"%d\" , \"2\":\"%d\" , \"3\":\"%d\" , \"4\":\"%d\" , \"5\":\"%d\" , \"6\":\"%d\" , \"7\":\"%d\" , \"8\":\"%d\" , \"k\":\"%s\"}" ,
                bavg[0],bavg[1],bavg[2],bavg[3],bavg[4],bavg[5],bavg[6],bavg[7],key1);
        Particle.publish(eventName1,msg1 , PRIVATE);
        
        snprintf(msg2,sizeof(msg2), 
                "{\"1\":\"%d\" , \"2\":\"%d\" , \"3\":\"%d\" , \"4\":\"%d\" , \"5\":\"%d\" , \"6\":\"%d\" , \"7\":\"%d\" , \"8\":\"%d\" , \"k\":\"%s\"}" ,
                bavg[8],bavg[9],bavg[10],bavg[11],bavg[12],bavg[13],bavg[14],bavg[15],key2);
        Particle.publish(eventName2 ,msg2 , PRIVATE);
        
        snprintf(msg3,sizeof(msg3), 
                "{\"1\":\"%d\" , \"2\":\"%d\" , \"3\":\"%d\", \"k\":\"%s\"}" ,
                ts,batteryLife,good_data_counter,key3);
        Particle.publish(eventName3,msg3 , PRIVATE);
        //RESETTING THE VARIABLES AND ARRAYS
        good_data_counter=0;
        lastpublish=now;
        for(j=0;j<=15;j++)
        {
            bavg[j]=0;
            bavg_ctr[j]=0;
            num_v1[j]=0;
            num[j]=0;
        }
        memset(msg1, 0, sizeof(msg1));
        memset(msg2, 0, sizeof(msg2));
        memset(msg3, 0, sizeof(msg3));
    }
}

Just to be clear, this does not reset the whole array but only the first field.
And my initial warning about potential buffer overflow and consistency of data does still not seem to be addressed.

Additionally if you should happen to have no good data at all for one set of data you may be running in a DIV/0 exception due to this unguarded division.

Just for C/C++ style, you could shorten "elaborate" instructions like these

      bavg_ctr[i]=bavg_ctr[i]+num_v1[i];
      good_data_counter=good_data_counter+1;
      ts=tx-60;

into this

      bavg_ctr[i] += num_v1[i];
      good_data_counter++;
      ts -= 60;

And while talking about style

    if((0<num_v1[0]<=10000) && (0<num_v1[1]<=10000) && (0<num_v1[2]<=10000) && (0<num_v1[3]<=10000) && (0<=num_v1[4]<=10000) && (0<=num_v1[5]<=10000) && (0<=num_v1[6]<=10000) && (0<=num_v1[7]<=10000) && (0<=num_v1[8]<=10000) && (0<=num_v1[9]<=10000) && (0<=num_v1[10]<=10000) && (0<=num_v1[11]<=10000) && (0<=num_v1[12]<=10000) && (0<=num_v1[13]<=10000) && (0<=num_v1[14]<=10000) && (0<=num_v1[15]<=10000) )
    {
      ...
    }

You could reuse the previous for loop this way

    bool allGood = true;
    for(i=0;i<=15;i++)
    {
        num_v1[i]=num[i];
        if (0 > num_v1[i] || num_v1[i] > 10000) allGood = false; 
    }   
    if (allGood) 
    {
      ...
    }

BTW, I'm quite sure this syntax doesn't work as you intend it to do

    if((0<num_v1[0]<=10000) ...)

it would rather be something like that

    if((0 < num_v1[0] && num_v1[0] <= 10000) ...)

but as already said such a huge if() construct isn't the best style anyway.

1 Like

@ScruffR Thanks for your inputs. I am a beginner in programming and I am still trying to figure out how to address buffer overflow and consistency of the data.
I changed the other parts of the code based on your suggestions and the error remains. So I am assuming it is because of consistency of the data.

As I have mentioned initially, I saw a missing data point every 10th minute even when I changed the publish frequency to 2 minutes

You may want to add some serial logging in your code to keep track of some key variables and your input/output data.
You need to know what leads up to the missing event.
Make an analysis of what data you’d expect each time round and what you actually get and see where things start to diverge.

Also, I have observed that the particle electron flashes red light at the tenth minute(same time when i miss the data point) and I get serial connection error.

If you catch what code these red flashes show you can get a clue of the reason.
As I said eariler, your code is running the risk of a DIV/0 exception which will inevitably cause a SOS panic crash which would explain your problem.
But to actually know, you need (at least) add debugging output.

5 Likes

Fixing the DIV/0 fixed the error. Thank you for your help.

3 Likes