I am trying to read the Plantower PMS7003 and DHT22 (Relative Humidity and Temperature) sensors using ESP32 and upload the data to 2 Thingspeak channels using WiFi. After several readings, the code breaks and give unrealistic high values. I used the code below.
#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <SoftwareSerial.h>
// WiFi credentials
const char* ssid = "";
const char* password = "";
// ThingSpeak API keys for two channels
const char* apiKey1 = "QX32BBO6UXGWWMCM"; // Channel 1
const char* apiKey2 = "F9PRN6I4UBSG94YF"; // Channel 2
// Define pins and type for DHT22
#define DHTPIN 22 // GPIO pin connected to the DHT22 data pin
#define DHTTYPE DHT22 // DHT22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
// PMS7003 sensor serial connection
SoftwareSerial pmsSerial(17, 16);
// Variables for tracking measurements
unsigned long previousMillis = 0; // Stores last time data was read
const unsigned long interval = 60000; // 1 minute interval for reading data
int measurementCount = 0; // Counter to track the number of measurements
const int maxMeasurements = 7; // Reset sensor after 7 measurements
void setup() {
// Start serial communication for debugging
Serial.begin(115200);
// Start PMS sensor communication at 9600 baud
pmsSerial.begin(9600);
// Initialize DHT22
dht.begin();
// Connect to WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("...");
}
Serial.println(" Connected!");
}
struct pms7003data {
uint16_t framelen;
uint16_t pm10_standard, pm25_standard, pm100_standard;
uint16_t pm10_env, pm25_env, pm100_env;
uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
uint16_t unused;
uint16_t checksum;
};
struct pms7003data data;
void loop() {
// Check if 1 minute has passed since the last reading
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // Reset the timer
if (readPMSdata(&pmsSerial)) {
Serial.println();
Serial.println("---------------------------------------");
Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
Serial.print("\tPM 2.5: "); Serial.print(data.pm25_standard);
Serial.print("\tPM 10: "); Serial.println(data.pm100_standard);
Serial.println("---------------------------------------");
// Increment the measurement counter
measurementCount++;
// If 7 measurements have been taken, reset the sensor and flush the buffer
if (measurementCount >= maxMeasurements) {
resetSensor();
measurementCount = 0; // Reset the counter
}
} else {
Serial.println("Failed to read PMS7003 data.");
}
// Read data from DHT22
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("Humidity: "); Serial.print(humidity);
Serial.print(" %\tTemperature: "); Serial.print(temperature); Serial.println(" °C");
// Send data to ThingSpeak, split across two channels
if (WiFi.status() == WL_CONNECTED) {
// Upload the first set of fields to Channel 1
HTTPClient http1;
String url1 = "http://api.thingspeak.com/update?api_key=" + String(apiKey1) +
"&field1=" + String(data.pm10_standard) +
"&field2=" + String(data.pm25_standard) +
"&field3=" + String(data.pm100_standard) +
"&field4=" + String(data.pm10_env) +
"&field5=" + String(data.pm25_env) +
"&field6=" + String(data.pm100_env);
http1.begin(url1);
int httpCode1 = http1.GET();
if (httpCode1 > 0) {
Serial.printf("Data sent to Channel 1, code: %d\n", httpCode1);
} else {
Serial.printf("Failed to send data to Channel 1, error: %s\n", http1.errorToString(httpCode1).c_str());
}
http1.end();
// Upload the remaining fields to Channel 2
HTTPClient http2;
String url2 = "http://api.thingspeak.com/update?api_key=" + String(apiKey2) +
"&field1=" + String(humidity) +
"&field2=" + String(temperature) +
"&field3=" + String(data.particles_03um) +
"&field4=" + String(data.particles_05um) +
"&field5=" + String(data.particles_10um) +
"&field6=" + String(data.particles_25um) +
"&field7=" + String(data.particles_50um) +
"&field8=" + String(data.particles_100um);
http2.begin(url2);
int httpCode2 = http2.GET();
if (httpCode2 > 0) {
Serial.printf("Data sent to Channel 2, code: %d\n", httpCode2);
} else {
Serial.printf("Failed to send data to Channel 2, error: %s\n", http2.errorToString(httpCode2).c_str());
}
http2.end();
} else {
Serial.println("WiFi not connected, data not sent.");
}
}
}
boolean readPMSdata(Stream *s) {
if (!s->available()) {
Serial.println("No data available from PMS7003.");
return false;
}
uint8_t firstByte = s->peek();
Serial.print("First byte: "); Serial.println(firstByte, HEX); // Debug output
if (firstByte != 0x42) {
Serial.println("First byte is not 0x42, discarding data.");
s->read();
return false;
}
if (s->available() < 32) {
Serial.print("Not enough data available. Bytes available: ");
Serial.println(s->available());
return false;
}
uint8_t buffer[32];
uint16_t sum = 0;
s->readBytes(buffer, 32);
// Calculate checksum and print buffer for debugging
for (uint8_t i = 0; i < 30; i++) {
sum += buffer[i];
Serial.print(buffer[i], HEX); Serial.print(" ");
}
Serial.println();
uint16_t buffer_u16[15];
for (uint8_t i = 0; i < 15; i++) {
buffer_u16[i] = (buffer[2 + i * 2] << 8) | buffer[2 + i * 2 + 1];
}
// Copy buffer to data struct
memcpy((void *)&data, (void *)buffer_u16, sizeof(data));
// Checksum validation
Serial.print("Checksum Expected: "); Serial.println(data.checksum, HEX);
Serial.print("Checksum Calculated: "); Serial.println(sum, HEX);
if (sum != data.checksum) {
Serial.println("Checksum failure");
return false;
}
return true;
}
void resetSensor() {
// Put the PMS7003 sensor to sleep and then wake it up again
Serial.println("Resetting PMS7003...");
pmsSerial.write(0x42); // Command to wake up the sensor
pmsSerial.write(0x4D); // Command to sleep the sensor
delay(3000); // Wait for sensor to sleep
pmsSerial.write(0x42); // Wake up the sensor
pmsSerial.write(0x4D); // Command to wake the sensor
delay(30000); // Allow time for the sensor to stabilize after wake-up
Serial.println("Sensor reset complete.");
}