Hi community,
I fight again serval problems for many days. I hope, you can help me to find the reason. The symptoms are that no events of these electrons recieved my application and the Particle console. I have a python app which waits for events using SSE. This interface works. The problem must be at the electron side. I have running 4 electrons in a field test. So I can not really produce logs which could help me and I cannot watch them the whole time. I only see the physical status when I detected that their is no event for some hours. Sometimes the status led is off, sometimes it breathe white and sometimes i flash green forever (I waited maximum 10 minutes before I tried a reset. After reset, the system works again for a few hours. Then the same issue is there.)
First I thought, it could be the current problem of a Particle service (topic “Electron won’t publish events”) because sometimes I had the issue of fast cyan flashing with red flashes. After Particle’s fix, this disappeared but the main problem is still there.
Second I thought, it could be the “String - heap” problem because the problems appears irregular after a few hours or some days. So I replaced all strings with char arrays. But this doesn’t change anything.
Third I thought it could be a problem, that I don’t always have a Cellular.on() before my System.sleep(…DEEP…) and I use the semi automatic mode. So I put the Cellular.on() before the sleep command, but this also didn’t help against the problem. I have Particle SIM cards.
The code on my electrons do the following:
- Each 15 minutes it measures four values with two sensors and the onboard power unit: 2x temperature, 1x humidity, 1x SOC
- The data is stored at the EEPROM in four queues
- After the 8 round of measurement, the data of the queues is published to the Particle cloud
- The code also have a cloud function to get borders for faster publish intervals.
On the whole, it is a temperatur sensor which publish the measurement in 2 hour intervals. The python app generates alertings and does other stuff. The alterting thresholds are saved on the electron via cloud function. So the electron publish immediately (before the 2h interval) when the threshold/border is breaked.
My english is not the best, so maybe the terms are wrong
This is my code (without Serial prints):
#include "SparkJson/SparkJson.h"
#include "SHT1x/SHT1x.h"
#include "OneWire/OneWire.h"
#include "math.h"
PRODUCT_ID(XXXX);
PRODUCT_VERSION(X);
SYSTEM_MODE(SEMI_AUTOMATIC);
OneWire ds = OneWire(D4);
FuelGauge fuel;
const unsigned long timeToSleep = 60 * 15; // 15 minutes
const int size_of_queue = 8; // reserve var * 4 bytes for addresses = 2 hours
const int steps_to_force = size_of_queue * 1; // force sending after 2 hours
int address_counter_force = 10;
int address_tempDS = 20;
int address_tempSH = 70;
int address_humiSH = 120;
int address_soc = 220;
int address_tempDS_max = 270;
int address_tempDS_min = 320;
int address_tempSH_max = 370;
int address_tempSH_min = 420;
int address_humiSH_max = 470;
int address_humiSH_min = 520;
float tempDS_array[size_of_queue];
float tempSH_array[size_of_queue];
float humiSH_array[size_of_queue];
float soc_array[size_of_queue];
// default values of borders to avoid RTEs
float ds_temp_max = 0;
float ds_temp_min = 0;
float sh_temp_max = 0;
float sh_temp_min = 0;
float sh_humi_max = 0;
float sh_humi_min = 0;
int current_counter_force = 0;
bool border_crashed = false;
char publishDString[80];
char publishSString[80];
char publishHString[80];
char publishPString[80];
char* latitude;
char* longitude;
SHT1x sht1x(0, 1); // dataPin, clockPin
void setup() {
Cellular.off();
Particle.function("borders", saveBorders);
}
int saveBorders(String json) {
// parse string
int lastFound = -1; // needed to get first char
int currentFound = 0;
int step = 0;
float borders[6];
while(currentFound != -1) {
currentFound = json.indexOf("|", lastFound + 1);
if(currentFound != -1) {
borders[step] = json.substring(lastFound + 1, currentFound).toFloat();
lastFound = currentFound;
step++;
}
}
if(currentFound == -1 && step == 0) return -1; // if no | is found, return error.
ds_temp_max = borders[0];
ds_temp_min = borders[1];
sh_temp_max = borders[2];
sh_temp_min = borders[3];
sh_humi_max = borders[4];
sh_humi_min = borders[5];
EEPROM.put(address_tempDS_max, ds_temp_max);
EEPROM.put(address_tempDS_min, ds_temp_min);
EEPROM.put(address_tempSH_max, sh_temp_max);
EEPROM.put(address_tempSH_min, sh_temp_min);
EEPROM.put(address_humiSH_max, sh_humi_max);
EEPROM.put(address_humiSH_min, sh_humi_min);
return 1;
}
float average(float * array, int len) {
float sum = 0.0 ;
for (int i=0; i<len; i++) {
sum += array[i];
}
return sum / len;
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float tempDS, tempSH, humiSH, batterySOC;
if (!ds.search(addr)) {
ds.reset_search();
delay(250);
return;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
return;
}
type_s = 0;
ds.reset(); // first clear the 1-wire bus
ds.select(addr); // now select the device we just found
ds.write(0x44, 0); // or start conversion in powered mode (bus finishes low)
delay(1000); // maybe 750ms is enough, maybe not, wait 1 sec for conversion
present = ds.reset();
ds.select(addr);
ds.write(0xB8,0); // Recall Memory 0
ds.write(0x00,0); // Recall Memory 0
present = ds.reset();
ds.select(addr);
ds.write(0xBE,0); // Read Scratchpad
for (i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
int16_t raw = (data[1] << 8) | data[0];
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
tempDS = (float)raw * 0.0625;
// remove random errors
if(tempDS > 84.0) {
tempDS = tempDS_array[size_of_queue-2]; // take the last measured value instead of the error
}
// Read values from the SHT10 sensor
tempSH = sht1x.readTemperatureC();
humiSH = sht1x.readHumidity();
// Read values of battery
batterySOC = fuel.getSoC();
// routine to check a border crash
EEPROM.get(address_tempDS_max, ds_temp_max);
EEPROM.get(address_tempDS_min, ds_temp_min);
EEPROM.get(address_tempSH_max, sh_temp_max);
EEPROM.get(address_tempSH_min, sh_temp_min);
EEPROM.get(address_humiSH_max, sh_humi_max);
EEPROM.get(address_humiSH_min, sh_humi_min);
if(tempDS > ds_temp_max || tempDS < ds_temp_min || tempSH > sh_temp_max || tempSH < sh_temp_min || humiSH > sh_humi_max || humiSH < sh_humi_min) {
border_crashed = true;
}
// read EEPROM
EEPROM.get(address_counter_force, current_counter_force);
EEPROM.get(address_counter_admin, current_counter_admin);
EEPROM.get(address_tempDS, tempDS_array);
EEPROM.get(address_tempSH, tempSH_array);
EEPROM.get(address_humiSH, humiSH_array);
EEPROM.get(address_soc, soc_array);
// move every entry one position back
for(int n=0; n<size_of_queue; n++) {
tempDS_array[n] = tempDS_array[n + 1];
tempSH_array[n] = tempSH_array[n + 1];
humiSH_array[n] = humiSH_array[n + 1];
soc_array[n] = soc_array[n + 1];
}
tempDS_array[size_of_queue - 1] = tempDS;
tempSH_array[size_of_queue - 1] = tempSH;
humiSH_array[size_of_queue - 1] = humiSH;
soc_array[size_of_queue - 1] = batterySOC;
// store new values in EEPROM
EEPROM.put(address_tempDS, tempDS_array);
EEPROM.put(address_tempSH, tempSH_array);
EEPROM.put(address_humiSH, humiSH_array);
EEPROM.put(address_soc, soc_array);
// Need to do this to go in the correct sleep mode: https://community.particle.io/t/electron-sleep-mode-deep-tips-and-examples/27823
Cellular.on();
// dont send data every time. Store in EEPROM and send whole array sometimes.
if ((current_counter_force >= (steps_to_force - 1)) || border_crashed) { // "- 1" because counter starts with 0
EEPROM.put(address_counter_force, 0);
Cellular.connect();
waitUntil(Cellular.ready);
Particle.connect();
waitUntil(Particle.connected);
Particle.process();
// build transfer string
publishDString[0] = '[';
publishSString[0] = '[';
publishHString[0] = '[';
publishPString[0] = '[';
for(int i=0; i<size_of_queue; i++) {
if(i == (size_of_queue - 1)) { // last iteration -> closing brake
sprintf(publishDString, "%s%.2f]", publishDString, tempDS_array[i]);
sprintf(publishSString, "%s%.2f]", publishSString, tempSH_array[i]);
sprintf(publishHString, "%s%.2f]", publishHString, humiSH_array[i]);
sprintf(publishPString, "%s%.2f]", publishPString, soc_array[i]);
} else {
sprintf(publishDString, "%s%.2f,", publishDString, tempDS_array[i]);
sprintf(publishSString, "%s%.2f,", publishSString, tempSH_array[i]);
sprintf(publishHString, "%s%.2f,", publishHString, humiSH_array[i]);
sprintf(publishPString, "%s%.2f,", publishPString, soc_array[i]);
}
}
Particle.publish("tempSMS", String::format("{\"d\":\"%s\",\"s\":\"%s\",\"h\":\"%s\",\"p\":\"%s\",\"t\":\"%s\"}", publishDString, publishSString, publishHString, publishPString, String::format("%d", timeToSleep).c_str()), PRIVATE); // data max 255 bytes
Particle.process();
delay(10000); // wait 10sec for new borders
} else {
EEPROM.put(address_counter_force, current_counter_force + 1);
}
delay(1000); //can be removed with firmware 0.6.1
System.sleep(SLEEP_MODE_DEEP, timeToSleep - (millis() / 1000));
}
Can someone helps me? I’m very frustrated because I want to have a stable version of my application. At this point, the electrons stop working after some hours or sometimes after 2 days Maybe it is a very simple mistake of myself which results a lot of chaos
Best regards,
Niklas