Hello everyone,
I'm currently working on a project involving a Particle Photon 2 that needs to store data offline and then send it via HTTP when connected to the internet. To achieve this, I'm using external flash memory.
However, I've encountered an issue where the Photon seems to get stuck after running for a while in offline mode. The RGB LED shows either a non-breathing green or no light at all.
I suspect that the problem might be related to the way I'm managing the external flash memory or the way I'm handling the internet connectivity check.
I'd appreciate any insights or suggestions on what might be causing this issue and how I can resolve it.
// This #include statement was automatically added by the Particle IDE.
#include <RTClibraryDS3231_DL.h>
#include "DFRobot_SHT20.h"
#include <DustSensor.h>
// This #include statement was automatically added by the Particle IDE.
#include <SpiffsParticleRK.h>
// This #include statement was automatically added by the Particle IDE.
#include <thermistor-library.h>
#include "Particle.h"
#include "Wire.h"
#define CHUNK_SIZE 100
#define led D7
DustSensor dustSensor;
String PM25 ="";
String PM10 ="";
//////////////////////////////////////
DFRobot_SHT20 sht20;
String Humidity ="";
String Temperature ="";
//////////////////////////////////////
RTC_DS3231 rtc;
//////////////////////////////////////
const int16_t SCD_ADDRESS = 0x62;
int status = 0;
int thermPin = A1;
int thermRes = 8000;
Thermistor Thermistor(thermPin, thermRes);
String CO2= "";
bool isButtonPressed = false;
const int buttonPin = A0;
SpiFlashWinbond spiFlash(SPI1, D5);
SpiffsParticle fs(spiFlash);
unsigned long previousMillis = 0; // Variable to store the last time a message was sent
const long interval = 60000; // Interval in milliseconds (1 minute)
//PM Sensor timeout
unsigned long sensorTimeout = 5000; // Timeout value in milliseconds
unsigned long sensorStartTime;
//////////////////////
#define ONE_DAY_MILLIS (24 * 60 * 60 * 1000)
unsigned long lastSync = millis();
char data[800] = "";
TCPClient client;
String server = "31da7296e5e88ed99a06e8c9fb9eca30.m.pipedream.net"; // Replace with your server URL
unsigned long lastConnectionTime = 0;
unsigned long lastUpdateTime = 0;
const unsigned long postingInterval = 120L * 1000L;
const unsigned long updateInterval = 15L * 1000L;
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
//SYSTEM_MODE(MANUAL); // enabling system thread , sram memory,manual mode
SYSTEM_THREAD(ENABLED);
retained int Counter;
String getMacAddressAsString() {
byte mac[6];
WiFi.macAddress(mac);
String macAddress;
for (int i = 0; i < 6; ++i) {
macAddress += String(mac[i], HEX);
if (i < 5) {
macAddress += ":";
}
}
return macAddress;}
void setup() {
Serial.begin();
dustSensor.begin();
Thermistor.begin();
spiFlash.begin();
Wire.begin();
/////////
sht20.initSHT20(); // Init SHT20 Sensor
delay(100);
sht20.checkSHT20(); // Check SHT20 Sensor
////////////
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
if (rtc.lostPower()) {
Serial.println("RTC lost power, setting the time!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// rtc.adjust(DateTime(2024, 3, 27, 11, 25, 0)); // Adjust as needed
////////////
pinMode(led,OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
fs.withPhysicalSize(16 * 1024 * 1024);
s32_t res = fs.mountAndFormatIfNecessary();
if (res == SPIFFS_OK) {
SpiffsParticleFile file = fs.openFile("data.txt", SPIFFS_O_APPEND | SPIFFS_O_CREAT | SPIFFS_O_WRONLY);
}
}
void loop() {
unsigned long currentMillis = millis(); // Get the current time
if ((currentMillis - previousMillis >= interval) && (status == 0) && (Particle.connected()==false)) // Particle disconnected condition
{ // Check if it's time to execute
previousMillis = currentMillis; // Save the last execution time
//PMS
sensorStartTime = millis(); // Record the start time for sensor operation
while (millis() - sensorStartTime < sensorTimeout) {
if(dustSensor.listen()) {
// Read the data from the sensor
pms5003data data = dustSensor.readData();
PM25 = String(data.pm25_standard);
PM10 = String(data.pm100_standard);
break;
}
}
if (millis() - sensorStartTime >= sensorTimeout) {
System.reset(); // Add error handling or recovery mechanism here
}
//PMS END
//SHT20
float humd = sht20.readHumidity(); // Read Humidity
float temp = sht20.readTemperature();
Humidity = String::format("%.1f", humd);
Temperature = String::format("%.1f", temp);
//
//SCD41 starting
int co2;
uint8_t data[2];
Wire.beginTransmission(SCD_ADDRESS);
Wire.write(0x21);
Wire.write(0xb1);
Wire.endTransmission();
delay(10);
Wire.requestFrom(SCD_ADDRESS, 2);
int i = 0;
while (Wire.available() && i < 2) {
data[i] = Wire.read();
i++;
}
if (i == 2) {
co2 = (int)((uint16_t)data[0] << 8 | data[1]);
CO2 = String(co2);
} else {
// Error handling if data not available
co2 = -1; // Or any other error code
CO2 = String(co2);
}
//SCD41 ending
// Your code to run every 1 minute
String macAddress = getMacAddressAsString();
DateTime now = rtc.now();
String currentTime = String(now.unixtime());
float temperatureValue = Thermistor.getTempC();
String currentTemperature = String::format("%.1f", temperatureValue);
// Save current time and temperature to flash memory
saveDataToFlash(currentTime, macAddress, currentTemperature, CO2,PM25,PM10,Temperature,Humidity);
}
if ((digitalRead(buttonPin) == 0)&&(Particle.connected()==true))
{
if (!isButtonPressed) {
isButtonPressed = true;
status = 1;
readAndPostDataFromFlash();
}
} else {
isButtonPressed = false;
}
// Handle TCPClient connection status
if ((!client.connected())&&(Particle.connected()==true)) {
// Attempt to reconnect
if (client.connect(server, 80)) {
Particle.publish("Connected to server");
} else {
Particle.publish("Failed to connect to server");
}
}
// No need to call client.loop() as it does not exist
}
void saveDataToFlash(String timestamp,String macAddress,String temperature,String CO2,String PM25,String PM10,String Temperature, String Humidity) {
Counter = Counter + 1;
SpiffsParticleFile file = fs.openFile("data.txt", SPIFFS_O_APPEND | SPIFFS_O_WRONLY);
if (file.isValid()) {
// Concatenate all data fields together with a delimiter
String data = "$"+(String(Counter)) +","+timestamp + "," + macAddress + "," + temperature +","+Temperature+ ","+Humidity+","+CO2+","+PM25+","+PM10+"#"+"/n";
// Save the concatenated data string
file.print(data);
file.close();
data = "";
// Particle.publish("Data saved in flash",data);
} else {
// Particle.publish("Failed to open file for appending!");
}
}
void updateData() {
strcpy(data, "");
strcat(data, String(Time.local()));
strcat(data, ",");
float temperatureValue = Thermistor.getTempC();
strcat(data, String::format("%.1f", temperatureValue));
strcat(data, "\n");
if (millis() - lastConnectionTime >= postingInterval) {
httpRequest(data);
data[0] = '\0';
}
lastUpdateTime = millis();
}
bool httpRequest(const char* csvBuffer) {
client.stop();
if (client.connect(server, 80)) {
client.println("POST / HTTP/1.1");
client.println("Host: " + server);
client.println("User-Agent: Particle");
client.println("Content-Type: text/plain");
client.print("Content-Length: ");
client.println(strlen(csvBuffer));
client.println();
client.println(csvBuffer);
return true; // Return true indicating successful connection and request sending
} else {
Serial.println("Failed to connect to server");
return false; // Return false indicating failure to connect
}
}
void readAndPostDataFromFlash() {
digitalWrite(led, HIGH);
delay(2000);
digitalWrite(led, LOW);
SpiffsParticleFile file = fs.openFile("data.txt", SPIFFS_O_RDONLY);
if (file.isValid()) {
String chunk;
while (file.available()) {
chunk = file.readStringUntil('/n');
httpRequest(chunk.c_str());
Particle.publish("Data from flash",chunk);
delay(500);
Particle.process();
}
file.close();
eraseFlashMemory();
Particle.publish("FErased");
Counter = 0;
status = 0;
} else {
Serial.println("Flash error");
}
}
void eraseFlashMemory() {
if (fs.remove("data.txt")) {
Serial.println("Flash Memory Erased");
} else {
Serial.println("Failed to erase flash memory!");
}
delay(1000);
SpiffsParticleFile file = fs.openFile("data.txt", SPIFFS_O_APPEND | SPIFFS_O_CREAT | SPIFFS_O_WRONLY);
}