Photon gets frozen after some time running

Hi

I have a particle photon and it is running with both a particle sensor (PMS5003) and a temperature and humidity sensor (DHT22).

The software i am running in there reads both devices and send the message to a mosquitto MQ queue (home assistant).

It works correctly but after a couple of days, it doesnt work anymore. The photon light turns cyan and no data is sent to the queue. It is like if the device got frozen. Once i restart it, it works fine, but the problem happens constantly every other day.

The code is as follows:

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

#define DHTTYPE  DHT22
#define DHTPIN   D4

DustSensor dustSensor;
PietteTech_DHT DHT(DHTPIN, DHTTYPE);

double serverTemp;
double serverHumidity;
pms5003data data;

void callback(char* topic, byte* payload, unsigned int length);
  MQTT client("192.168.1.12", 1883, callback);   

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

void setup()
{
    dustSensor.begin();
}

void send_dht22_data() {
   int result = DHT.acquireAndWait(2000);
   serverTemp = DHT.getCelsius();
   serverHumidity = DHT.getHumidity();
   if ((serverTemp > 0) || (serverHumidity > 0)) {
       client.connect("photon", "XXX", "XXX");
        if (client.isConnected()) {
            client.publish("temperature",String(serverTemp).substring(0,4));
            client.publish("humidity",String(serverHumidity).substring(0,4));
        } 
   }
}

void send_pms5003_data() {
    if(dustSensor.listen()) {
        data = dustSensor.readData();
        client.connect("photon", "XXX", "XXX");
        if (client.isConnected()) {
            client.publish("pm10",String(data.pm10_standard));
            client.publish("pm25",String(data.pm25_standard));
            client.publish("pm100",String(data.pm100_standard));
    
        } 
    } 
}

void loop() {
    send_dht22_data();
    send_pms5003_data();
    delay(100);
}

Any idea what might be the problem?

Thanks

I'd start with getting rid of all these String() statements and rather use snprintf().
Additionally I'd consider wrapping your readings up into a single event (e.g. as JSON string).
I'd also separate data acquisition from data transfer.

You may also want to not unconditionally call client.connect() when you potentially still have a (re)usable connection.

Which brings us back to some discussion we already had a while ago

With each instance when you were given some hints and then not applying them, the urge to help keeps getting less and less.
In that very thread I even provided a fully working code that does all that and most likely would not suffer from the problem you are facing now.

Hi

You have not been ignored, i just realised i never answered that message :slight_smile:

The reason behind publishing 5 different messages is because it goes to HA and i need 5 different topics for that.

