Photon Particle simultaneous devices only

Hi All,

I have been using photon to make weather measurements and I would like to have multiple devices sending data to wehook. I created a test for two wehook corresponding to two photons. One has been working very well during one week but when I connected the second one, the first one stop to send data. I send data every 5 minutes and it is less than 245 characters, the WiFi signal is fine and the battery is also working. My only guess is that the Particle cloud has some restriction to have multiple devices online, I could not find any restriction in the documentation and I was wondering if somebody has had a similar issue?

Thanks for your help,

Shouldn’t be a problem. I have multiple photons sending data through webhooks with no issues.

Thanks Fragma for your answer, I am still having the same issues. I tried another approach, instead of using a wehook I am using my own server. As soon as the photons connect to my WiFi they start to send data but after a few minutes they keep connected but don’t send data anymore. Here I post a piece a code in case that somebody can find a bug in my code.

Sample code


#include <SPI.h>
#include "SdFat.h"               //sd card
#include <Wire.h>
#include "ADS1115.h"            //ads1115 library
#include <elapsedMillis.h>      //timers


#define SERIAL_DEBUG

#ifdef SERIAL_DEBUG
  #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
  #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define DEBUG_PRINT(...)
  #define DEBUG_PRINTLN(...)
#endif


SYSTEM_MODE(SEMI_AUTOMATIC); 
SYSTEM_THREAD(ENABLED); // Allows multithreading - Wifi goes out, board still runs
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));  // Uses external antenna


const uint32_t msRetryDelay = 5*60000; // retry every 5min
const uint32_t msRetryTime  =   50000; // stop trying after 50sec
bool   retryRunning = false;

Timer retryTimer(msRetryDelay, retryConnect);  // timer to retry connecting  particle. h functions
Timer stopTimer(msRetryTime, stopConnect);     // timer to stop a long running try


SdFat SD;

#define SD_CS_PIN SS
File myFile;

//----HTTP variables
int unixTime=0;
int oldunixTime=0;
String xtime;
char data[80];                                   //Data to publish in web maximum 255 thingspeak
int msecs = 0;

//---Magnetic field measurements
int msl= 0;
float bx=0.0;
float by=0.0;
float bz=0.0; 
float bxl=0.0;                                   //residual difference of magnetic component
float byl=0.0;
float bzl=0.0;


//---Sampling frequency parameters
long previousTime = 0;                           // will store last time adc read
long speriod = 1000;                             //--Sampling period (ms)
int count = 0;                                   //--Counter for average
int lint;                                        //--Store line of string measurements
float bxt=0.0;                                   //--Sum all bx measurements in x
float byt=0.0;
float bzt=0.0;
unsigned long currentTime=0; 

//---Constants
const char *mv = "mV\n";



//--ADS1115  objects
ADS1115 adc0(ADS1115_DEFAULT_ADDRESS);            //0x48, 1001 000 (ADDR=GND)

//---WiFi signal
elapsedMillis timeElapsed;                      //timer for publishing over the net

//----HTTP configuration
#define MAX_LENGTH_BUFFER 4080
TCPClient client;                               // Initialize the TCP client library
byte server[] = { xxx, xxx, xxx, xxx };         // IP 
String sserver = "xxxx.edu";   
String receivedData;      
byte dataBuffer[1024];                          // used internally by httpout
char buf01[256];                                // multi use buffer  Data to publish in web maximum 255 thingspeak
char outbuf[MAX_LENGTH_BUFFER];      //  the data to send out
String fsname = "COTSMAG_MK003_P004.txt";


void setup() {   
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
   
  DEBUG_PRINTLN("Attempting to connect to the cloud"); 
  Particle.connect();            //Connect to the cloud and turn the wifi module on (needed for semiautomatic mode)
  if (!waitFor(Particle.connected, msRetryTime)){
    DEBUG_PRINTLN("Connection failed"); 
    WiFi.off();                // no luck, no need for WiFi
    DEBUG_PRINTLN("Wifi module turned off"); 
  }
  DEBUG_PRINT("fsname = ");DEBUG_PRINTLN(fsname);
  sync_my_time();
  checkSdcard_start();
  writeMetadata();                         //--Create new file and start recording
  init_ads1115();                          //--Initiate ads transmision
}

