Hi everyone,
I've been working on a project using an ESP32 to monitor air quality and environmental conditions with sensors like PMS7003 and DHT22. The ESP32 is supposed to connect to WiFi, serve a web page where I can view the sensor data, and also provide a downloadable CSV file with logged data. However, I'm having trouble getting it to stay on. The ESP32 turns on, connects to the internet, and then suddenly reboots.
The issue seems to happen shortly after the WiFi connection is established, but I can't pinpoint why. I've checked my code for any obvious errors, and everything seems to be in order. The WiFi credentials are correct, and the code compiles without any issues.
Here is what I've got
<#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <TimeLib.h>
#include <AirGradient.h>
#include <DHT.h>
#ifdef ESP832
AirGradient ag = AirGradient(DIY_BASIC);
#else
AirGradient ag = AirGradient(ONE_INDOOR);
// AirGradient ag = AirGradient(OPEN_AIR_OUTDOOR);
#endif
#define DHTPIN 27
#define DHTTYPE DHT22
void failedHandler(String msg);
const char* ssid = "Meter 1";
const char* password = "12345671";
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sensor Readings</title>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h2> </h2>
<table id="sensorTable">
<tbody>
<!-- Table rows will be inserted here -->
</tbody>
</table>
<!-- Current sensor values -->
<h3>Device Readings</h3>
<p id="currentValues">Loading...</p>
<!-- Button to download values -->
<button id="downloadButton">Download Values</button>
<script>
var data = [];
// Function to update the table with sensor values and current time
function updateSensors() {
var tableBody = document.getElementById("sensorTable").getElementsByTagName('tbody')[0];
tableBody.innerHTML = "";
data.forEach(function(rowData) {
var row = tableBody.insertRow(-1);
rowData.forEach(function(cellData) {
var cell = row.insertCell();
cell.textContent = cellData;
});
});
}
// Function to display the current sensor values
function displayCurrentValues(values) {
var currentValueElement = document.getElementById("currentValues");
currentValueElement.innerHTML = "PM1 (µg/m3): " + values[0] + "<br>" +
"PM2.5 (µg/m3): " + values[1] + "<br>" +
"PM10 (µg/m3): " + values[2] + "<br>" +
"Humidity (%): " + values[3] + "<br>" +
"Temperature (°C): " + values[4];
}
// Function to download the values into a text file
function downloadValues() {
fetch('/values')
.then(response => response.text())
.then(csvContent => {
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", 'data:text/csv;charset=utf-8,' + encodedUri);
link.setAttribute("download", "sensor_values.csv");
document.body.appendChild(link);
link.click();
})
.catch(error => console.error('Error downloading the values:', error));
}
// Click event on the download button
document.getElementById("downloadButton").addEventListener("click", downloadValues);
// Periodically update data
setInterval(function() {
fetch('/values')
.then(response => response.text())
.then(responseData => {
data = JSON.parse(responseData);
updateSensors();
})
.catch(error => console.error('Error fetching sensor values:', error));
// Fetch and display current sensor values
fetch('/current-values')
.then(response => response.json())
.then(currentValues => displayCurrentValues(currentValues))
.catch(error => console.error('Error fetching current sensor values:', error));
}, 5000);
</script>
</body>
</html>
)rawliteral";
struct SensorData {
std::vector<int> values;
};
std::vector<SensorData> sensorDataList = {{}, {}, {}, {}, {}}; // Each entry corresponds to a sensor
// Sensor values definition
DHT dht(DHTPIN, DHTTYPE);
String getTime(int i) {
return String(hour()) + ":" + String(minute()) + ":" + String(second());
}
int sensor1 = ag.pms7003.getPm01Ae();
int sensor2 = ag.pms7003.getPm25Ae();
int sensor3 = ag.pms7003.getPm10Ae();
int sensor4 = dht.readHumidity();
int sensor5 = dht.readTemperature();
void setup() {
Serial.begin(9600);
dht.begin();
#ifdef ESP832
if (ag.pms7003.begin(&Serial) == false) {
failedHandler("Init PMS7003 failed ONE");
}
#else
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
if (ag.pms7003t_1.begin(Serial) == false) {
failedHandler("Init PMS7003T failed TWO");
}
} else {
if (ag.pms7003.begin(Serial) == false) {
failedHandler("Init PMS7003T failed THREE");
}
}
#endif
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("connecting...");
}
Serial.println(WiFi.localIP());
server.begin();
setenv("TZ", "GMT-3", 1); // Set time zone to GMT-3
configTime(0, 0, "pool.ntp.org");
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/html", index_html);
});
server.on("/values", HTTP_GET, [](AsyncWebServerRequest *request) {
String csvContent = "Date/Time,PM 1,PM 2.5,PM 10,Humidity,Temperature\n";
for (size_t i = 0; i < sensorDataList[0].values.size(); i++) {
csvContent += getTime(i) + ","; // Using getTime() instead of setTime()
for (size_t j = 0; j < sensorDataList.size(); j++) {
csvContent += String(sensorDataList[j].values[i]) + ",";
}
csvContent += "\n";
}
request->send(200, "text/csv", csvContent);
});
server.on("/current-values", HTTP_GET, [](AsyncWebServerRequest *request) {
String currentValues = "[" + String(ag.pms7003.getPm01Ae()) + "," + String(ag.pms7003.getPm25Ae()) + "," +
String(ag.pms7003.getPm10Ae()) + "," + String(dht.readHumidity()) + "," +
String(dht.readTemperature()) + "]";
request->send(200, "application/json", currentValues);
});
}
uint32_t lastRead = 0;
void loop() {
int PM2;
bool readResult = false;
uint32_t ms = (uint32_t)(millis() - lastRead);
if (ms >= 5000) {
lastRead = millis();
#ifdef ESP32
if (ag.pms7003.isFailed() == false) {
PM2 = ag.pms7003.getPm25Ae();
Serial.printf("PM2.5 in µg/m3: %d\r\n", PM2);
Serial.printf("PM2.5 in US AQI: %d\r\n",
ag.pms7003.convertPm25ToUsAqi(PM2));
} else {
Serial.println("PMS sensor failed");
}
#else
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
if (ag.pms7003t_1.isFailed() == false) {
PM2 = ag.pms7003t_1.getPm25Ae();
readResult = true;
}
} else {
if (ag.pms7003.isFailed() == false) {
PM2 = ag.pms7003.getPm25Ae();
readResult = true;
}
}
if (readResult) {
Serial.printf("PM2.5 in µg/m3: %d\r\n", PM2);
if (ag.getBoardType() == OPEN_AIR_OUTDOOR) {
Serial.printf("PM2.5 in US AQI: %d\r\n", ag.pms7003t_1.convertPm25ToUsAqi(PM2));
} else {
Serial.printf("PM2.5 in US AQI: %d\r\n", ag.pms7003.convertPm25ToUsAqi(PM2));
}
} else {
Serial.println("PMS sensor failed");
}
#endif
}
// Add new values to the sensor data list
sensorDataList[0].values.push_back(ag.pms7003.getPm01Ae());
sensorDataList[1].values.push_back(ag.pms7003.getPm25Ae());
sensorDataList[2].values.push_back(ag.pms7003.getPm10Ae());
sensorDataList[3].values.push_back(dht.readHumidity());
sensorDataList[4].values.push_back(dht.readTemperature());
}
void failedHandler(String msg) {
Serial.println(msg);
delay(10000);
}