Since some air pollutants can react with each other and spread very rapidly, precedence must be given to detecting highly reactive gases (air contaminants), such as ozone (O3) and nitrogen compounds (NOx, NOy). Thus, in this project, I decided to focus on ozone (O3) and nitrogen dioxide (NO2) concentrations, which denote dangerous air pollution.

In ambient air, nitrogen oxides can occur from diverse combinations of oxygen and nitrogen. The higher combustion temperatures cause more nitric oxide reactions. In ambient conditions, nitric oxide is rapidly oxidized in air to form nitrogen dioxide by available oxidants, for instance, oxygen, ozone, and VOCs (volatile organic compounds). Hence, nitrogen dioxide (NO2) is widely known as a primary air pollutant (contaminant). Since road traffic is considered the principal outdoor source of nitrogen dioxide[1], densely populated areas are most susceptible to its detrimental effects. Nitrogen dioxide causes a range of harmful effects on the respiratory system, for example, increased inflammation of the airways, reduced lung function, increased asthma attacks, and cardiovascular harm[2].

Tropospheric, or ground-level ozone (O3), is formed by chemical reactions between oxides of nitrogen (NOx) and volatile organic compounds (VOCs). This chemical reaction is triggered by sunlight between the mentioned air pollutants emitted by cars, power plants, industrial boilers, refineries, and chemical plants[3]. Depending on the level of exposure, ground-level ozone (O3) can have various effects on the respiratory system, for instance, coughing, sore throat, airway inflammation, increased frequency of asthma attacks, and increased lung infection risk. Some of these detrimental effects have been found even in healthy people, but symptoms can be more severe in people with lung diseases such as asthma[4].

Credit: epa.gov

Credit: epa.gov

Since nitrogen dioxide (NO2), ozone (O3), and other photochemical oxidant reactions and transmission rates are inextricably related to air flow, heat, and ambient humidity, I decided to collect the following data parameters to create a meticulous data set:

After perusing recent research papers on ambient air pollution, I noticed there are very few appliances focusing on collecting air quality data, detecting air pollution levels with machine learning, and providing surveillance footage for further examination. Therefore, I decided to build a budget-friendly and easy-to-use air station to forecast air pollution levels with machine learning and inform the user of the model detection results with surveillance footage consecutively, in the hope of forfending the plight of hazardous gases.

To predict air pollution levels, I needed to collect precise ambient hazardous gas concentrations in order to train my neural network model with notable validity. Therefore, I decided to utilize DFRobot electrochemical gas sensors. To obtain the additional weather data, I employed an anemometer kit and a DHT22 sensor. Since FireBeetle ESP32 is a compact and powerful IoT-purposed development board providing numerous features with its budget-friendly media (camera) board, I decided to use FireBeetle ESP32 in combination with its media board so as to run my neural network model and inform the user of the model detection results with surveillance footage. Due to the memory allocation issues, I connected all sensors to Arduino Mega to collect and transmit air quality data to FireBeetle ESP32 via serial communication. Also, I connected three control buttons to Arduino Mega to send commands to FireBeetle ESP32 via serial communication.

Since the FireBeetle media board supports reading and writing information from/to files on an SD card, I stored the collected air quality data in separate CSV files on the SD card, named according to the selected air pollution class, to create a pre-formatted data set. In this regard, I was able to save and process data records via FireBeetle ESP32 without requiring any additional procedures.

After completing my data set, I built my artificial neural network model (ANN) with Edge Impulse to make predictions on air pollution levels (classes). Since Edge Impulse is nearly compatible with all microcontrollers and development boards, I had not encountered any issues while uploading and running my model on FireBeetle ESP32. As labels, I utilized the empirically assigned air pollution levels in accordance with the Air Quality Index (AQI) estimations provided by IQAir:

After training and testing my neural network model, I deployed and uploaded the model on FireBeetle ESP32 as an Arduino library. Therefore, the air station is capable of detecting air pollution levels by running the model independently without any additional procedures or latency.

Since I focused on building a full-fledged AIoT air station predicting air pollution and informing the user of the model detection results with surveillance footage, I decided to develop a web application from scratch to obtain the detection results with surveillance footage from FireBeetle ESP32 via HTTP POST requests, save the received information to a MySQL database table, and display the stored air quality data with model detection results in descending order simultaneously.