void loop() {
  //------Get time from the RTC in photon               
  unixTime=Time.now();
  xtime=Time.timeStr(unixTime);                // UTC time

  // offset first measurement in milliseconds
  currentTime = millis();
  
  read_ads1115();
  bxt=bxt+bx;                                    //Sum instantaneous bx component 
  byt=byt+by; 
  bzt=bzt+bz;     

  //-----Average measurements per one second
  count=count+1;
  if ((currentTime-previousTime)>=10*speriod)
  {
    bx=bxt/count;
    by=byt/count;
    bz=bzt/count;
    DEBUG_PRINT("Counts = ");DEBUG_PRINTLN(count);
    DEBUG_PRINT("Time = ");DEBUG_PRINTLN(xtime);
    
    snprintf(data, sizeof(data), "UT: %d, S1,S2,S3(mV): %.2f, %.2f, .2f\n",unixTime,bx,by,bz);
    DEBUG_PRINT(data);

    lint=strlen(outbuf);                           //String data length
    Serial.printlnf("Content-Length: %d",lint);    
    if (lint < MAX_LENGTH_BUFFER-45){    //Avoid overflow (Seg fault errors)        
      lint=sprintf(buf01,"U%d",unixTime-oldunixTime);
      strcat(outbuf,buf01); 
      lint=sprintf(buf01,"++%.2f+%.2f+%.2f+%d",bx-bxl,by-byl,bz-bzl,count);
      Serial.printlnf("add to buf: |%s|",buf01);
      strcat(outbuf,buf01);                // Append buf01 into outbuf for posting to a server later
      DEBUG_PRINT("outbuf test1 = ");DEBUG_PRINTLN(outbuf);
    }
    else{
      outbuf[0] = '\0';    // Reinitialise the data buffer.
    }

    write2sd(bx, by, bz, xtime, count);
    count=0;                          //--restart counter for averaging
    bxt=0.0;byt=0.0;bzt=0.0;          //--Restart total sum
    bxl=bx;byl=by;bzl=bz;             //--Store current bx(y,z) averaged components for next iter
    previousTime = currentTime;
    oldunixTime = unixTime; 
  }

  if (timeElapsed>=2*60*speriod){
    // Read and publish if photon is connected to the cloud
    if (Particle.connected() == true) {
      ///check Wifi signal every 120 secs (2 mins)
      int rssi = WiFi.RSSI();
      Serial.printlnf("RSSI=%d\n", rssi);        //---Check for wifi strength
      //publishToParticle(bx, by, bz, rssi);       //--Minimum 15 secs rate thingspeak
      DEBUG_PRINT("outbuf test2 = ");DEBUG_PRINTLN(outbuf);
      httpOut();                            // Call httpRequest to send outbuf to server file fname
      outbuf[0] = '\0';                     // Reinitialise the data buffer.
      bxl=0.0;byl=0.0;bzl=0.0;             //--Reinitialise residuals bx(y,z) for next block
      oldunixTime=0;
    }
    timeElapsed = timeElapsed-2*60*speriod;
  }

  if (!retryRunning && !Particle.connected()){
    // if we have not already scheduled a retry and are not connected
    DEBUG_PRINTLN("schedule"); 
    stopTimer.start();         // set timeout for auto-retry by system
    retryRunning = true;
    retryTimer.start();        // schedula a retry
  }
}


void retryConnect()
{
  if (!Particle.connected())   // if not connected to cloud
  {
    DEBUG_PRINTLN("Reconnecting ..."); 
    stopTimer.start();         // set of the timout time
    WiFi.on();
    Particle.connect();        // start a reconnection attempt
  }
  else                         // if already connected
  {
    DEBUG_PRINTLN("Connected"); 
    retryTimer.stop();         // no further attempts required
    retryRunning = false;
  }
}

void stopConnect(){
  DEBUG_PRINTLN("Connection Stopped"); 

  if (!Particle.connected()){ // if after retryTime no connection
    DEBUG_PRINTLN("Stop reconnecting and switch off WiFi"); 
    WiFi.off();
  }                // stop trying and swith off WiFi
  stopTimer.stop();
}

void checkSdcard_start(){
  //---Check if the sdcard is present and can be initialized
  Serial.println("Initializing SD card...");

  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}

void writeMetadata(){
  myFile = SD.open(fsname, FILE_WRITE); 
  if (myFile) {
    myFile.println("=====================================================");
    myFile.println("Start of new data recording");
    myFile.println("# mvs per Ch and counts per sec");
    myFile.println("Date, Ch1, Ch2, Ch3, counts");
    myFile.close();
  }
  // if the file isn't open, pop up an error and blink the led:
  else {
    Serial.print("error opening ");Serial.println(fsname);
  }
}

void write2sd(float blx, float bly, float blz, String datestr, int counts){
  myFile = SD.open(fsname, FILE_WRITE);
  if (myFile){
    Serial.print("Writing to ");Serial.println(fsname);
    myFile.print(datestr);myFile.print(",");
    myFile.print(blx);myFile.print(",");
    myFile.print(bly);myFile.print(",");
    myFile.print(blz);myFile.print(",");
    myFile.print(counts);myFile.print("\n");
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.print("error opening");Serial.println(fsname);
  }
  
}

