Building a simple air quality indicator

I demonstrated Using a bicolour LED with an NodeMCU in an earlier blog.

We now extend that code and instead of having a single LED, we have two. One LED will indicate the current levels of PM2.5, and the other LED will indicate the current levels of PM10. To do this we need to connect to the internet and download these levels from the Clean Air Eastbourne API. The API returns a single float as a string with the current value in µg/m3.

The wiring is very similar to the previous blog post, except we include an extra LED connected to D3 and D4 on the NodeMCU.

The code

The NodeMCU has support for WiFi built in thanks to it’s ESP8266 chip, so it’s very easy to go online in our in setup()loop() function we poll for values every 30 seconds. We turn these values into floats and compare our snapshot against the WHO annual guidelines limits, and UK annual legal limits. If we’re below WHO and UK limits, we show green. If we’re above WHO limits, but below UK limits, we show amber. If we’re above both WHO and UK limits, we show red.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

// Wifi connection details
const char* ssid = "Wifi Network";
const char* password = "Wifi Password";

// Poll URLs
const char* PM10_URL = "http://api.eastbourneair.com/readings/906088-pm10";
const char* PM25_URL = "http://api.eastbourneair.com/readings/906088-pm25";

// How often to poll the website for updates (in microseconds)
const int POLL_DELAY = 30000;

// Limits for particulates from the WHO and UK.
// These are annual limits.
const float WHO_PM10 = 20.0;
const float WHO_PM25 = 10.0;
const float UK_PM10 = 40.0;
const float UK_PM25 = 25.0;

// The TriColour LEDs are wired to the following pins
int redPinPM10 = D2, greenPinPM10 = D1;
int redPinPM25 = D3, greenPinPM25 = D4;

void setup () {
  pinMode(redPinPM10, OUTPUT);
  pinMode(redPinPM25, OUTPUT);
  pinMode(greenPinPM10, OUTPUT);
  pinMode(greenPinPM25, OUTPUT);

  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to Wifi...");
  }

}

void loop() {

  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status

    HTTPClient http;  //Declare an object of class HTTPClient

    Serial.println("Getting PM10 data...");
    http.begin(PM10_URL);  //Specify request destination
    int httpCode = http.GET();                                        //Send the request
    if (httpCode > 0) { //Check the returning code

      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);             //Print the response payload

      int reading = payload.toFloat();

      digitalWrite(redPinPM10, LOW);
      digitalWrite(greenPinPM10, LOW);
      if (reading >= WHO_PM10 && reading < UK_PM10) {  // turn the LED if over WHO limits, but under UK
        Serial.println("Over WHO guidelines ");
        digitalWrite(redPinPM10, HIGH);
        digitalWrite(greenPinPM10, HIGH);
      } else if (reading >= UK_PM10) {                 // turn the LED on if over UK limits
        Serial.println("Over UK limits");
        digitalWrite(redPinPM10, HIGH);
      } else {
        Serial.println("under limit");
        digitalWrite(greenPinPM10, HIGH);
      }
    } else {
      Serial.println("Unable to get data from API");
    }
    http.end();   //Close connection


    Serial.println("Getting PM2.5 data...");
    http.begin(PM25_URL);  //Specify request destination
    httpCode = http.GET();                                            //Send the request
    if (httpCode > 0) { //Check the returning code

      String payload = http.getString();   //Get the request response payload
      Serial.println(payload);             //Print the response payload

      int reading = payload.toFloat();

      digitalWrite(redPinPM25, LOW);
      digitalWrite(greenPinPM25, LOW);
      if (reading >= WHO_PM25 && reading < UK_PM25) {  // turn the LED if over WHO limits, but under UK
        Serial.println("Over WHO guidelines ");
        digitalWrite(redPinPM25, HIGH);
        digitalWrite(greenPinPM25, HIGH);
      } else if (reading >= UK_PM25) {                 // turn the LED on if over UK limts
        Serial.println("Over UK limits");
        digitalWrite(redPinPM25, HIGH);
      } else {
        Serial.println("under limit");
        digitalWrite(greenPinPM25, HIGH);
      }
    } else {
      Serial.println("Unable to get data from API");
    }
    http.end();   //Close connection

  } else {
    Serial.println("Not connected to Wifi");
  }

  delay(POLL_DELAY);    // wait before we poll again.
}