Due to the fact that the FireBeetle media board can only generate raw image data, this complementing web application executes a Python script to convert the obtained raw image data to a JPG file automatically before saving it to the server as surveillance footage. After saving the converted image successfully, the web application shows the most recently obtained surveillance footage consecutively and allows the user to inspect previous surveillance footage in descending order.

Lastly, to make the device as robust and compact as possible while operating outdoors, I designed a metallic air station case with a sliding front cover and a mountable camera holder (3D printable) for the OV7725 camera connected to the FireBeetle media board.

So, this is my project in a nutshell 😃

In the following steps, you can find more detailed information on coding, capturing surveillance footage, building a neural network model with Edge Impulse, running the model on FireBeetle ESP32, and developing a full-fledged web application to obtain the model detection results with surveillance footage from FireBeetle ESP32 via HTTP POST requests.

🎁🎨 Huge thanks to DFRobot for sponsoring these products:

⭐ FireBeetle ESP32 | Inspect

⭐ FireBeetle Covers - Camera&Audio Media Board | Inspect

⭐ Gravity: Electrochemical Nitrogen Dioxide Sensor | Inspect

⭐ Gravity: Electrochemical Ozone Sensor | Inspect

⭐ Anemometer Kit | Inspect

⭐ LattePanda 3 Delta 864 | Inspect

⭐ DFRobot 8.9" 1920x1200 IPS Touch Display | Inspect

🎁🎨 Also, huge thanks to Creality for sending me a Creality Sonic Pad, a Creality Sermoon V1 3D Printer, and a Creality CR-200B 3D Printer.

Step 1: Designing and printing a metallic air station case

Since I focused on building a budget-friendly and accessible air station that collects air quality data and runs a neural network model to inform the user of air pollution via a PHP web application, I decided to design a sturdy and compact metallic case allowing the user to access the SD card after logging data, place the air quality sensors, and adjust the OV7725 camera effortlessly. To avoid overexposure to dust and prevent loose wire connections, I added a sliding front cover with a handle to the case. Then, I designed a separate camera holder mountable to the left side of the case at four different angles. Also, I decided to inscribe air pollution indicators on the sliding front cover to highlight the imminent pollution risk.

Since I needed to attach an anemometer to the case to collect wind speed data, I decided to design a semi-convex structure for the case. This unique shape also serves as a wind deflector that protects the air quality sensors from potential wind damage.

I designed the metallic air station case, its sliding front cover, and the mountable camera holder in Autodesk Fusion 360. You can download their STL files below.

Then, I sliced all 3D models (STL files) in Ultimaker Cura.

Since I wanted to create a solid metallic structure for the air station case with the sliding front cover and apply a unique alloy combination complementing the metallic theme, I utilized these PLA filaments:

Finally, I printed all parts (models) with my Creality Sermoon V1 3D Printer and Creality CR-200B 3D Printer in combination with the Creality Sonic Pad. You can find more detailed information regarding the Sonic Pad in Step 1.1.

If you are a maker or hobbyist planning to print your 3D models to create more complex and detailed projects, I highly recommend the Sermoon V1. Since the Sermoon V1 is fully-enclosed, you can print high-resolution 3D models with PLA and ABS filaments. Also, it has a smart filament runout sensor and the resume printing option for power failures.

Furthermore, the Sermoon V1 provides a flexible metal magnetic suction platform on the heated bed. So, you can remove your prints without any struggle. Also, you can feed and remove filaments automatically (one-touch) due to its unique sprite extruder (hot end) design supporting dual-gear feeding. Most importantly, you can level the bed automatically due to its user-friendly and assisted bed leveling function.

#️⃣ Before the first use, remove unnecessary cable ties and apply grease to the rails.

#️⃣ Test the nozzle and hot bed temperatures.

#️⃣ Go to Print Setup ➡ Auto leveling and adjust five predefined points automatically with the assisted leveling function.

#️⃣ Finally, place the filament into the integrated spool holder and feed the extruder with the filament.

#️⃣ Since the Sermoon V1 is not officially supported by Cura, download the latest Creality Slicer version and copy the official printer settings provided by Creality, including Start G-code and End G-code, to a custom printer profile on Cura.