//---ads1115 settings
void init_ads1115(){
    Wire.begin();
    Serial.begin(115200); // initialize serial communication 
    Serial.println("Initializing I2C devices..."); 
    adc0.initialize(); // initialize ADS1115 16 bit A/D chip
    Serial.println("Testing device connections...");
    Serial.println(adc0.testConnection() ? "ADS1115 connection successful" : "ADS1115 connection failed");
  
    // We're going to do continuous sampling
    adc0.setMode(ADS1115_MODE_CONTINUOUS);
}

//-----make sure time is synced with cloud
void sync_my_time(){
  Particle.syncTime();
  if(Time.isValid()) { 
    Serial.println("The time is valid."); 
  }
  msecs=millis(); 
  Serial.printlnf("time = %u milliseconds", msecs);
}

  void read_ads1115(){
    //-----Sensor 1 is on P0/N3
    adc0.setMultiplexer(ADS1115_MUX_P0_N3);
    adc0.setGain(ADS1115_PGA_2P048);          //------PGA +/- 2.048V    (res=62.5 muv)
    adc0.setRate(ADS1115_RATE_128);      //------Define sample rate (SPS) 8,16,32,64,128,250,475,860
  
    bx=adc0.getMilliVolts(false);

    //-----Sensor 2 is on P1/N3
    adc0.setMultiplexer(ADS1115_MUX_P1_N3);
    adc0.setGain(ADS1115_PGA_2P048);          //------PGA +/- 2.048V    (res=62.5 muv)
    adc0.setRate(ADS1115_RATE_128);         //------Define sample rate //--delay for power saving
    by=adc0.getMilliVolts(false);
    
    //-----Sensor 3 is on P2/N3
    adc0.setMultiplexer(ADS1115_MUX_P2_N3);
    adc0.setGain(ADS1115_PGA_2P048);          //------PGA +/- 2.048V    (res=62.5 muv)
    adc0.setRate(ADS1115_RATE_128);          //------Define sample rate
    bz=adc0.getMilliVolts(false);
  }
 

void publishToParticle(float Bx, float By, float Bz, int dbsig){ //used for remote status control
    snprintf(buf01, sizeof(buf01), "%.1f,%.1f,%.1f,%2d \n",Bx,By,Bz,dbsig);
    Serial.print(buf01);
    //Publish in Thingspeak
    Particle.publish("data", buf01, PRIVATE);
}

void httpOut() {
  if (client.connect(server, 80)) {
    DEBUG_PRINTLN("Connection OK!");
    //client.println("POST "+cgifile);
    client.println("POST /~groundmags/cgi-bin/receive-mag.cgi HTTP/1.0");
    client.println("Host: "+sserver);
    client.println("Content-Type: application/x-www-form-urlencoded");
    strcat(buf01,fsname);
    strcat(buf01,"&data=");
    lint=strlen(buf01) + strlen(outbuf);           //String data length
    client.printlnf("Content-Length: %d",lint);
    Serial.printlnf("Content-Length: %d",lint);
    client.println();
    client.print(buf01);
    DEBUG_PRINT("buf01= ");DEBUG_PRINTLN(buf01);
    client.print(outbuf);
    DEBUG_PRINT("outbuf= ");DEBUG_PRINTLN(outbuf);
    
    // Read data from the buffer, see what we get back
    receivedData = "";
       
    while(receivedData.indexOf("\r\n\r\n") == -1){ //make sure that we close the post with \r\n\r\n
      memset(dataBuffer, 0x00, sizeof(dataBuffer));
      client.read(dataBuffer, sizeof(dataBuffer));
      receivedData += (const char*)dataBuffer;
    }
    //Print the string
    DEBUG_PRINT("receivedData= ");DEBUG_PRINTLN(receivedData);
    // Stop the current connection
    client.stop();
   
  }
  else {
    //Particle.publish("Failure","Failed to update ThingSpeak channel");
    DEBUG_PRINTLN("Server connection failed. Trying again...");
  }

}

Thanks,

There are lots of debug statements. Do they provide any hint about the possible reason?
You also don’t tell us anything about the RGB LED when this happens.

It is a long piece of code and the problem could be anywhere therein - that’s what all these debug statements are for: To narrow down the place where the issue comes from.

Hi ScruffR,

I used pretty much the same code with a Boron and it works perfectly, the only differences are the WiFi (Cellular) commands. The main problem is that the photon just send data for a few minutes and then stop to do it. The LED remains cyan so the photon is connected all the time, even I can see it in the particle app and flash code. It also keeps taking data in the background and saving it to a sd card, My only guess is that it might be an issue with my WiFi but it appears in the particle app so it must be something else. The key function to interact with the cloud is

 void httpOut

my other guess is the server side but I checked and it works perfectly with the boron using a similar code. At this point I am running out of ideas to find the problem.

Thanks,

The first thing I’d do is getting rid of all instances of String - particularly receiveData.

