W-air Quality: Wearable Air-Quality Sensor
What is W-Air Quality
In 2018 Chicago received an F grade on its air pollution quality report from the American Lung Association, and it was still only the 22nd worst city in America. Pollution is known to be seriously harmful to those with asthma and is detrimental to health over long term exposure.  This project will attempt to shed some light on the issue of air quality by creating a live map of Chicago with points indicating the worst air quality in the city.
This wearable device creates a live-map of air quality in a city, based on sensor data from an MQ-135 air quality sensor and location from a NEO 6-M GPS module. An ESP32 microcontroller (MCU) will analyze sensor data, and transmit locations of poor air quality using the RESTful API to a Raspberry Pi cloud that pins that location on a map.
Essentially, while you're out and about the device will constantly be looking for pollution. If a high enough level of pollution is reached the user will receive feedback from a ring of LEDs. The device takes sensor readings to determine the level of gasses present and then grabs the GPS location and stores the value and GPS location in memory. When the device is near Wi-Fi again this data is uploaded to a Raspberry Pi server which applies the data to a live map based on the GPS coordinates.
In the prototype, the sensor readings are uncalibrated, and should only be compared to other sensor readings from the same prototype.
The device utilizes an MQ-135 air quality sensor capable of NH3, NOx, Alcohol, Benzene, Smoke, CO2. Chemicals in those gasses interact with a tin-oxide (SnO2) layer, which will change resistance when the gas is present, allowing us to detect the above gases. The sensor is also very sensitive to heat, so a heating-element is included in the sensor module to maintain a constant temperature.
The MQ-135 sensor was far from perfect. The heating element required substantial current (150 mA, more than the current draw of the MCU), and several minutes to warm up to operating temperatures. The sensor was also very inaccurate, although it could easily detect the presence of gasses it's difficult to determine the concentration of the gas which could be used to determine the AQI (Air Quality Index), which is widely used to gather Air Quality data. This definitely leaves room for the project to expand.
Originally, the levels of gas were measured as a threshold value. However, to determine the severity of pollution in an area, the device records the peak value from the sensor as a function of voltage. Once the threshold for pollution is reached, the device begins tracking the highest value of pollution detected to be recorded as the "peak value". A sampling function was also included, which takes 5 samples during the data collection period and averages them to even out faulty sensor data.
In these tests, a 40% alcohol solution was introduced to the sensor for 5 sensor cycles (2.5 seconds), and the resulting data is recorded above. With the sampling algorithm applied, you can observe that the readings appear much steadier.
To retrieve its location the device utilizes NEO-6M GPS module. The GPS module I’m using for this device is self-contained and simply sends NMEA Strings over Serial Communication lines to the Arduino (at 9600 baud). NMEA stands for National Marine Electronics Association and is the standard for GPS communication world-wide (GPS World). I used the TinyGps++ library to parse these strings and read the latitude, longitude, and number of satellites the GPS module can see.
After implementing the library, I found that it takes a lock on at least 3 satellites to get the position, but the best accuracy is had at a lock on 4 satellites. This is useful to know, we can require a lock on 4 satellites before longitude and latitude values are accepted.
The ESP32 is a very popular microcontroller for IoT projects. It can perform standard Wi-Fi functions and can operate using the Bluetooth and BLE protocols. It also has dual-cores, which makes multitasking with this MCU very easy.
I implemented state-based control for the LEDs as a process that runs on the second core of the ESP-32. One of the neat things about the ESP32 is that it uses FreeRTOS, or real-time operating system which allows us to utilize tasks with different priorities that can all run independently. The task that controls the LEDs runs on Core 1, and Core 0 operates our main function. A global variable that controls the brightness, color, and type of display (the state) can be changed by the main program that will instantly change the display.
Something I’ve seen in other IoT devices and always wanted to implement is a solution for the user to input their SSID and Password over Wi-Fi so their IoT device can access the internet. To do this, I utilized a captive portal on the ESP32 based on ESPRESSIF’s captive portal example (ESP32 Resources). A captive portal is a web page that can be accessed by joining a network, what makes it captive is that all traffic is directed to the page once a device is connected. You can see this on airplanes, when you connect to the in-flight Wi-Fi and get redirected to their website. The way the ESP 32 does this is by establishing itself as a DNS server and creating a Wi-fi network you can connect to. It waits for a client connection and then directs all traffic to a webpage it hosts. I added a form to the webpage for the SSID and Password of your network, input from that is parsed on the Arduino from a GET request using code I wrote.
One of the design constraints I was concerned about in my initial proposal is a lack of Wi-Fi connection. If there’s no Wi-Fi, we need to be able to store the coordinates and send them to the server when a Wifi connection is available. I considered two solutions to this problem, writing to the Flash memory on the ESP with SPIFFs or writing directly into the EEPROM. SPIFFs is a flash file system that lets you write files to flash and update them later, it works similarly to the os commands in python that allow you to edit files. This has the advantage of storing larger files, but large files aren’t necessary on this project, and I found that I’m already using over 80% of the flash memory on the ESP32 so the more I can minimize that usage, the better.
The solution I ended up using was writing to the EEPROM, which is limited to 512 bytes, so I decided to create a memory map, similar to what we did in ECE 441, embedded systems. There are 3 things I need to store in memory; SSID, Password, and sensor values. I used $000 to store the number of locations, and since SSID and Password are variable strings I used $001 and $002 to store their lengths. I also had to include a spacer after the SSID in EEPROM, otherwise it would be difficult for the Arduino EEPROM library to differentiate the two strings. Using my memory map, we can determine where each String and Coordinate are located. For example, the Coordinates start at $005+ the length of the SSID + the length of the password. Using this method I calculated we can store roughly 40 sets of coordinates in the EEPROM which can be returned when the device is connected to Wi-Fi again.
Using the Flask API I was able to parse GET requests from the ESP32 on the Raspberry Pi and store them in a CSV file using Pandas, a python library for editing data structures. Then I utilized Plotly, a python library for generating interactive HTML plots, to create a heat-map based on the CSV file. I updated the main page of my website to deliver the plotly HTML page to the user. Currently, when a GET request is sent, the server first appends it to the CSV file, then reopens the CSV file with plotly to remake the heat-map. This is not optimal if the ESP sends a large quantity of coordinates, and may waste a lot of time, so I will consider reoptimizing this in the future. Perhaps the GET request could include a flag, so the server would know only to append to the CSV file, and wait to create the heat-map until the last coordinate is received.
 - “Chicago Gets 'F' Grade in 2018 Air Pollution Report,” WTTW News. [Online]. Available: https://news.wttw.com/2018/04/20/chicago-gets-f-grade-2018-air-pollution-report. [Accessed: 16-Mar-2020].