Step 1.1: Improving print quality and speed with the Creality Sonic Pad

Since I wanted to improve my print quality and speed with Klipper, I decided to upgrade my Creality CR-200B 3D Printer with the Creality Sonic Pad.

Creality Sonic Pad is a beginner-friendly device to control almost any FDM 3D printer on the market with the Klipper firmware. Since the Sonic Pad uses precision-oriented algorithms, it provides remarkable results with higher printing speeds. The built-in input shaper function mitigates oscillation during high-speed printing and smooths ringing to maintain high model quality. Also, it supports G-code model preview.

Although the Sonic Pad is pre-configured for some Creality printers, it does not support the CR-200B officially yet. Therefore, I needed to add the CR-200B as a user-defined printer to the Sonic Pad. Since the Sonic Pad needs unsupported printers to be flashed with the self-compiled Klipper firmware before connection, I flashed my CR-200B with the required Klipper firmware settings via FluiddPI by following this YouTube tutorial.

If you do not know how to write a printer configuration file for Klipper, you can download the stock CR-200B configuration file from here.

#️⃣ After flashing the CR-200B with the Klipper firmware, copy the configuration file (printer.cfg) to a USB drive and connect the drive to the Sonic Pad.

#️⃣ After setting up the Sonic Pad, select Other models. Then, load the printer.cfg file.

#️⃣ After connecting the Sonic Pad to the CR-200B successfully via a USB cable, the Sonic Pad starts the self-testing procedure, which allows the user to test printer functions and level the bed.

#️⃣ After completing setting up the printer, the Sonic Pad lets the user control all functions provided by the Klipper firmware.

#️⃣ In Cura, export the sliced model in the ufp format. After uploading .ufp files to the Sonic Pad via the USB drive, it converts them to sliced G-code files automatically.

#️⃣ Also, the Sonic Pad can display model preview pictures generated by Cura with the Create Thumbnail script.

Step 1.2: Assembling the case and making connections & adjustments

// Connections
// FireBeetle ESP32 :  
//                                Arduino Mega
// D4   --------------------------- D18 (RX1)
// D2   --------------------------- D19 (TX1)
&
&
&
// Connections
// Arduino Mega :
//                                FireBeetle ESP32
// D18  --------------------------- D4
// D19  --------------------------- D2
//                                DFRobot Gravity: Electrochemical Ozone Sensor
// D20  --------------------------- SDA
// D21  --------------------------- SCL
//                                DFRobot Gravity: Electrochemical Nitrogen Dioxide Sensor
// D20  --------------------------- SDA
// D21  --------------------------- SCL
//                                SH1106 OLED Display (128x64)
// D23  --------------------------- SDA
// D22  --------------------------- SCK
// D24  --------------------------- RST
// D25  --------------------------- DC
// D26  --------------------------- CS   
//                                DHT22 Temperature and Humidity Sensor
// D27  --------------------------- DATA
//                                DFRobot Anemometer Kit
// A0   --------------------------- S (Yellow)
//                                Keyes 10mm RGB LED Module (140C05)
// D2   --------------------------- R
// D3   --------------------------- G
// D4   --------------------------- B
//                                Control Button (A)
// D5   --------------------------- +
//                                Control Button (B)
// D6   --------------------------- +
//                                Control Button (C)
// D7   --------------------------- +

First of all, I soldered female pin headers to FireBeetle ESP32 and male pin headers to the FireBeetle (Covers) media board before attaching the OV7725 camera.

Due to the Arduino library incompatibilities and the memory allocation issues, I decided to connect the electrochemical NO2 sensor, the electrochemical ozone sensor, the anemometer kit, and the DHT22 sensor to Arduino Mega so as to collect the required air quality data. Then, I utilized Arduino Mega to transmit the collected air quality data to FireBeetle ESP32 via serial communication.

#️⃣ When the electrochemical NO2 sensor and the electrochemical ozone sensor are powered up for the first time, both sensors require operating for about 24-48 hours to generate calibrated and stable gas concentrations. In my case, I was able to obtain stable results after 30 hours of warming up. Although the electrochemical sensors need to be calibrated once, they have a preheat (warm-up) time of about 5 minutes to evaluate gas concentrations accurately after being interrupted.