However, you still haven’t provided any info on what the debug statements tell you. You may also want to check all return values of any of the function calls in your code and compare against the expected values.

Hi @ScruffR, it took me a while for trying and checking all the changes. Here is the output of all debug statements

Counts = 117
Time = Sun Sep 27 23:44:58 2020
UT: 1601250298, S1,S2,S3(mV): 268.86, 2047.94, 25.74
Sensor 1: 268.863mV
Sensor 2: 2047.938mV
Sensor 3: 25.741mV
Content-Length: 226
add to buf: |+0.24+0.00+0.41+117+|
outbuf test1 = U944006410+268.44+2047.94+25.00+1+U657243808+0.10+0.00+0.11+117+U10+0.00+0.00+0.09+117+U10+-0.03+0.00+0.04+117+U10+0.02+0.00+0.02+117+U10+0.01+0.00+0.03+117+U10+0.03+0.00+0.01+117+U10+0.02+0.00+0.02+117+U10+0.04+0.00+0.01+117+U10+0.24+0.00+0.41+117+
Writing to COTSMAG_MK003_P003.txt
done.
Counts = 117
Time = Sun Sep 27 23:45:08 2020
UT: 1601250308, S1,S2,S3(mV): 269.07, 2047.94, 25.91
Sensor 1: 269.070mV
Sensor 2: 2047.938mV
Sensor 3: 25.907mV
Content-Length: 249
add to buf: |+0.21+0.00+0.17+117+|
outbuf test1 = U944006410+268.44+2047.94+25.00+1+U657243808+0.10+0.00+0.11+117+U10+0.00+0.00+0.09+117+U10+-0.03+0.00+0.04+117+U10+0.02+0.00+0.02+117+U10+0.01+0.00+0.03+117+U10+0.03+0.00+0.01+117+U10+0.02+0.00+0.02+117+U10+0.04+0.00+0.01+117+U10+0.24+0.00+0.41+117+U10+0.21+0.00+0.17+117+
Writing to COTSMAG_MK003_P003.txt
done.
RSSI=-63

outbuf test2 = U944006410+268.44+2047.94+25.00+1+U657243808+0.10+0.00+0.11+117+U10+0.00+0.00+0.09+117+U10+-0.03+0.00+0.04+117+U10+0.02+0.00+0.02+117+U10+0.01+0.00+0.03+117+U10+0.03+0.00+0.01+117+U10+0.02+0.00+0.02+117+U10+0.04+0.00+0.01+117+U10+0.24+0.00+0.41+117+U10+0.21+0.00+0.17+117+
Connection OK!
Content-Length: 320
outbuf= U944006410+268.44+2047.94+25.00+1+U657243808+0.10+0.00+0.11+117+U10+0.00+0.00+0.09+117+U10+-0.03+0.00+0.04+117+U10+0.02+0.00+0.02+117+U10+0.01+0.00+0.03+117+U10+0.03+0.00+0.01+117+U10+0.02+0.00+0.02+117+U10+0.04+0.00+0.01+117+U10+0.24+0.00+0.41+117+U10+0.21+0.00+0.17+117+
Response code:200

The changes that I did in the header are


char receivedData[64];                          // C array to save server reply
//String receivedData;      
char fsname[] ="COTSMAG_MK003_P003.txt";      //  the file name in the server end
//String fsname = "COTSMAG_MK003_P003.txt";

and in the http function

void httpOut() {

// Read data from the buffer, see what we get back
    //receivedData = "";
       
    //while(receivedData.indexOf("\r\n\r\n") == -1){ //make sure that we close the post with \r\n\r\n
    //  memset(dataBuffer, 0x00, sizeof(dataBuffer));
    //  client.read(dataBuffer, sizeof(dataBuffer));
    //  receivedData += (const char*)dataBuffer;
    //}

delay(250); //Wait to receive the response
client.parseFloat();
String resp = String(client.parseInt());
DEBUG_PRINT("Response code:");DEBUG_PRINTLN(resp);

So I compiled and run the code for a few days and the photon sent data for one day and a half, after that it stopped but it is still connected to the WiFi and can be flashed from the particle workbench. My concern is that I have another photon with the same code excepting that I am sending data to Thingspeak through the particle.publish command and it is sending data perfectly fine. I also have a Boron that has been running for several days the same code and sending data to my own server and it works fine too. Everything points out that it is a memory problem, do you know if there is any restriction in the amount of characters when sending data to you own server?

Thanks,

As it seems your changes extended the period before the error occurs.
That with the fact that you have not replaced all instances of String compels me to repeat that suggestion with regards to this statement

If you refer to a potential memory leak you may want to keep an eye on your System.freeMemory() value.
However, heap fragmentation (also caused by use of String) cannot be diagnosed reliably that way.

There is a limit how big a single chunk of data sent via TCP can be. For the Photon that is 1023 bytes.