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.
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.
You have not been ignored, i just realised i never answered that message
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 :():
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.
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
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)’
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
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
Thats why i hate C and pointers 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?
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
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.