From 415d8e07681175dcc8e1b505db23c580e8b74c90 Mon Sep 17 00:00:00 2001 From: Vagif Veliev Date: Sun, 16 Oct 2022 00:17:25 -0400 Subject: [PATCH 1/3] feat: adding prometheus example --- .../DIY_BASIC_PROMETHEUS.ino | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino diff --git a/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino b/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino new file mode 100644 index 00000000..04001b31 --- /dev/null +++ b/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino @@ -0,0 +1,335 @@ +/* + * This sketch connects an AirGradient DIY sensor to a WiFi network, and runs a + * tiny HTTP server to serve air quality metrics to Prometheus. + */ + +#include +#include +#include +#include +#include +#include "SSD1306Wire.h" + +// Config ---------------------------------------------------------------------- + +// Optional. +const char* deviceId = "GVK-air2"; + +// set to 'F' to switch display from Celcius to Fahrenheit +const char temp_display = 'C'; + +// Hardware options for AirGradient DIY sensor. +#define SET_PMS +// Pick One CO2 sensor +// #define SET_CO2_S8 +#define SET_CO2_MH_Z19 +// #define SET_SHT +// #define +//#define SET_DISPLAY + + +// WiFi and IP connection info. +const char* ssid = "GVK"; +const char* password = "os179nyqzm"; +const int port = 9926; + +// Uncomment the line below to configure a static IP address. +// #define staticip +#ifdef staticip +IPAddress static_ip(10, 31, 17, 20); +IPAddress gateway(10, 31, 17, 1); +IPAddress subnet(255, 255, 255, 0); +#endif + + +#ifdef SET_DISPLAY +// The frequency of measurement updates. +const int updateFrequency = 5000; +const int displayTime = 5000; +#endif // SET_DISPLAY + +// Config End ------------------------------------------------------------------ + +#define ERROR_PMS 0x01 +#define ERROR_SHT 0x02 +#define ERROR_CO2 0x04 + +AirGradient ag = AirGradient(); + +TMP_RH value_sht; +int value_pm; +int value_co2; + +#ifdef SET_DISPLAY +long lastUpdate = 0; +#endif // SET_DISPLAY + +SSD1306Wire display(0x3c, SDA, SCL); +ESP8266WebServer server(port); + +void setup() { + Serial.begin(9600); + +// Set airfradiaend modules as needed. +#ifdef SET_DISPLAY + display.init(); + display.flipScreenVertically(); + showTextRectangle("Init", String(ESP.getChipId(), HEX), true); +#endif // SET_DISPLAY +#ifdef SET_PMS + ag.PMS_Init(); +#endif +#ifdef SET_CO2_S8 + ag.CO2_Init(); +#endif // SET_CO2_S8 +#ifdef SET_CO2_MH_Z19 + ag.MHZ19_Init(19); +#endif // SET_CO2_MH_Z19 +#ifdef SET_SHT + ag.TMP_RH_Init(0x44); +#endif // SET_SHT + + // Set static IP address if configured. +#ifdef staticip + WiFi.config(static_ip, gateway, subnet); +#endif // staticip + + // Set WiFi mode to client (without this it may try to act as an AP). + WiFi.mode(WIFI_STA); + + // Configure Hostname + if ((deviceId != NULL) && (deviceId[0] == '\0')) { + Serial.printf("No Device ID is Defined, Defaulting to board defaults"); + } + else { + wifi_station_set_hostname(deviceId); + WiFi.setHostname(deviceId); + } + + // Setup and wait for WiFi. + WiFi.begin(ssid, password); + Serial.println(""); + while (WiFi.status() != WL_CONNECTED) { + delay(500); +#ifdef SET_DISPLAY + showTextRectangle("Trying to", "connect...", true); +#endif // SET_DISPLAY + Serial.print("."); + } + + Serial.print("\nConnected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + Serial.print("MAC address: "); + Serial.println(WiFi.macAddress()); + Serial.print("Hostname: "); + Serial.println(WiFi.hostname()); + server.on("/", HandleRoot); + server.on("/metrics", HandleRoot); + server.onNotFound(HandleNotFound); + + server.begin(); + Serial.println("HTTP server started at ip " + WiFi.localIP().toString() + ":" + String(port)); +#ifdef SET_DISPLAY + showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port), true); +#endif // SET_DISPLAY +} + +void loop() { + server.handleClient(); +#ifdef SET_DISPLAY + updateScreen(millis()); +#endif // SET_DISPLAY +} + +uint8_t update() { + uint8_t result = 0; +#ifdef SET_PMS + { + int value = ag.getPM2_Raw(); + if(value) + value_pm = value; + else + result += ERROR_PMS; + } +#endif // SET_PMS + +#ifdef SET_CO2_S8 + { + int value = ag.getCO2_Raw(); + if(value > 0) + value_co2 = value; + else + result += ERROR_CO2; + } +#endif // SET_CO2_S8 + +#ifdef SET_CO2_MH_Z19 + { + int value = ag.readMHZ19(); + if(value > 0) + value_co2 = value; + else + result += ERROR_CO2; + } +#endif // SET_CO2_MH_Z19 + +#ifdef SET_SHT + { + TMP_RH value = ag.periodicFetchData(); + if(value.t != NULL && value.rh != NULL) + value_sht = value; + else + result += ERROR_SHT; + } +#endif // SET_SHT + +#ifdef SET_DISPLAY + lastUpdate = millis(); +#endif + return result; +} + +String GenerateMetrics() { + String message = ""; + String idString = "{id=\"" + String(deviceId) + "\",mac=\"" + WiFi.macAddress().c_str() + "\"}"; + + // Update sensor data + uint8_t error = update(); + +#ifdef SET_PMS + if(!(error & ERROR_PMS)) + { + message += "# HELP pm02 Particulate Matter PM2.5 value\n"; + message += "# TYPE pm02 gauge\n"; + message += "pm02"; + message += idString; + message += String(value_pm); + message += "\n"; + } +#endif // SET_PMS + +#ifdef SET_CO2_S8 + if(!(error & ERROR_CO2)) + { + message += "# HELP rco2 CO2 value, in ppm\n"; + message += "# TYPE rco2 gauge\n"; + message += "rco2"; + message += idString; + message += String(value_co2); + message += "\n"; + } +#endif // SET_CO2_S8 + +#ifdef SET_CO2_MH_Z19 + if(!(error & ERROR_CO2)) + { + message += "# HELP rco2 CO2 value, in ppm\n"; + message += "# TYPE rco2 gauge\n"; + message += "rco2"; + message += idString; + message += String(value_co2); + message += "\n"; + } +#endif // SET_CO2_MH_Z19 + +#ifdef SET_SHT + if(!(error & ERROR_SHT)) + { + message += "# HELP atmp Temperature, in degrees Celsius\n"; + message += "# TYPE atmp gauge\n"; + message += "atmp"; + message += idString; + message += String(value_sht.t); + message += "\n# HELP rhum Relative humidity, in percent\n"; + message += "# TYPE rhum gauge\n"; + message += "rhum"; + message += idString; + message += String(value_sht.rh); + message += "\n"; + } +#endif // SET_SHT + + return message; +} + +void HandleRoot() { + server.send(200, "text/plain", GenerateMetrics() ); +} + +void HandleNotFound() { + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/html", message); +} + +// DISPLAY +#ifdef SET_DISPLAY +void showTextRectangle(String ln1, String ln2, boolean small) { + display.clear(); + display.setTextAlignment(TEXT_ALIGN_LEFT); + if (small) { + display.setFont(ArialMT_Plain_16); + } else { + display.setFont(ArialMT_Plain_24); + } + display.drawString(32, 16, ln1); + display.drawString(32, 36, ln2); + display.display(); +} + +void updateScreen(long now) { + static long lastDisplayUpdate = millis(); + static uint8_t state = 0; + + if ((now - lastUpdate) > updateFrequency) { + // Take a measurement at a fixed interval. + update(); + } + + switch (state) { + case 0: +#ifdef SET_PMS + showTextRectangle("PM2", String(value_pm), false); + break; +#else + state = 1; +#endif // SET_PMS + case 1: +#ifdef SET_CO2_S8 + showTextRectangle("CO2", String(value_co2), false); + break; +#else + state = 2; +#endif // SET_CO2_S8 + case 2: +#ifdef SET_SHT + if (temp_display == 'F' || temp_display == 'f') { + showTextRectangle("TMP", String((value_sht.t * 9 / 5) + 32, 1) + "F", false); + } else { + showTextRectangle("TMP", String(value_sht.t, 1) + "C", false); + } + break; + case 3: + showTextRectangle("HUM", String(value_sht.rh) + "%", false); +#else + state = 1; +#endif // SET_SHT + break; + } + if ((now - lastDisplayUpdate) > displayTime) { + state = (state + 1) % 4; + lastDisplayUpdate = millis(); + } +} +#endif // SET_DISPLAY \ No newline at end of file From fd5a446fb0c3f92cc8d425133c8f9b99ac11c201 Mon Sep 17 00:00:00 2001 From: Vagif Veliev Date: Sun, 16 Oct 2022 00:36:30 -0400 Subject: [PATCH 2/3] refactor: removing compex examples --- .../C02_PM1_PM2_PM10_SHT_OLED_WIFI.ino | 336 ------------------ .../CO_PM_SHT_OLED_PROMETHEUS.ino | 164 --------- 2 files changed, 500 deletions(-) delete mode 100644 examples/CO2_PM1_PM2_PM10_OLED_WIFI/C02_PM1_PM2_PM10_SHT_OLED_WIFI.ino delete mode 100644 examples/CO_PM_SHT_OLED_PROMETHEUS/CO_PM_SHT_OLED_PROMETHEUS.ino diff --git a/examples/CO2_PM1_PM2_PM10_OLED_WIFI/C02_PM1_PM2_PM10_SHT_OLED_WIFI.ino b/examples/CO2_PM1_PM2_PM10_OLED_WIFI/C02_PM1_PM2_PM10_SHT_OLED_WIFI.ino deleted file mode 100644 index 6059fccc..00000000 --- a/examples/CO2_PM1_PM2_PM10_OLED_WIFI/C02_PM1_PM2_PM10_SHT_OLED_WIFI.ino +++ /dev/null @@ -1,336 +0,0 @@ -/** - * This sketch connects an AirGradient DIY sensor to a WiFi network, and runs a - * tiny HTTP server to serve air quality metrics to Prometheus. - */ - -/* - PM1 and PM10 reporting for Plantower PMS5003 PM2.5 sensor enabled. - Workaround for glitchy CO2 and PM sensors reporting included. - For using this .ino you have to install improved AirGradient libraries, which supports PM1 and PM10 reporting: - https://github.com/d3vilh/airgradient-improved -*/ - - -#include -#include -#include -#include - -#include -#include "SSD1306Wire.h" - -AirGradient ag = AirGradient(); - -// Config ---------------------------------------------------------------------- - -// Optional. -const char* deviceId = "livingroom"; - -// set to 'F' to switch display from Celcius to Fahrenheit -char temp_display = 'C'; - -// Hardware options for AirGradient DIY sensor. -const bool hasPM1 = true; -const bool hasPM2 = true; -const bool hasPM10 = true; -const bool hasCO2 = true; -const bool hasSHT = true; - -// WiFi and IP connection info. -const char* ssid = "NETCOM VIKTOR"; -const char* password = "58879016"; -const int port = 9926; - -// Uncomment the line below to configure a static IP address. -// #define staticip -#ifdef staticip -IPAddress static_ip(192, 168, 88, 100); -IPAddress gateway(192, 168, 88, 249); -IPAddress subnet(255, 255, 255, 0); -#endif - -// The frequency of measurement updates. -const int updateFrequency = 5000; - -// For housekeeping. -long lastUpdate; -int counter = 0; -int stat_prev_pm1 = 0; -int stat_prev_pm2 = 0; -int stat_prev_pm10 = 0; -int stat_prev_co = 0; - - -// Config End ------------------------------------------------------------------ - -SSD1306Wire display(0x3c, SDA, SCL); -ESP8266WebServer server(port); - -void setup() { - Serial.begin(9600); - - // Init Display. - display.init(); - display.flipScreenVertically(); - showTextRectangle("Init", String(ESP.getChipId(),HEX),true); - - // Enable enabled sensors. - if (hasPM1) ag.PMS_Init(); - if (hasCO2) ag.CO2_Init(); - if (hasSHT) ag.TMP_RH_Init(0x44); - - // Set static IP address if configured. - #ifdef staticip - WiFi.config(static_ip,gateway,subnet); - #endif - - // Set WiFi mode to client (without this it may try to act as an AP). - WiFi.mode(WIFI_STA); - - // Configure Hostname - if ((deviceId != NULL) && (deviceId[0] == '\0')) { - Serial.printf("No Device ID is Defined, Defaulting to board defaults"); - } - else { - wifi_station_set_hostname(deviceId); - WiFi.setHostname(deviceId); - } - - // Setup and wait for WiFi. - WiFi.begin(ssid, password); - Serial.println(""); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - showTextRectangle("Trying to", "connect...", true); - Serial.print("."); - } - - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - Serial.print("MAC address: "); - Serial.println(WiFi.macAddress()); - Serial.print("Hostname: "); - Serial.println(WiFi.hostname()); - server.on("/", HandleRoot); - server.on("/metrics", HandleRoot); - server.onNotFound(HandleNotFound); - - server.begin(); - Serial.println("HTTP server started at ip " + WiFi.localIP().toString() + ":" + String(port)); - showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port),true); -} - -void loop() { - long t = millis(); - - server.handleClient(); - updateScreen(t); -} - -String GenerateMetrics() { - String message = ""; - String idString = "{id=\"" + String(deviceId) + "\",mac=\"" + WiFi.macAddress().c_str() + "\"}"; - - if (hasPM1) { - int statf_pm1 = 0; - int stat = ag.getPM1_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm1 = stat; - stat_prev_pm1 = statf_pm1; // saving not glitchy value - } else { - statf_pm1 = stat_prev_pm1; // using previous not glitchy value if curent value is glitchy - } - message += "# HELP pm01 Particulate Matter PM1 value\n"; - message += "# TYPE pm01 gauge\n"; - message += "pm01"; - message += idString; - message += String(statf_pm1); - message += "\n"; - } - - if (hasPM2) { - int statf_pm2 = 0; - int stat = ag.getPM2_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm2 = stat; - stat_prev_pm2 = statf_pm2; // saving not glitchy value - } else { - statf_pm2 = stat_prev_pm2; // using previous not glitchy value if curent value is glitchy - } - message += "# HELP pm02 Particulate Matter PM2.5 value\n"; - message += "# TYPE pm02 gauge\n"; - message += "pm02"; - message += idString; - message += String(statf_pm2); - message += "\n"; - } - - if (hasPM10) { - int statf_pm10 = 0; - int stat = ag.getPM10_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm10 = stat; - stat_prev_pm10 = statf_pm10; // saving not glitchy value - } else { - statf_pm10 = stat_prev_pm10; // using previous not glitchy value if curent value is glitchy - } - message += "# HELP pm10 Particulate Matter PM10 value\n"; - message += "# TYPE pm10 gauge\n"; - message += "pm10"; - message += idString; - message += String(statf_pm10); - message += "\n"; - } - - if (hasCO2) { - int statf_co = 0; - int stat = ag.getCO2_Raw(); - if (stat >= 0 && stat <= 10000) { - statf_co = stat; - stat_prev_co = statf_co; // saving not glitchy value - } else { - statf_co = stat_prev_co; // using previous not glitchy value if curent value is glitchy - } - message += "# HELP rco2 CO2 value, in ppm\n"; - message += "# TYPE rco2 gauge\n"; - message += "rco2"; - message += idString; - message += String(statf_co); - message += "\n"; - } - - if (hasSHT) { - TMP_RH stat = ag.periodicFetchData(); - message += "# HELP atmp Temperature, in degrees Celsius\n"; - message += "# TYPE atmp gauge\n"; - message += "atmp"; - message += idString; - // Dirty Temp adjust (-3 degrees) - message += String(stat.t - 3); - message += "\n"; - - message += "# HELP rhum Relative humidity, in percent\n"; - message += "# TYPE rhum gauge\n"; - message += "rhum"; - message += idString; - message += String(stat.rh); - message += "\n"; - } - - return message; -} - -void HandleRoot() { - server.send(200, "text/plain", GenerateMetrics() ); -} - -void HandleNotFound() { - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; - message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; - for (uint i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; - } - server.send(404, "text/html", message); -} - -// DISPLAY -void showTextRectangle(String ln1, String ln2, boolean small) { - display.clear(); - display.setTextAlignment(TEXT_ALIGN_LEFT); - if (small) { - display.setFont(ArialMT_Plain_16); - } else { - display.setFont(ArialMT_Plain_24); - } - display.drawString(32, 16, ln1); - display.drawString(32, 36, ln2); - display.display(); -} - -void updateScreen(long now) { - if ((now - lastUpdate) > updateFrequency) { - // Take a measurement at a fixed interval. - switch (counter) { - case 0: - if (hasPM1) { - int statf_pm1 = 0; - int stat = ag.getPM1_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm1 = stat; - stat_prev_pm1 = statf_pm1; // saving not glitchy value - } else { - statf_pm1 = stat_prev_pm1; // using previous not glitchy value if curent value is glitchy - } - showTextRectangle("PM1",String(statf_pm1),false); - } - break; - case 1: - if (hasPM2) { - int statf_pm2 = 0; - int stat = ag.getPM2_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm2 = stat; - stat_prev_pm2 = statf_pm2; // saving not glitchy value - } else { - statf_pm2 = stat_prev_pm2; // using previous not glitchy value if curent value is glitchy - } - showTextRectangle("PM2",String(statf_pm2),false); - } - break; - case 2: - if (hasPM10) { - int statf_pm10 = 0; - int stat = ag.getPM10_Raw(); - if (stat > 0 && stat <= 10000) { - statf_pm10 = stat; - stat_prev_pm10 = statf_pm10; // saving not glitchy value - } else { - statf_pm10 = stat_prev_pm10; // using previous not glitchy value if curent value is glitchy - } - showTextRectangle("PM10",String(statf_pm10),false); - } - break; - case 3: - if (hasCO2) { - int statf_co = 0; - int stat = ag.getCO2_Raw(); - if (stat >= 0 && stat <= 10000) { - statf_co = stat; - stat_prev_co = statf_co; // saving not glitchy value - } else { - statf_co = stat_prev_co; // using previous not glitchy value if curent value is glitchy - } - showTextRectangle("CO2", String(statf_co), false); - } - break; - case 4: - if (hasSHT) { - TMP_RH stat = ag.periodicFetchData(); - if (temp_display == 'F' || temp_display == 'f') { - showTextRectangle("TMP", String((stat.t * 9 / 5) + 32, 1) + "F", false); - } else { - showTextRectangle("TMP", String(stat.t - 3, 1) + "C", false); - } - } - break; - case 5: - if (hasSHT) { - TMP_RH stat = ag.periodicFetchData(); - showTextRectangle("HUM", String(stat.rh) + "%", false); - } - break; - } - counter++; - if (counter > 5) counter = 0; - lastUpdate = millis(); - } -} diff --git a/examples/CO_PM_SHT_OLED_PROMETHEUS/CO_PM_SHT_OLED_PROMETHEUS.ino b/examples/CO_PM_SHT_OLED_PROMETHEUS/CO_PM_SHT_OLED_PROMETHEUS.ino deleted file mode 100644 index ebd2b071..00000000 --- a/examples/CO_PM_SHT_OLED_PROMETHEUS/CO_PM_SHT_OLED_PROMETHEUS.ino +++ /dev/null @@ -1,164 +0,0 @@ -/** - * This sketch connects an AirGradient DIY sensor to a WiFi network, and runs a - * tiny HTTP server to serve air quality metrics to Prometheus. - */ - -#include "main.h" -#include -#include - -#include -#include "SSD1306Wire.h" - -#include - -// Config ---------------------------------------------------------------------- - -//screen refresh -const int screenUpdateFrequencyMs = 5000; - -//Id of the device for Prometheus -const char * deviceId = ""; - -//Wifi information -const char* ssid = ""; -const char* password = ""; -const uint16_t port = 9925; - -#ifdef staticip -IPAddress static_ip(192, 168, 42, 20); -IPAddress gateway(192, 168, 42, 1); -IPAddress subnet(255, 255, 255, 0); -#endif - -const char* ntp_server = "pool.ntp.org"; - -// For housekeeping. -uint8_t counter = 0; - -// Config End ------------------------------------------------------------------ - -SSD1306Wire display(0x3c, SDA, SCL); - -auto metrics = std::make_shared(); -auto aqiCalculator = std::make_shared(metrics); -auto server = std::make_unique(port, deviceId, metrics, aqiCalculator); -Ticker updateScreenTicker; - - -void setup() { - Serial.begin(9600); - - metrics->addSensor(std::make_unique()) - .addSensor(std::make_unique()) - .addSensor(std::make_unique()) - .addSensor(std::make_unique(ntp_server)); - - // Init Display. - display.init(); - display.flipScreenVertically(); - showTextRectangle("Init", String(EspClass::getChipId(), HEX), true); - - // Set static IP address if configured. -#ifdef staticip - WiFi.config(static_ip, gateway, subnet); -#endif - - // Set WiFi mode to client (without this it may try to act as an AP). - WiFi.mode(WIFI_STA); - - // Configure Hostname - if ((deviceId != NULL) && (deviceId[0] == '\0')) { - Serial.printf("No Device ID is Defined, Defaulting to board defaults"); - } else { - wifi_station_set_hostname(deviceId); - WiFi.setHostname(deviceId); - } - - // Setup and wait for WiFi. - WiFi.begin(ssid, password); - Serial.println(""); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - showTextRectangle("Trying to", "connect...", true); - Serial.print("."); - } - - Serial.println(""); - Serial.print("Connected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - Serial.print("MAC address: "); - Serial.println(WiFi.macAddress()); - Serial.print("Hostname: "); - Serial.println(WiFi.hostname()); - - metrics->begin(); - aqiCalculator->begin(); - - server->begin(); - - showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port), true); - updateScreenTicker.attach_ms_scheduled(screenUpdateFrequencyMs, updateScreen); -} - -void loop() { - server->handleRequests(); -} - -// DISPLAY -void showTextRectangle(const String &ln1, const String &ln2, boolean small) { - display.clear(); - display.setTextAlignment(TEXT_ALIGN_LEFT); - if (small) { - display.setFont(ArialMT_Plain_16); - } else { - display.setFont(ArialMT_Plain_24); - } - display.drawString(32, 16, ln1); - display.drawString(32, 36, ln2); - display.display(); -} - -void updateScreen() { - auto data = metrics->getData(); - auto sensorType = metrics->getMeasurements(); - // Take a measurement at a fixed interval. - switch (counter) { - - case 0: - if (!(sensorType & Measurement::Particle)) { - showTextRectangle("PM2", String(data.PARTICLE_DATA.PM_2_5), false); - break; - } - - case 1: - if (!(sensorType & Measurement::CO2)) { - showTextRectangle("CO2", String(data.GAS_DATA.CO2), false); - break; - } - - case 2: - if (!(sensorType & Measurement::Temperature)) { - showTextRectangle("TMP", String(data.TMP, 1) + "C", false); - break; - } - - case 3: - if (!(sensorType & Measurement::Humidity)) { - showTextRectangle("HUM", String(data.HUM, 1) + "%", false); - break; - } - - case 4: - if (!(sensorType & Measurement::Particle)) { - auto aqi = aqiCalculator->isAQIAvailable() ? String(aqiCalculator->getAQI(), 1) : "N/A"; - showTextRectangle("AQI", aqi, false); - break; - } - - } - - counter = ++counter % 5; -} \ No newline at end of file From 67b3d31a4bb7dd3c24881332c7d455fad7fdfedc Mon Sep 17 00:00:00 2001 From: Vagif Veliev Date: Sun, 16 Oct 2022 01:40:18 -0400 Subject: [PATCH 3/3] refactor: updating prometheus example --- .../DIY_BASIC_PROMETHEUS.ino | 93 +++-- examples/MINI_DISPLAY/MINI_DISPLAY.ino | 380 ------------------ platformio.ini | 3 +- 3 files changed, 58 insertions(+), 418 deletions(-) delete mode 100644 examples/MINI_DISPLAY/MINI_DISPLAY.ino diff --git a/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino b/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino index 04001b31..5d3d24c4 100644 --- a/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino +++ b/examples/DIY_BASIC_PROMETHEUS/DIY_BASIC_PROMETHEUS.ino @@ -10,6 +10,10 @@ #include #include "SSD1306Wire.h" + +using namespace AirGradient; + + // Config ---------------------------------------------------------------------- // Optional. @@ -24,7 +28,7 @@ const char temp_display = 'C'; // #define SET_CO2_S8 #define SET_CO2_MH_Z19 // #define SET_SHT -// #define +// #define SET_SGP30 //#define SET_DISPLAY @@ -43,9 +47,10 @@ IPAddress subnet(255, 255, 255, 0); #ifdef SET_DISPLAY +SSD1306Wire display(0x3c, SDA, SCL); + // The frequency of measurement updates. -const int updateFrequency = 5000; -const int displayTime = 5000; +const uint16_t screenUpdateFrequencyMs = 5000; #endif // SET_DISPLAY // Config End ------------------------------------------------------------------ @@ -54,6 +59,17 @@ const int displayTime = 5000; #define ERROR_SHT 0x02 #define ERROR_CO2 0x04 + +auto metrics = std::make_shared(); + +uint8_t counter = 0; + +auto metrics = std::make_shared(); +// auto aqiCalculator = std::make_unique(metrics); +Ticker updateScreenTicker; +Ticker sendPayloadTicker; + + AirGradient ag = AirGradient(); TMP_RH value_sht; @@ -75,19 +91,48 @@ void setup() { display.init(); display.flipScreenVertically(); showTextRectangle("Init", String(ESP.getChipId(), HEX), true); -#endif // SET_DISPLAY +#endif #ifdef SET_PMS - ag.PMS_Init(); + metrics->addSensor(std::make_unique()); #endif #ifdef SET_CO2_S8 - ag.CO2_Init(); -#endif // SET_CO2_S8 + metrics->addSensor(std::make_unique()); +#endif #ifdef SET_CO2_MH_Z19 - ag.MHZ19_Init(19); -#endif // SET_CO2_MH_Z19 + metrics->addSensor(std::make_unique()); +#endif #ifdef SET_SHT - ag.TMP_RH_Init(0x44); -#endif // SET_SHT + metrics->addSensor(std::make_unique()); +#endif +#ifdef SET_SGP30 + metrics->addSensor(std::make_unique()); +#endif + + connectToWifi(); + + metrics->begin(); +#ifdef SET_DISPLAY + aqiCalculator->begin(); +#endif + updateScreenTicker.attach_ms_scheduled(screenUpdateFrequencyMs, updateScreen); + + sendPayloadTicker.attach_scheduled(20, sendPayload); + +#ifdef SET_DISPLAY + showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port), true); +#endif // SET_DISPLAY +} + +void loop() { + server.handleClient(); +#ifdef SET_DISPLAY + updateScreen(millis()); +#endif // SET_DISPLAY +} + + +// Wifi Manager +void connectToWifi() { // Set static IP address if configured. #ifdef staticip @@ -113,35 +158,9 @@ void setup() { delay(500); #ifdef SET_DISPLAY showTextRectangle("Trying to", "connect...", true); -#endif // SET_DISPLAY - Serial.print("."); - } - - Serial.print("\nConnected to "); - Serial.println(ssid); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); - Serial.print("MAC address: "); - Serial.println(WiFi.macAddress()); - Serial.print("Hostname: "); - Serial.println(WiFi.hostname()); - server.on("/", HandleRoot); - server.on("/metrics", HandleRoot); - server.onNotFound(HandleNotFound); - - server.begin(); - Serial.println("HTTP server started at ip " + WiFi.localIP().toString() + ":" + String(port)); -#ifdef SET_DISPLAY - showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port), true); #endif // SET_DISPLAY } -void loop() { - server.handleClient(); -#ifdef SET_DISPLAY - updateScreen(millis()); -#endif // SET_DISPLAY -} uint8_t update() { uint8_t result = 0; diff --git a/examples/MINI_DISPLAY/MINI_DISPLAY.ino b/examples/MINI_DISPLAY/MINI_DISPLAY.ino deleted file mode 100644 index 130984e6..00000000 --- a/examples/MINI_DISPLAY/MINI_DISPLAY.ino +++ /dev/null @@ -1,380 +0,0 @@ -/* -This is the code for the AirGradient DIY Mini Display with an ESP8266 Microcontroller. -It can be configures to show the outside air quality as well as one indoor location from the AirGradient platform. - -For build instructions please visit - -https://www.airgradient.com/open-airgradient/blog/airgradient-diy-display/ - -The codes needs the following libraries installed: -"WifiManager by tzapu, tablatronix" tested with Version 2.0.5-alpha -"Adafruit_ILI9341" tested with Version 1.5.10 -"Adafruit GFX library" tested with Version 1.10.12 (often automatically installed with above ILI9341 library) -"ArduinoJSON" by Benoit Blanchon tested with Version 6.18.5 - -Configuration: -Please set in the code below (line 90-) if you want to display the PM2.5 values in US AQI and temperature in F. - -If you have any questions please visit our forum at https://forum.airgradient.com/ - - -If you are a school or university contact us for a free trial on the AirGradient platform. -https://www.airgradient.com/ - -MIT License -*/ - -#include - -#include - -#include - -#include - -#include - -#include - -#include - -#include - -#include - -#define TFT_CS D0 -#define TFT_DC D8 -#define TFT_RST - 1 -#define TS_CS D3 - -Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); - -const char * locNameInside; -const char * locNameOutside; - -const char * place_timezone; -const char * location; -bool outdoor_offline; -bool indoor_offline; -const char * outdoor_policy; -const char * outdoor_date; -const char * indoor_date; -boolean prodMode = true; - -String deviceID; -const char * timex; -int pm02; -int pi02; -int pi02_outside; -int rco2; -float atmp; -float atmp_outside; -int rhum_outside; -int rhum; -int heat; - -const char * pi02_color; -const char * pi02_color_outside; -const char * pi02_category; -const char * pm02_color; -const char * pm02_category; -const char * rco2_color; -const char * rco2_category; -const char * heat_color; -const char * heat_color_outside; -const char * heat_category; - -// Configuration -#define API_ROOT "http://hw.airgradient.com/displays/" -boolean inUSaqi = false; -boolean inF = false; - -String getDeviceId() { - return String(ESP.getChipId(), HEX); -} - -void setup() { - Serial.begin(115200); - Serial.println("Chip ID"); - Serial.println(String(ESP.getChipId(), HEX)); - - tft.begin(); - tft.setRotation(2); - while (!Serial && (millis() <= 1000)); - welcomeMessage(); - connectToWifi(); - - Serial.print("Connecting"); - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println(); - - tft.fillScreen(ILI9341_BLACK); - delay(2000); -} - -void loop() { - - WiFiClient client; - HTTPClient http; - http.begin(client, API_ROOT + getDeviceId()); - - int httpCode = http.GET(); - if (httpCode == 200) { - String airData = http.getString(); - payloadToDataInside(airData); - Serial.print("airData1 : "); - Serial.println(airData); - } else { - Serial.println("error"); - Serial.println(httpCode); - } - http.end(); - - delay(1000); - updateDisplay(); - - delay(120000); - tft.fillScreen(ILI9341_BLACK); - tft.setTextColor(ILI9341_WHITE); - tft.setFont( & FreeSans12pt7b); - tft.setCursor(5, 20); - tft.println("requesting data..."); -} - -void payloadToDataInside(String payload) { - const size_t capacity = JSON_ARRAY_SIZE(1) + 2 * JSON_OBJECT_SIZE(2) + 2 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(10) + JSON_OBJECT_SIZE(13) + 530; - DynamicJsonBuffer jsonBuffer(capacity); - JsonObject & root = jsonBuffer.parseObject(payload); - location = root["place"]["name"]; - place_timezone = root["place"]["timezone"]; - JsonObject & outdoor = root["outdoor"]; - locNameOutside = outdoor["name"]; - outdoor_offline = outdoor["offline"]; - outdoor_policy = outdoor["guidelines"][0]["title"]; - JsonObject & outdoor_current = outdoor["current"]; - - atmp_outside = outdoor_current["atmp"]; - rhum_outside = outdoor_current["rhum"]; - outdoor_date = outdoor_current["date"]; - JsonObject & indoor = root["indoor"]; - locNameInside = indoor["name"]; - indoor_offline = indoor["offline"]; - JsonObject & indoor_current = indoor["current"]; - - atmp = indoor_current["atmp"]; - rhum = indoor_current["rhum"]; - rco2 = indoor_current["rco2"]; - indoor_date = indoor_current["date"]; - rco2_color = indoor_current["rco2_clr"]; - rco2_category = indoor_current["rco2_lbl"]; - - if (inUSaqi) { - pi02_outside = outdoor_current["pi02"]; - pi02_color_outside = outdoor_current["pi02_clr"]; - pi02_category = outdoor_current["pi02_lbl"]; - pi02 = indoor_current["pi02"]; - pi02_color = indoor_current["pi02_clr"]; - pi02_category = indoor_current["pi02_lbl"]; - } else { - pi02_outside = outdoor_current["pm02"]; - pi02_color_outside = outdoor_current["pm02_clr"]; - pi02_category = outdoor_current["pm02_lbl"]; - pi02 = indoor_current["pm02"]; - pi02_color = indoor_current["pm02_clr"]; - pi02_category = indoor_current["pm02_lbl"]; - } - -} - -void updateDisplay() { - int y = 25; - int boxHeight = 75; - int boxWidth = 110; - int radius = 8; - tft.fillScreen(ILI9341_BLACK); - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); - tft.setCursor(5, y); - tft.println(location); - - tft.drawLine(0, 35, 250, 35, ILI9341_WHITE); - - y = y + 50; - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); - tft.setCursor(5, y); - tft.println(locNameOutside); - tft.setFont( & FreeSans12pt7b); - - y = y + 12; - - if (String(pi02_color_outside) == "green") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_GREEN); - } else if (String(pi02_color_outside) == "yellow") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_YELLOW); - } else if (String(pi02_color_outside) == "orange") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_ORANGE); - } else if (String(pi02_color_outside) == "red") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_RED); - } else if (String(pi02_color_outside) == "purple") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_PURPLE); - } else if (String(pi02_color_outside) == "brown") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_MAROON); - } - - if (String(heat_color_outside) == "green") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_GREEN); - } else if (String(heat_color_outside) == "yellow") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_YELLOW); - } else if (String(heat_color_outside) == "orange") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_ORANGE); - } else if (String(heat_color_outside) == "red") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_RED); - } else if (String(heat_color_outside) == "purple") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_PURPLE); - } else if (String(heat_color_outside) == "brown") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_MAROON); - } - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK); - tft.setCursor(20, y + boxHeight - 10); - - if (inUSaqi) { - tft.println("US AQI"); - } else { - tft.println("ug/m3"); - } - - tft.setFont( & FreeSans18pt7b); - tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK); - tft.setCursor(20, y + 40); - tft.println(String(pi02_outside)); - - tft.setFont( & FreeSans9pt7b); - - tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); - - tft.setCursor(20 + boxWidth + 10, y + 20); - - if (inF) { - tft.println(String((atmp_outside * 9 / 5) + 32) + "F"); - } else { - tft.println(String(atmp_outside) + "C"); - } - - tft.setCursor(20 + boxWidth + 10, y + 40); - tft.println(String(rhum_outside) + "%"); - - tft.setTextColor(ILI9341_DARKGREY, ILI9341_BLACK); - tft.setCursor(20 + boxWidth + 10, y + 60); - tft.println(String(outdoor_date)); - - //inside - - y = y + 110; - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); - tft.setCursor(5, y); - tft.println(locNameInside); - tft.setFont( & FreeSans12pt7b); - - y = y + 12; - - if (String(pi02_color) == "green") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_GREEN); - } else if (String(pi02_color) == "yellow") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_YELLOW); - } else if (String(pi02_color) == "orange") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_ORANGE); - } else if (String(pi02_color) == "red") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_RED); - } else if (String(pi02_color) == "purple") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_PURPLE); - } else if (String(pi02_color) == "brown") { - tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_MAROON); - } - - if (String(rco2_color) == "green") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_GREEN); - } else if (String(rco2_color) == "yellow") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_YELLOW); - } else if (String(rco2_color) == "orange") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_ORANGE); - } else if (String(rco2_color) == "red") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_RED); - } else if (String(rco2_color) == "purple") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_PURPLE); - } else if (String(rco2_color) == "brown") { - tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_MAROON); - } - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK); - tft.setCursor(20, y + boxHeight - 10); - - if (inUSaqi) { - tft.println("US AQI"); - } else { - tft.println("ug/m3"); - } - - tft.setCursor(20 + boxWidth + 10, y + boxHeight - 10); - tft.println("CO2 ppm"); - - tft.setFont( & FreeSans18pt7b); - tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK); - tft.setCursor(20, y + 40); - tft.println(String(pi02)); - tft.setCursor(20 + boxWidth + 10, y + 40); - tft.println(String(rco2)); - - y = y + 100; - - tft.setFont( & FreeSans9pt7b); - tft.setTextColor(ILI9341_DARKGREY, ILI9341_BLACK); - tft.setCursor(boxWidth - 30, y); - tft.println(String(indoor_date)); -} - -void welcomeMessage() { - Serial.println("Welcome Message 2"); - tft.setFont( & FreeSans9pt7b); - tft.fillScreen(ILI9341_BLACK); - tft.setTextColor(ILI9341_WHITE); - - tft.setCursor(40, 24); - tft.setFont( & FreeSans12pt7b); - tft.setCursor(5, 20); - tft.println("AirGradient"); - - tft.setFont( & FreeSans9pt7b); - tft.setCursor(5, 100); - tft.println("id: " + String(ESP.getChipId(), HEX)); - - tft.setCursor(5, 140); - tft.println("connecting ..."); - - delay(2000); -} - -void connectToWifi() { - delay(2000); - - WiFiManager wifiManager; - //chWiFi.disconnect(); //to delete previous saved hotspot - String HOTSPOT = "AIRGRADIENT-DISPLAY-" + String(ESP.getChipId(), HEX); - wifiManager.setTimeout(120); - if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) { - Serial.println("failed to connect and hit timeout"); - delay(3000); - ESP.restart(); - delay(5000); - } -} diff --git a/platformio.ini b/platformio.ini index eb095624..8794148c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,4 +21,5 @@ lib_deps = sensirion/arduino-sht@^1.2.1 jcomas/S8_UART@^1.0.1 SparkFun SGP30 Arduino Library@^1.0.5 - MH-Z19@^1.5.3 \ No newline at end of file + MH-Z19@^1.5.3 + adafruit/Adafruit_BME280_Library@^2.2.2 \ No newline at end of file