diff --git a/examples/C02_PM_SHT_OLED_WIFI/C02_PM_SHT_OLED_WIFI.ino b/examples/C02_PM_SHT_OLED_WIFI/C02_PM_SHT_OLED_WIFI.ino index 53d6b5ec..b2b6fbfa 100644 --- a/examples/C02_PM_SHT_OLED_WIFI/C02_PM_SHT_OLED_WIFI.ino +++ b/examples/C02_PM_SHT_OLED_WIFI/C02_PM_SHT_OLED_WIFI.ino @@ -16,48 +16,59 @@ The codes needs the following libraries installed: "WifiManager by tzapu, tablatronix" tested with Version 2.0.3-alpha "ESP8266 and ESP32 OLED driver for SSD1306 displays by ThingPulse, Fabrice Weinberg" tested with Version 4.1.0 +If you have any questions please visit our forum at https://forum.airgradient.com/ + Configuration: Please set in the code below which sensor you are using and if you want to connect it to WiFi. +You can also switch PM2.5 from ug/m3 to US AQI and Celcius to Fahrenheit If you are a school or university contact us for a free trial on the AirGradient platform. https://www.airgradient.com/schools/ -Ready made kits with all required components are available at https://www.airgradient.com/diyshop/ +Kits with all required components are available at https://www.airgradient.com/diyshop/ MIT License */ #include + #include + #include + #include #include + #include "SSD1306Wire.h" AirGradient ag = AirGradient(); SSD1306Wire display(0x3c, SDA, SCL); -WiFiClient client; - // set sensors that you do not use to false -boolean hasPM=true; -boolean hasCO2=true; -boolean hasSHT=true; +boolean hasPM = true; +boolean hasCO2 = true; +boolean hasSHT = true; + +// set to true to switch PM2.5 from ug/m3 to US AQI +boolean inUSaqi = false; + +// set to true to switch from Celcius to Fahrenheit +boolean inF = false; // set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection -boolean connectWIFI=false; +boolean connectWIFI = false; // change if you want to send the data to another server String APIROOT = "http://hw.airgradient.com/"; -void setup(){ +void setup() { Serial.begin(9600); display.init(); display.flipScreenVertically(); - showTextRectangle("Init", String(ESP.getChipId(),HEX),true); + showTextRectangle("Init", String(ESP.getChipId(), HEX), true); if (hasPM) ag.PMS_Init(); if (hasCO2) ag.CO2_Init(); @@ -67,7 +78,7 @@ void setup(){ delay(2000); } -void loop(){ +void loop() { // create payload @@ -75,43 +86,56 @@ void loop(){ if (hasPM) { int PM2 = ag.getPM2_Raw(); - payload=payload+"\"pm02\":" + String(PM2); - showTextRectangle("PM2",String(PM2),false); + payload = payload + "\"pm02\":" + String(PM2); + + if (inUSaqi) { + showTextRectangle("AQI", String(PM_TO_AQI_US(PM2)), false); + } else { + showTextRectangle("PM2", String(PM2), false); + } + delay(3000); + } if (hasCO2) { - if (hasPM) payload=payload+","; + if (hasPM) payload = payload + ","; int CO2 = ag.getCO2_Raw(); - payload=payload+"\"rco2\":" + String(CO2); - showTextRectangle("CO2",String(CO2),false); + payload = payload + "\"rco2\":" + String(CO2); + showTextRectangle("CO2", String(CO2), false); delay(3000); } if (hasSHT) { - if (hasCO2 || hasPM) payload=payload+","; + if (hasCO2 || hasPM) payload = payload + ","; TMP_RH result = ag.periodicFetchData(); - payload=payload+"\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh); - showTextRectangle(String(result.t),String(result.rh)+"%",false); + payload = payload + "\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh); + + if (inF) { + showTextRectangle(String((result.t * 9 / 5) + 32), String(result.rh) + "%", false); + } else { + showTextRectangle(String(result.t), String(result.rh) + "%", false); + } + delay(3000); } - payload=payload+"}"; + payload = payload + "}"; // send payload - if (connectWIFI){ - Serial.println(payload); - String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(),HEX) + "/measures"; - Serial.println(POSTURL); - WiFiClient client; - HTTPClient http; - http.begin(client, POSTURL); - http.addHeader("content-type", "application/json"); - int httpCode = http.POST(payload); - String response = http.getString(); - Serial.println(httpCode); - Serial.println(response); - http.end(); + if (connectWIFI) { + Serial.println(payload); + String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "/measures"; + Serial.println(POSTURL); + WiFiClient client; + HTTPClient http; + http.begin(client, POSTURL); + http.addHeader("content-type", "application/json"); + int httpCode = http.POST(payload); + String response = http.getString(); + Serial.println(httpCode); + Serial.println(response); + http.end(); } } @@ -130,16 +154,28 @@ void showTextRectangle(String ln1, String ln2, boolean small) { } // Wifi Manager -void connectToWifi(){ +void connectToWifi() { WiFiManager wifiManager; //WiFi.disconnect(); //to delete previous saved hotspot - String HOTSPOT = "AIRGRADIENT-"+String(ESP.getChipId(),HEX); + String HOTSPOT = "AIRGRADIENT-" + 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); + if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) { + Serial.println("failed to connect and hit timeout"); + delay(3000); + ESP.restart(); + delay(5000); } } + +// Calculate PM2.5 US AQI +int PM_TO_AQI_US(int pm02) { + if (pm02 <= 12.0) return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0); + else if (pm02 <= 35.4) return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50); + else if (pm02 <= 55.4) return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100); + else if (pm02 <= 150.4) return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150); + else if (pm02 <= 250.4) return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200); + else if (pm02 <= 350.4) return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300); + else if (pm02 <= 500.4) return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400); + else return 500; +}; diff --git a/examples/C02_SIMPLE/C02_SIMPLE.ino b/examples/C02_SIMPLE/C02_SIMPLE.ino index d4822e12..027662f4 100644 --- a/examples/C02_SIMPLE/C02_SIMPLE.ino +++ b/examples/C02_SIMPLE/C02_SIMPLE.ino @@ -10,9 +10,13 @@ SenseAir S8 (CO2 Sensor) Please install ESP8266 board manager (tested with version 3.0.0) +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/schools/ +Kits with all required components are available at https://www.airgradient.com/diyshop/ + MIT License */ diff --git a/examples/MINI_DISPLAY/MINI_DISPLAY.ino b/examples/MINI_DISPLAY/MINI_DISPLAY.ino new file mode 100644 index 00000000..f1b067bd --- /dev/null +++ b/examples/MINI_DISPLAY/MINI_DISPLAY.ino @@ -0,0 +1,381 @@ +/* +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/resources/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/schools/ + +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/examples/PM2_SIMPLE/PM2_SIMPLE.ino b/examples/PM2_SIMPLE/PM2_SIMPLE.ino index 18fdf390..990dbdb8 100644 --- a/examples/PM2_SIMPLE/PM2_SIMPLE.ino +++ b/examples/PM2_SIMPLE/PM2_SIMPLE.ino @@ -10,25 +10,45 @@ Plantower PMS5003 (Fine Particle Sensor) Please install ESP8266 board manager (tested with version 3.0.0) +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/schools/ +Kits with all required components are available at https://www.airgradient.com/diyshop/ + MIT License */ #include + AirGradient ag = AirGradient(); -void setup(){ +void setup() { Serial.begin(9600); ag.PMS_Init(); } -void loop(){ - -int PM2 = ag.getPM2_Raw(); -Serial.print("PM2: "); -Serial.println(ag.getPM2()); +void loop() { + + int PM2 = ag.getPM2_Raw(); -delay(5000); + Serial.print("PM2.5 in ug/m3: "); + Serial.println(String(PM2)); + + Serial.print("PM2.5 in US AQI: "); + Serial.println(String(PM_TO_AQI_US(PM2))); + + delay(5000); } + +int PM_TO_AQI_US(int pm02) { + if (pm02 <= 12.0) return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0); + else if (pm02 <= 35.4) return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50); + else if (pm02 <= 55.4) return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100); + else if (pm02 <= 150.4) return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150); + else if (pm02 <= 250.4) return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200); + else if (pm02 <= 350.4) return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300); + else if (pm02 <= 500.4) return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400); + else return 500; +}; diff --git a/examples/SHT_SIMPLE/SHT_SIMPLE.ino b/examples/SHT_SIMPLE/SHT_SIMPLE.ino index d9fbdcd8..261ff060 100644 --- a/examples/SHT_SIMPLE/SHT_SIMPLE.ino +++ b/examples/SHT_SIMPLE/SHT_SIMPLE.ino @@ -13,6 +13,10 @@ Please install ESP8266 board manager (tested with version 3.0.0) If you are a school or university contact us for a free trial on the AirGradient platform. https://www.airgradient.com/schools/ +Kits with all required components are available at https://www.airgradient.com/diyshop/ + +If you have any questions please visit our forum at https://forum.airgradient.com/ + MIT License */ @@ -25,10 +29,17 @@ void setup(){ } void loop(){ + TMP_RH result = ag.periodicFetchData(); - Serial.print("Humidity: "); - Serial.print(result.rh_char); - Serial.print(" Temperature: "); - Serial.println(result.t_char); + + Serial.print("Relative Humidity in %: "); + Serial.println(result.rh); + + Serial.print(" Temperature in Celcius: "); + Serial.println(result.t); + + Serial.print(" Temperature in Fahrenheit: "); + Serial.println((result.t * 9 / 5) + 32); + delay(5000); } diff --git a/examples/TVOC/TVOC.ino b/examples/TVOC/TVOC.ino new file mode 100644 index 00000000..6fdfc4d1 --- /dev/null +++ b/examples/TVOC/TVOC.ino @@ -0,0 +1,158 @@ +/* +This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller. + +It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi. + +For build instructions please visit https://www.airgradient.com/diy/ + +Instructions on using the TVOC sensor (SGP30) instead of the Temperature / Humidity sensor (SHT3x). + +https://www.airgradient.com/resources/tvoc-on-airgradient-diy-sensor/ + +The codes needs the following libraries installed: +"WifiManager by tzapu, tablatronix" tested with Version 2.0.3-alpha +"ESP8266 and ESP32 OLED driver for SSD1306 displays by ThingPulse, Fabrice Weinberg" tested with Version 4.1.0 +"SGP30" by Rob Tillaart tested with Version 0.1.4 + +Configuration: +Please set in the code below which sensor you are using and if you want to connect it to WiFi. + +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/schools/ + +MIT License +*/ + +#include "SGP30.h" +SGP30 SGP; + +#include +#include +#include +#include + +#include +#include "SSD1306Wire.h" + +AirGradient ag = AirGradient(); + +SSD1306Wire display(0x3c, SDA, SCL); + +WiFiClient client; + +// set sensors that you do not use to false +boolean hasPM=true; +boolean hasCO2=true; +boolean hasSHT=false; +boolean hasTVOC=true; + +// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection +boolean connectWIFI=true; + +// change if you want to send the data to another server +String APIROOT = "http://hw.airgradient.com/"; + +void setup(){ + Serial.begin(9600); + + display.init(); + display.flipScreenVertically(); + showTextRectangle("Init", String(ESP.getChipId(),HEX),true); + + if (hasTVOC) SGP.begin(); + if (hasPM) ag.PMS_Init(); + if (hasCO2) ag.CO2_Init(); + if (hasSHT) ag.TMP_RH_Init(0x44); + + if (connectWIFI) connectToWifi(); + delay(2000); +} + +void loop(){ + + if (hasTVOC) SGP.measure(false); + + // create payload + + String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ","; + + if (hasPM) { + int PM2 = ag.getPM2_Raw(); + payload=payload+"\"pm02\":" + String(PM2); + showTextRectangle("PM2",String(PM2),false); + delay(3000); + } + + if (hasTVOC) { + if (hasPM) payload=payload+","; + int TVOC = SGP.getTVOC(); + payload=payload+"\"tvoc\":" + String(TVOC); + showTextRectangle("TVOC",String(TVOC),false); + delay(3000); + } + + if (hasCO2) { + if (hasTVOC) payload=payload+","; + int CO2 = ag.getCO2_Raw(); + payload=payload+"\"rco2\":" + String(CO2); + showTextRectangle("CO2",String(CO2),false); + delay(3000); + } + + if (hasSHT) { + if (hasCO2 || hasPM) payload=payload+","; + TMP_RH result = ag.periodicFetchData(); + payload=payload+"\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh); + showTextRectangle(String(result.t),String(result.rh)+"%",false); + delay(3000); + } + + payload=payload+"}"; + + // send payload + if (connectWIFI){ + Serial.println(payload); + String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(),HEX) + "/measures"; + Serial.println(POSTURL); + WiFiClient client; + HTTPClient http; + http.begin(client, POSTURL); + http.addHeader("content-type", "application/json"); + int httpCode = http.POST(payload); + String response = http.getString(); + Serial.println(httpCode); + Serial.println(response); + http.end(); + } +} + +// 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(); +} + +// Wifi Manager +void connectToWifi(){ + WiFiManager wifiManager; + //WiFi.disconnect(); //to delete previous saved hotspot + String HOTSPOT = "AIRGRADIENT-"+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); + } + +}