Photon stops responding randomly

I have been using other boards for years and recently bought a Photon for a gate opener project. The gate is several hundred feet from my house. I am using a high gain antennae and get RSSI in the high 50 to mid 60s. The photon sends and receives MQTT messages. Every since I have installed it the photon it randomly stops responding and requires me to go the device and power cycle it. It will be up from several hours to several days. I am sure it is related to a signal interruption or a disrupted connection to the cloud. I am not sure where to even start troubleshooting. I have tried to add a function that restarts the photon if it is not connected to the network but it didn’t seem to make any difference. I can post my code if needed. I upgraded to the firmware to v.0.7.0-rc.3 and it seemed to make it more stable but I can still only get a few days out of it before it stops responding. Thanks in advance.

Yes, it is needed. Also, please explain what "stop responding" means.

1 Like

The photon stops responding to the IDE. It also stops processing my code because it stops sending and receiving MQTT messages. For some reason I cannot copy and paste my code so I shared my project.

https://go.particle.io/shared_apps/59fb004d548908d9380004ea

I think we can see a clear suspect. Strings, which is the guess I would have made even before you shared the code.

Rip them all out replace them with char arrays and use snprintf to create your messages.

I would also maybe avoid using strings to track things like status, you can use other varaible types, give them aliases or perhaps Enumerate them.

1 Like

Hi @hustjona

I would follow @Viscacha advice here.

Everytime you do this:

 if (buttonDebounce(2) == 1) {
        strState = "OFF";
    } else {
        strState = "ON";
    }

You create a new small String object and render the old one as garbage. Eventually memory becomes more and more fragmented until the system cannot allocate enough storage for an object and your program crashes. Doing things the way @Viscacha recommended will make the decision variables boolean or integers instead of String and not cause this fragementation by reusing the same memory over and over for the char array strings.

I seem to have a similar issue. I am sending one value to both the Particle cloud and to Ubidots. I have some #Define strings used for my Ubidots credentials. The only other string is a type cast of my float variable to string in order to publish the value on Particle.

It seems my particle stops responding after 8 to 10 hours. The LED on the Photon blinks cyan fast and the console indicates the device went offline. This behavior is seen with both my Photon running v0.6.2 and on my RedBear Duo.

The temperature is measured by an Adafruit MCP9808 sensor via I2C. My code is as follows (modified to remove some development comments and personal ID):

#include <Ubidots.h>
#include <Adafruit_MCP9808.h>


#define TOKEN "NOT_THE_REAL_TOKEN"  // Add here your Ubidots TOKEN

#define VARIABLE_IDENTIFIER "temperature" // Add a variable identifier, it must be in lowercase
#define DATA_SOURCE_NAME "ANON"

// Create the MCP9808 temperature sensor object
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

float temp = 0.0;

Ubidots ubidots(TOKEN);

void getTemperature()
{
    temp = tempsensor.readTempC();
    unsigned long devTime = Time.now();
    Particle.publish("Temperature: ", String(temp));
    

    ubidots.add(VARIABLE_IDENTIFIER, temp, NULL, devTime);

    ubidots.sendAll();
    
}

Timer timer(30000, getTemperature);

void setup() {
    Serial.begin(115200);
    ubidots.setDebug(true);    //Uncomment for debug messages
    
    tempsensor.begin();
    timer.start();
    Particle.syncTime();
    
    // connect to the server
    String myID = System.deviceID();
    
    ubidots.setDeviceLabel(DATA_SOURCE_NAME);

}

void loop() {
   
}

Your getTemperature() function creates a new String object every 30 seconds. That could lead to heap fragmentation eventually. Try using a char array instead.

char tempString[10];

void getTemperature()
{
    temp = tempsensor.readTempC();
    unsigned long devTime = Time.now();
    snprintf(tempString, 10, "%.2f", temp);
    Particle.publish("Temperature: ", tempString);
    
    ubidots.add(VARIABLE_IDENTIFIER, temp, NULL, devTime);

    ubidots.sendAll();
    
}