I tried snprintf(), but i was having problems with the conversions, also it requires a lot more of lines of codes, something like this (which doesnt work as i said :():

            char buffer[4];
            char* temp = (char*)(&serverTemp);
            client.publish("temperature",snprintf(buffer, 4, "%s", temp));

As per the is connected validation, i saw that there were some problems with this and it was the recommended code. Should i change it to

        if (!client.isConnected()) {
        client.connect("photon", "mosquitouser", "mosquitouser");
     }
       else {
             client.publish("pm10",String(data.pm10_standard));
            client.publish("pm25",String(data.pm25_standard));
            client.publish("pm100",String(data.pm100_standard));
        } 

Thanks. And once again, i have not intended to ignore those comments, sorry about that

If you are worried about line count and your HA is incapable of parsing JSON messages you could go with this.

  char buf[32]; // big enough for any message to be reusable
  client.publish("pm10" , itoa(buf, data.pm10_standard ));
  client.publish("pm25" , itoa(buf, data.pm25_standard ));
  client.publish("pm100", itoa(buf, data.pm100_standard));

To do it with sprintf() it would be done like this (although I'm not a fan of mutilple instructions per code line)

  char buf[32]; // big enough for any message to be reusable
  sprintf(buf, "%l", data.pm10_standard ); client.publish("pm10" , buf);
  sprintf(buf, "%l", data.pm25_standard ); client.publish("pm25" , buf);
  sprintf(buf, "%l", data.pm100_standard); client.publish("pm100", buf);

The main point is that String() can lead to heap fragmentation and that would fit your experienced freezing of the connection.

2 Likes

ok, i will try that

Regarding the connection check, would this code i pasted work? The reason why i built it like this was because sometimes even when you open a connection, the isConnected returns false as the connection is not ready yet

Thanks

That should work.

1 Like

This worked. Thanks

There is a problem with the first solution. Casting (hate it)

tempsensor_and_particlesensor.ino:54:50: invalid conversion from ‘uint16_t’ {aka ‘short unsigned int’} to ‘char*’ [-fpermissive]
tempsensor_and_particlesensor.ino:54:64: too few arguments to function ‘char* itoa(int, char*, int)’

The second one with sprintf works well

Thanks!

That should not call for casting. Should rather have been

client.publish("pm10" , itoa(data.pm10_standard, buf, 10));

I should have double checked :blush:
I switched first and second parameter and assumed the third (base) was optional :man_facepalming:
https://www.cplusplus.com/reference/cstdlib/itoa/

1 Like

Works perfectly now :slight_smile: Thanks!

I will keep an eye on this and if it gets frozen again with this new code i will answer this topic if thats ok for you, but hope it will work

Thanks for the help once again

2 Likes

Still happening ;(

Is there any way to schedule the photon to be restarted each day at 3am for example? If not, Another option would be to add something to the code to restart the device after n number of executions (don’t know if that’s even possible)

It may well be that one of the used libraties (or your own code) has some memory leak. They are usually difficult to find when you don't know what to look for :wink:
As a (poor) workaround you can use Time.local() and check that against your desired restart time and once you hit that time call System.reset().

BTW, can you post your entire new code to see what you changed?
You could also add SerialLogHandler logger(LOG_LEVEL_ALL); and record the output to see what's happening with the system during the lead-up to such a freeze.

Since you also don't do anything with the MQTT callback you could remove that too.
As I already suggested here

1 Like

Thats why i hate C and pointers :frowning: Im a python person

Thats the code

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

#define DHTTYPE  DHT22
#define DHTPIN   D4

DustSensor dustSensor;
PietteTech_DHT DHT(DHTPIN, DHTTYPE);

double serverTemp;
double serverHumidity;
pms5003data data;

void callback(char* topic, byte* payload, unsigned int length);
  MQTT client("192.168.1.12", 1883, callback);   

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

void setup()
{
    dustSensor.begin();
}

void send_dht22_data() {
   int result = DHT.acquireAndWait(2000);
   serverTemp = DHT.getCelsius();
   serverHumidity = DHT.getHumidity();
   if ((serverTemp > 0) || (serverHumidity > 0)) {
        if (!client.isConnected()) {
       client.connect("photon", "mosquitouser", "mosquitouser");
        }
        else {
          char buf[32]; // big enough for any message to be reusable
        client.publish("temperature" , itoa(serverTemp, buf, 10));
        client.publish("humidity" , itoa(serverHumidity, buf, 10));
        } 
   }
}

void send_pms5003_data() {
    if(dustSensor.listen()) {
        data = dustSensor.readData();
        if (!client.isConnected()) {
            client.connect("photon", "mosquitouser", "mosquitouser");
        }
        else {
   char buf[32]; // big enough for any message to be reusable
   client.publish("pm10" , itoa(data.pm10_standard, buf, 10));
   client.publish("pm25" , itoa(data.pm25_standard, buf, 10));
   client.publish("pm100" , itoa(data.pm100_standard, buf, 10));
        } 
    } 
}

void loop() {
    send_dht22_data();
    send_pms5003_data();
    delay(100);
}

I can add the logger and remove the callback. Regarding the system reset, would it work? As i am adding some delay, it might be that this condition is never triggered. Would it be better to do it based on number of executions (eg, after 50000 executions, restart)?

Or even better, could it be restarted from outside of the running code, like scheduling something in the console?

Thanks!

For one it would be recommended to avoid delay and rather go with a non-blocking approach.
And when dealing with time stamps it's also advisable to not only check for equality (==) to account for situations where you might be missing the exact match (e.g. check => time && != date - most simple would be a midnight reset when currentDate != lastResetData)

This might work as long you never forget to reset the device before its cloud connection freezes :wink:

BTW, you still haven't followed the advice to separate sensor reading from data transmission.

BTW²: itoa() works for your pm### variables as they are integers. However your temp and humidity are doubles and for those it will only give you the truncated integer part but no decimals (e.g. 10.9 will be converted to "10").
If you need some of the decimals you could either scale up your values (e.g. *10 + 0.5 - extra 0.5 for poor-man's rounding) or go back to snprintf() with %.1f format.

Thanks. I just applied this

if (lastRestart != Time.day()) {
    System.reset();
}

Seems to be working fine

Thanks!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.