#️⃣ Since the anemometer kit requires a 9-24V supply voltage and generates a 0-5V output voltage (signal), I connected a USB buck-boost converter board to my Xiaomi power bank to elicit a stable 20V supply voltage to power the anemometer.

Since Arduino Mega operates at 5V and FireBeetle ESP32 requires 3.3V logic level voltage, they cannot be connected with each other directly. Therefore, I utilized a bi-directional logic level converter to shift the voltage for the connections between FireBeetle ESP32 and Arduino Mega.

To display the collected information and notifications, I utilized an SH1106 OLED screen. To assign air pollution levels empirically while saving the collected data to individual CSV files on the SD card, I used the built-in MicroSD card module on the media board and added three control buttons.

After printing all parts (models), I fastened all components except the OV7725 camera to their corresponding slots on the metallic air station case via a hot glue gun. I also utilized the anemometer's screw kit to attach it more tightly to its connection points on the top of the metallic case.

I placed the OV7725 camera in the mountable camera holder and attached the camera holder to the metallic case via its snap-fit joints.

Then, I placed the sliding front cover via the dents on the metallic case.

As mentioned earlier, the mountable camera holder can be utilized to adjust the OV7725 camera at four different angles via the snap-fit joints.

Step 2: Developing a web application displaying real-time database updates in PHP, JavaScript, CSS, and MySQL

https://www.hackster.io/kutluhan-aktar/ai-assisted-air-quality-monitor-w-iot-surveillance-fd05bb#toc-step-2--developing-a-web-application-displaying-real-time-database-updates-in-php--javascript--css--and-mysql-3

Step 3: Setting up FireBeetle ESP32 on Arduino IDE

https://www.hackster.io/kutluhan-aktar/ai-assisted-air-quality-monitor-w-iot-surveillance-fd05bb#toc-step-3--setting-up-firebeetle-esp32-on-arduino-ide-7

Step 4: Collecting air quality data and communicating with FireBeetle ESP32 via serial communication w/ Arduino Mega

https://www.hackster.io/kutluhan-aktar/ai-assisted-air-quality-monitor-w-iot-surveillance-fd05bb#toc-step-4--collecting-air-quality-data-and-communicating-with-firebeetle-esp32-via-serial-communication-w--arduino-mega-9

Step 4.1: Logging the transmitted air quality data in a CSV file on the SD card w/ FireBeetle ESP32

After uploading and running the code for collecting air quality data and transferring the collected data to FireBeetle ESP32 via serial communication:

🎈⚠️📲 If the electrochemical gas sensors work accurately, the air station turns the RGB LED to blue and waits until the electrochemical gas sensors heat (warm-up) for 3 minutes.

🎈⚠️📲 The air station generates a data record from the recently collected air quality data and shows the collected data parameters on the SH1106 OLED screen to inform the user.

🎈⚠️📲 If the control button (A) is pressed, Arduino Mega adds Clean as the selected air pollution level to the recently generated data record, transfers the modified data record to FireBeetle ESP32 via serial communication, and turns the RGB LED to green.

🎈⚠️📲 Then, it shows the unique monochrome icon of the selected air pollution level (class) on the SH1106 OLED screen.

🎈⚠️📲 If the control button (B) is pressed, Arduino Mega adds Risky as the selected air pollution level to the recently generated data record, transfers the modified data record to FireBeetle ESP32 via serial communication, and turns the RGB LED to yellow.

🎈⚠️📲 Then, it shows the unique monochrome icon of the selected air pollution level (class) on the SH1106 OLED screen.

🎈⚠️📲 If the control button (C) is pressed, Arduino Mega adds Unhealthy as the selected air pollution level to the recently generated data record, transfers the modified data record to FireBeetle ESP32 via serial communication, and turns the RGB LED to red.

🎈⚠️📲 Then, it shows the unique monochrome icon of the selected air pollution level (class) on the SH1106 OLED screen.

🎈⚠️📲 When FireBeetle ESP32 receives a data record, it creates a new CSV file under the samples folder on the SD card and combines the given air pollution level and the sample number as the file name. Then, FireBeetle ESP32 appends the received air quality data items with the given header to the created CSV file.

🎈⚠️📲 Also, FireBeetle ESP32 increments the sample number of the received air pollution level (class) by 1 to generate unique CSV files (samples).