By the way, what you're doing with String(temp) is not a type cast; that expression creates a String object using the float as input, that's an entirely different thing from a type cast.

2 Likes

I have converted all of my strings to char* variables. I had some messages that were no longer needed so it was easy to remove them. I will let you know if that fixes the issue. Thank you all so very much.

// This #include statement was automatically added by the Particle IDE.
#include <adafruit-ina219.h>

// This #include statement was automatically added by the Particle IDE.
#include "MQTT.h"

Adafruit_INA219 ina219;

boolean updateSuccess = false;
char* pushState;
char* doorbellState;
char* sensorState;
char* charState;
int intRSSI;
int intRSSIPrev;
double totalVolt = 0;
double avgVolt = 0;
int avgTimes = 0;
double totalAmp = 0;
double avgAmp = 0;
char* charMsg;
unsigned long timeMqttRetry;

Timer timer(60000, send_voltage);

STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));

void callback(char* topic, byte* payload, unsigned int length);

MQTT client("192.168.0.20", 1883, callback);

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;

    if (!strcmp(p, "ON")) {
        Serial.println("relay on");
        digitalWrite(A0, LOW);
        //digitalWrite(D7, HIGH);
    }
    if (!strcmp(p, "OFF")) {
        Serial.println("relay off");    
        digitalWrite(A0, HIGH);
    }
}

void mqtt_connect() {
    // connect to the server
    client.connect("GateOpener");
    // publish/subscribe
    if (client.isConnected()) {
        charMsg = "ONLINE";
        client.publish("openhab/gate/controller", charMsg);
        client.subscribe("openhab/gate/togglerelay");
    }
}

void send_voltage(){
    avgVolt = totalVolt/avgTimes;
    avgAmp = totalAmp/avgTimes;
    client.publish("openhab/gate/voltage", String(avgVolt,3));
    client.publish("openhab/gate/amp", String(avgAmp,2));
    client.publish("openhab/gate/memory", String(System.freeMemory()));
    totalVolt = 0;
    totalAmp = 0;
    avgTimes = 0;
}

int buttonDebounce(int pinIn) {
    int value = 0;
    int t = 0;
    
    for (int d = 0; d <= 10; d++) {
      if (digitalRead(pinIn) == HIGH){
        t = 1000;
      } else {
        t = 0;
      }
      value = value + t;
    }
    value = value / 10;
    if ( value > 700  ) {
      // Open
      return 1;
    } else {
      // Closed
      return 0;
    }
}

void setup() {
    Serial.begin(9600);
    Serial.println("Booting");
    Serial.println("Ready");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    pinMode(D2, INPUT_PULLUP);
    pinMode(D3, INPUT_PULLUP);
    pinMode(A0, OUTPUT);
    digitalWrite(A0, HIGH);
    
    uint32_t currentFrequency;
    ina219.begin();
    timer.start();
    mqtt_connect();
}

void loop() {
    if (client.isConnected()) {
        client.loop();
    }else{
        System.reset();
    }
    
    // measure voltage and current
    float shuntvoltage = 0;
    float busvoltage = 0;
    float current_mA = 0;
    float loadvoltage = 0;
    shuntvoltage = ina219.getShuntVoltage_mV();
    busvoltage = ina219.getBusVoltage_V();
    current_mA = ina219.getCurrent_mA();
    loadvoltage = busvoltage + (shuntvoltage / 1000);
    
    if (buttonDebounce(2) == 1) {
        charState = "OFF";
    } else {
        charState = "ON";
    }
    if (pushState != charState){
        client.publish("openhab/gate/toggleswitch", charState);
        pushState = charState;
    }
    
    // gate door bell
    if (analogRead(A1) > 2000) {
        charState = "OFF";
    } else {
        charState = "ON";
    }
    if (doorbellState != charState){
        client.publish("openhab/gate/doorbell", charState);
        doorbellState = charState;
    }
    
    // gate sensor
    if (current_mA > 200) {
        charState = "moving";
    } else if (buttonDebounce(3) == 1) {
        charState = "open";
    } else {
        charState = "closed";
    }
    if (sensorState != charState){
        client.publish("openhab/gate/state", charState);
        sensorState = charState;
    }
    
    intRSSI = WiFi.RSSI();
    if (intRSSI == intRSSIPrev || intRSSI + 1 == intRSSIPrev || intRSSI -1 == intRSSIPrev|| intRSSI + 2 == intRSSIPrev || intRSSI -2 == intRSSIPrev){
    } else {
        client.publish("openhab/gate/rssi", String(intRSSI));
        intRSSIPrev = intRSSI;
    }
    
    totalVolt = totalVolt + busvoltage;
    totalAmp = totalAmp + current_mA;
    avgTimes = avgTimes + 1;
}

