/* This is the code for the AirGradient DIY BASIC 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. Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy/ Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/ The codes needs the following libraries installed: “WifiManager by tzapu, tablatronix” tested with version 2.0.11-beta “U8g2” by oliver tested with version 2.32.15 Configuration: Please set in the code below the configuration parameters. 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 "SSD1306Wire.h" AirGradient ag = AirGradient(); SSD1306Wire display(0x3c, SDA, SCL); // CONFIGURATION START // set to true to switch PM2.5 from ug/m3 to US AQI boolean inUSaqi = true; // 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=true; // CONFIGURATION END unsigned long currentMillis = 0; const int oledInterval = 5000; unsigned long previousOled = 0; const int sendToServerInterval = 10000; unsigned long previoussendToServer = 0; const int co2Interval = 5000; unsigned long previousCo2 = 0; int Co2 = 0; const int pm25Interval = 5000; unsigned long previousPm25 = 0; int pm25 = 0; const int tempHumInterval = 2500; unsigned long previousTempHum = 0; float temp = 0; int hum = 0; int displaypage = 0; String APIROOT = "http://hw.airgradient.com/"; void setup() { Serial.begin(115200); display.init(); display.flipScreenVertically(); if (connectWIFI) { connectToWifi(); } showTextRectangle("Init", String(ESP.getChipId(), HEX), true); ag.CO2_Init(); ag.PMS_Init(); ag.TMP_RH_Init(0x44); } void loop() { currentMillis = millis(); updateOLED(); updateCo2(); updatePm25(); updateTempHum(); sendToServer(); } void updateCo2() { if (currentMillis - previousCo2 >= co2Interval) { previousCo2 += co2Interval; Co2 = ag.getCO2_Raw(); Serial.println(String(Co2)); } } void updatePm25() { if (currentMillis - previousPm25 >= pm25Interval) { previousPm25 += pm25Interval; pm25 = ag.getPM2_Raw(); Serial.println(String(pm25)); } } void updateTempHum() { if (currentMillis - previousTempHum >= tempHumInterval) { previousTempHum += tempHumInterval; TMP_RH result = ag.periodicFetchData(); temp = result.t; hum = result.rh; Serial.println(String(temp)); } } void updateOLED() { if (currentMillis - previousOled >= oledInterval) { previousOled += oledInterval; switch (displaypage) { case 0: if (inUSaqi) { showTextRectangle("AQI", String(PM_TO_AQI_US(pm25)), false); } else { showTextRectangle("PM2", String(pm25), false); } displaypage = 1; break; case 1: showTextRectangle("CO2", String(Co2), false); displaypage = 2; break; case 2: if (inF) { showTextRectangle("F", String((temp * 9 / 5) + 32), false); } else { showTextRectangle("C", String(temp), false); } displaypage = 3; break; case 3: showTextRectangle("Hum", String(hum)+"%", false); displaypage = 0; break; } } } 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, 38, ln2); display.display(); } void sendToServer() { if (currentMillis - previoussendToServer >= sendToServerInterval) { previoussendToServer += sendToServerInterval; String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ", \"rco2\":" + String(Co2) + ", \"pm02\":" + String(pm25) + ", \"atmp\":" + String(temp) + ", \"rhum\":" + String(hum) + "}"; if(WiFi.status()== WL_CONNECTED){ 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(); } else { Serial.println("WiFi Disconnected"); } } } // Wifi Manager void connectToWifi() { WiFiManager wifiManager; //WiFi.disconnect(); //to delete previous saved hotspot String HOTSPOT = "AIRGRADIENT-" + String(ESP.getChipId(), HEX); wifiManager.setTimeout(60); if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) { showTextRectangle("offline", "mode", true); Serial.println("failed to connect and hit timeout"); delay(6000); } } // 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; };