A time-interval issue caused the ‘on’/‘off’ behaviour. Which looks ok now.
Still see the -1 values, but not so often anymore.
(top graph is from another PM2.5 monitor, bottom the PM2.5 graph of the AirGradient)
The applied changes from Themi, and a few from me (PMS5003 extended lifespan).
--- DIY_PRO_V3_7.ino_v2.4.3.txt 2023-04-29 01:50:56.000000000 +0200
+++ DIY_PRO_V3_7.ino_v2.4.3_2023-06-01_v1.5.txt 2023-06-01 12:44:11.000000000 +0200
@@ -27,6 +27,8 @@
*/
+// Added by Themi
+#include <ESP8266WebServer.h>
#include <AirGradient.h>
#include <WiFiManager.h>
@@ -51,7 +53,7 @@
// time in seconds needed for NOx conditioning
uint16_t conditioning_s = 10;
-// for peristent saving and loading
+// for persistent saving and loading
int addr = 4;
byte value;
@@ -64,6 +66,14 @@
// CONFIGURATION START
+// Added by Themi
+// Set to true if you'd like to report to an airgradient endpoint
+boolean doReport = true;
+// Http port number
+const int port = 8080;
+// Prometheus device id
+const String deviceId = "AirGradient1";
+
//set to the endpoint you would like to use
String APIROOT = "http://hw.airgradient.com/";
@@ -76,11 +86,13 @@
// Display Position
boolean displayTop = true;
-// set to true if you want to connect to wifi. You have 60 seconds to connect. Then it will go into an offline mode.
+// set to true if you want to connect to wifi. You have 90 seconds to connect. Then it will go into an offline mode.
boolean connectWIFI=true;
// CONFIGURATION END
+// Added by Themi
+ESP8266WebServer server(port);
unsigned long currentMillis = 0;
@@ -99,9 +111,13 @@
unsigned long previousCo2 = 0;
int Co2 = 0;
-const int pm25Interval = 5000;
+//const int pm25Interval = 5000;
+const int pm25Interval = 30000;
+const int pm25SleepIntvl = 150000;
unsigned long previousPm25 = 0;
+//unsigned long previousSleepPm25 = 0;
int pm25 = 0;
+boolean pm25sleep = false;
const int tempHumInterval = 2500;
unsigned long previousTempHum = 0;
@@ -148,6 +164,59 @@
ag.CO2_Init();
ag.PMS_Init();
ag.TMP_RH_Init(0x44);
+
+ // Added by Themi
+ server.on("/metrics", HandleMetrics);
+ server.on("/metricsjson", HandleJsonMetrics);
+ server.on("/", HandleIndexHTML);
+ server.onNotFound(HandleNotFound);
+ server.begin();
+}
+
+// Added by Themi
+void HandleMetrics() {
+ String message = "";
+ message += GetPrometheusString("pm02 Particulate Matter PM2.5 value", "pm02 gauge", "pm02", "µg/m³", String(pm25) );
+ message += GetPrometheusString("rco2 CO2 value, in ppm", "rco2 gauge", "rco2", "ppm", String(Co2) );
+ message += GetPrometheusString("Temperature, in degrees Celcius", "temp gauge", "temp", "°C", String(temp) );
+ message += GetPrometheusString("rhum Relative humidity, in percent", "rhum gauge", "rhum", "%", String(hum) );
+ message += GetPrometheusString("TVOC index value", "tvoc gauge", "tvoc", "index", String(TVOC) );
+ message += GetPrometheusString("NOX index value", "nox gauge", "nox", "index", String(NOX) );
+ server.send(200, "text/plain", message);
+}
+
+void HandleJsonMetrics() {
+ String message = "{\"pm02\":"+ String(pm25) + ",\"rco2\":" + String(Co2) + ",\"temp\":" + String(temp) + ",\"rhum\":" + String(hum) + ",\"tvoc\":" + String(TVOC) + ",\"nox\":" + String(NOX) + "}";
+ server.send(200, "application/json", message);
+}
+
+void HandleIndexHTML() {
+ String message = "<!doctype html>";
+ message += "<title>CO2-Monitor</title>";
+ message += "<section class=\"content\">";
+ message += " <h1>Welcome to CO2-Monitor</h1>";
+ message += " <p>I'm a C++ script to received sensor data from the CO2-Monitor and make it available via HTTP</p>";
+ message += " <p>For prometheus metrics, see <a href=\"/metrics\">/metrics</a></p>";
+ message += " <p>For the raw JSON data try <a href=\"/metricsjson\">/metricsjson</a></p>";
+ server.send(200, "text/html", message);
+}
+
+// Added by Themi
+String GetPrometheusString(String proHelp, String proType, String proMetric, String proUnit, String proStat) {
+ String idString = "{id=\"" + String(deviceId) + "\",name=\"" + proType + "\",unit=\"" + proUnit + "\"}";
+ String proOut = "";
+ proOut += "# HELP " + proHelp + "\n";
+ proOut += "# TYPE " + proType + "\n";
+ proOut += proMetric;
+ proOut += idString;
+ proOut += proStat;
+ proOut += "\n";
+ return proOut;
+}
+
+// Added by Themi
+void HandleNotFound() {
+ server.send(404, "text/plain", "Not found");
}
void loop() {
@@ -155,10 +224,16 @@
updateTVOC();
updateOLED();
updateCo2();
+ //
+ sleepPm25();
updatePm25();
updateTempHum();
+ // Added by Themi
+ if (doReport) {
sendToServer();
}
+ server.handleClient();
+}
void inConf(){
setConfig();
@@ -307,12 +382,26 @@
}
}
+void sleepPm25()
+{
+ if (currentMillis - previousPm25 >= pm25SleepIntvl && pm25sleep) {
+// This will not work because it is true also
+// previousSleepPm25 = currentMillis;
+ ag.wakeUp();
+ pm25sleep = false;
+ }
+}
+
void updatePm25()
{
- if (currentMillis - previousPm25 >= pm25Interval) {
- previousPm25 += pm25Interval;
+ if (currentMillis - previousPm25 >= pm25SleepIntvl + pm25Interval) {
+ previousPm25 = currentMillis;
+// if (currentMillis - previousPm25 >= pm25Interval) {
+// previousPm25 = currentMillis;
pm25 = ag.getPM2_Raw();
Serial.println(String(pm25));
+ ag.sleep();
+ pm25sleep = true;
}
}
@@ -403,6 +492,17 @@
updateOLED2("90s to connect", "to Wifi Hotspot", HOTSPOT);
wifiManager.setTimeout(90);
+
+
+
+
+
+
+
+
+
+
+
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
updateOLED2("booting into", "offline mode", "");
Serial.println("failed to connect and hit timeout");