You still have these strings in the send_voltage() function,

void send_voltage(){
    avgVolt = totalVolt/avgTimes;
    avgAmp = totalAmp/avgTimes;
    client.publish("openhab/gate/voltage", String(avgVolt,3));
    client.publish("openhab/gate/amp", String(avgAmp,2));
    client.publish("openhab/gate/memory", String(System.freeMemory()));
    totalVolt = 0;
    totalAmp = 0;
    avgTimes = 0;
}

BTW, when you post code, you should enclose it like so to make it format properly,

```cpp
// your code here
```

(those characters, ```, are grave accent marks, not apostrophes)

Thanks very much for the reply Ric. Will give that a try.

My apologies too as my type casting statement is wrong. String is an object.

I have changed my code. It locked up again and when I went to reset it the controller is breathing green.

void send_voltage(){
    avgVolt = totalVolt/avgTimes;
    avgAmp = totalAmp/avgTimes;
    sprintf(buffer, "%02.02f", avgVolt);
    sprintf(buffer1, "%02.02f", avgAmp);
    client.publish("openhab/gate/voltage", buffer);
    client.publish("openhab/gate/amp", buffer1);
    totalVolt = 0;
    totalAmp = 0;
    avgTimes = 0;
}

Under what conditions did it lock up. Did this happen right away, or after some period of time. Is the rest of your code the same as it was (except for the addition of buffer and buffer1)? Please edit your posts to format your code properly, it makes it easier to read for those trying to help you.

This use of char* might not actually do what you intend

e.g. when you do this

    ...
    if (buttonDebounce(2) == 1) {
        charState = "OFF";
    } else {
        charState = "ON";
    }
    if (pushState != charState){
        client.publish("openhab/gate/toggleswitch", charState);
        pushState = charState;
    }
    
    // gate door bell
    if (analogRead(A1) > 2000) {
        charState = "OFF";
    } else {
        charState = "ON";
    }
    ...

charState may well get four different values and a subsequent check for charState == "ON" will most likely fail too.

The reason being, that with charState = "someString" you only assign the address of the string literal wherever the compiler/linker happened to place it in the process.
f the compiler/linker is clever enough, it might actually use only one literal for each instance of a unique string and reuse the reference, but I'd definetly not bet on it.
String comparisons shoule be made with strcmp() and string assignments should either be made with direct transfer (e.g. strcpy(), snprintf(), ...) or by use of a defined list of possible values (e,g, const char states[] = { "ON", "OFF", ... }) or even better not as strings at all but via numeric values which - in turn - can be used as index for a string list - enum might help making the numeric states readable.

I implemented the suggested code and unfortunately the Photon still stops responding. Is there any way to have the device reset on a periodic basis?

I noticed something about an application watchdog in the reference documentation. Anyone use it before? As the light is fast blinking cyan, perhaps there is a way to trigger a system reset if the state changes?

Any additional troubleshooting tips to help me find the issue are welcome…

I have a Photon that is reading a temperature using a MCP9808 over I2C. A timer is set for 30 seconds, and every time it expires it reads the temperature and publishes the value on Ubidots as well as the Particle Cloud.

This code works great for 8 to 12 hours, but then the Photon stops communicating and is its LED flashes cyan at a fast rate. The only way to recover is to physically press the button on the Photon which is less than ideal.

Originally I posted the issue in another topic (Photon stops responding randomly) and it was suggested that I convert any strings to character arrays to avoid possible memory fragmentation. I did so and the problem still exists.There has been no further response to my update on the previous thread.

If anyone has any suggestions on other things I could try to either troubleshoot the issue, or steps I can take to make my code more resilient so it can recover automatically as opposed to requiring human intervention via physical reset, I would greatly appreciate it.

Thanks in advance.

In that other thread (Update: now “this thread”, after re-joining threads) you just mentioned you’ve implemented the suggestions, but you haven’t shown your “final” code.

BTW, opening a new thread for the same issue isn’t the best of practices, hence I’ll move your post back to the end of the original thread. This will also push it up the list again.

On the other hand “thread jacking” further up, wasn’t best practice either.

1 Like

Thanks for your response ScruffR and my sincerest apologies on both my forum faux pas. :disappointed_relieved:

Here is my updated source code:

    #include <Ubidots.h>
    #include <Adafruit_MCP9808.h>


    #define TOKEN "NOT_THE_REAL_TOKEN"  // Add here your Ubidots TOKEN
    #define VARIABLE_IDENTIFIER "temperature" // Add a variable identifier, it must be in lowercase
    #define DATA_SOURCE_NAME "ANON"

    // Create the MCP9808 temperature sensor object
    Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

    float temp = 0.0;
    char tempString[10];

    Ubidots ubidots(TOKEN);

    void getTemperature()
    {
    temp = tempsensor.readTempC();
    unsigned long devTime = Time.now();
    snprintf(tempString, 10, "%.2f", temp);
    Particle.publish("Temperature: ", tempString);

    ubidots.add(VARIABLE_IDENTIFIER, temp, NULL, devTime);
    //Serial.println(devTime);
    ubidots.sendAll();
     
    }

    Timer timer(30000, getTemperature);

    void setup() {
    //Serial.begin(115200);
    //ubidots.setDebug(true);    //Uncomment for debug messages
    tempsensor.begin();
    timer.start();
    Particle.syncTime();

    // connect to the server
    //String myID = System.deviceID();

    ubidots.setDeviceLabel(DATA_SOURCE_NAME);

    }

    void loop() {
       
    }

After skimming over the Ubidots library I see frequent use of String objects and ontop of that malloc() - this may or may not contribute to the issue.

Although I haven’t followed the whole process through I suspect this function may cause problems


/**
 * Send all package via TCP method
 * @arg buffer the message to send
 * @reutrn true upon success, false upon error.
 */

bool Ubidots::sendAllTCP(char* buffer) {
    int i = 0;
    while (!_client.connected() && i < 6) {
        i++;
        if (_debug) {
            Serial.println("not connected, trying to connect again");
        }
        _client.connect(_server, PORT);
        if (i == 5) {
            if (_debug) {
                Serial.println("Max attempts to connect reached, data could not be sent");
            }
            return false;
        }
    }
    if (_client.connected()) {        // Connect to the server
        if (_debug) {
            Serial.println("Sending data");
        }
        _client.println(buffer);
        _client.flush();
        _client.stop();
        free(buffer);
        _currentValue = 0;
        return true;
    }
    _currentValue = 0;
    return false; // If any of the above conditions is reached, returns false to indicate an unexpected issue
}

There are code paths that don’t free() the 700 byte buffer. Which - over time - may exhaust the available heap space.

You can print/publish the freeMemory() reading and see whether the value decreases prior the connection loss.

BTW, you can reword this

Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

more economically this way

Adafruit_MCP9808 tempsensor;

Update:

I have filed an issue on the Ubidots GitHub repo.
@mariahernandez, could you please check if my assumption is valid and whether this really is a potential issue?

Hello @ScruffR,

I’m going to assign the revision of the Particle’s Library to the official maintainer (@jotathebest). He will answer you as soon as possible!

Thanks.

All the best,
Maria C.

2 Likes