You can get more detailed information on creating separate CSV files as samples in Step 6.

🎈⚠️📲 Every minute, Arduino Mega transmits the recently collected air quality data parameters to FireBeetle ESP32 via serial communication in order to obtain accurate prediction results after running an inference with the neural network model.

You can get more detailed information on running an inference with the neural network model in Step 7.

🎈⚠️📲 If Arduino Mega throws an error while operating, the air station shows the error message on the SH1106 OLED screen and prints the error details on the serial monitor.

🎈⚠️📲 Also, the air station prints notifications and sensor measurements on the serial monitor for debugging.

After collecting air quality data for nearly 2 months and creating separate CSV files for each data record on the SD card, I elicited my data set with eminent validity and veracity.

You can get more detailed information regarding assigning air pollution levels depending on the Air Quality Index (AQI) estimations provided by IQAir in Step 5.

Step 5: Building a neural network model with Edge Impulse

https://www.hackster.io/kutluhan-aktar/ai-assisted-air-quality-monitor-w-iot-surveillance-fd05bb#toc-step-5--building-a-neural-network-model-with-edge-impulse-11

Step 6: Setting up the Edge Impulse model on FireBeetle ESP32

https://www.hackster.io/kutluhan-aktar/ai-assisted-air-quality-monitor-w-iot-surveillance-fd05bb#toc-step-6--setting-up-the-edge-impulse-model-on-firebeetle-esp32-16

Step 7: Running the model on FireBeetle ESP32 to forecast air pollution levels and transferring the model results w/ surveillance footage via POST requests

My Edge Impulse neural network model predicts possibilities of labels (air pollution classes) for the given features buffer as an array of 3 numbers. They represent the model's "confidence" that the given features buffer corresponds to each of the three different air pollution levels (classes) [0 - 2], as shown in Step 5:

After executing the AIoT_weather_station_run_model.ino file on FireBeetle ESP32:

🎈⚠️📲 When FireBeetle ESP32 receives the latest collected air quality data parameters from Arduino Mega via serial communication, it stores them to run an inference with accurate data items.

🎈⚠️📲 After Arduino Mega sends the air quality data parameters via serial communication successfully, the air station turns the RGB LED to magenta.

🎈⚠️📲 Every 5 minutes, the air station runs an inference with the Edge Impulse neural network model by applying the stored air quality data parameters to predict the air pollution level and captures surveillance footage with the OV7725 camera.

🎈⚠️📲 Then, it transfers the stored air quality data parameters, the model detection result, and the captured surveillance footage (raw image data) as a TXT file to the web application via an HTTP POST request with URL query parameters.

🎈⚠️📲 If manual testing is required, the air station can also perform the mentioned sequence when the built-in button on the FireBeetle media board is pressed.

🎈⚠️📲 Also, the air station prints notifications and model detection results on the serial monitor for debugging.

As far as my experiments go, the air station detects air pollution levels precisely, captures real-time surveillance footage, and communicates with the web application faultlessly :)

Videos and Conclusion

Further Discussions

By applying neural network models trained on air quality data in detecting air pollution levels, we can achieve to:

🎈⚠️📲 prevent human-made air pollutants from harming the respiratory system,

🎈⚠️📲 reduce the risk of increased asthma attacks and cardiovascular harm,

🎈⚠️📲 protect people with lung diseases from severe symptoms of air pollution,

🎈⚠️📲 provide prescient warnings regarding a surge in photochemical oxidant reactions and transmission rates.

References

[1] Jarvis DJ, Adamkiewicz G, Heroux ME, et al, Nitrogen dioxide, WHO Guidelines for Indoor Air Quality: Selected Pollutants, Geneva: World Health Organization, 2010. 5, https://www.ncbi.nlm.nih.gov/books/NBK138707/

[2] Nitrogen Dioxide, The American Lung Association, https://www.lung.org/clean-air/outdoors/what-makes-air-unhealthy/nitrogen-dioxide

[3] Ground-level Ozone Basics, United States Environmental Protection Agency (EPA), https://www.epa.gov/ground-level-ozone-pollution/ground-level-ozone-basics

[4] Health Effects of Ozone Pollution, United States Environmental Protection Agency (EPA), https://www.epa.gov/ground-level-ozone-pollution/health-effects-ozone-pollution