Air Quality Monitoring Station With Wio Terminal

About the project

The Air Quality Terminal can be used as an indoor air quality meter to monitor VOCs, CO, NO2, C2H5CH, Temp and Humidity.

Project info

Difficulty: Moderate

Platforms: ArduinoSeeed Studio

Estimated time: 1 hour

License: GNU General Public License, version 3 or later (GPL3+)

Items used in this project

Hardware components

Seeed Wio Terminal Seeed Wio Terminal x 1

Software apps and online services

Arduino IDE Arduino IDE

Hand tools and fabrication machines

3D Printer (generic) 3D Printer (generic) x 1

Story

TL;DR: The Air Quality Terminal can be used as an indoor air quality meter to monitorVolatile organic compounds(VOCs),Carbon monoxide(CO), Nitrogen Dioxide(NO2), Ethyl alcohol(C2H5CH), Room Temperature and Humidity which can be used detect gas leaks and make alert..etc.

Introduction

Breathing quality indoor air is critical for good health, Humans spend a significant amount of time indoors—either in the home, office or other types of buildings—where gases, chemicals and other pollutants can cause headaches, eye irritation, allergies and fatigue. Serious pollutants can cause certain types of cancers and other long-term health complications. (Src: https://pureaircontrols.com/why-indoor-air-quality-is-important-to-all-of-us/)

Common indoor air pollutants include:

  • Secondhand smoke – A serious indoor air pollutant which can worsen symptoms for asthma sufferers, increase risks of ear infections in children and increase risks for Sudden Infant Death Syndrome.
  • Radon – A dangerous gas pollutant identified as the second leading cause of lung cancer, Radon enters homes through cracks and other improperly sealed openings.
  • Combustion pollutants – These gases, which include carbon monoxide and nitrogen dioxide, come from burning materials or improperly vented fuel-burning appliances such as space heaters, wood stoves, gas stoves, water heaters, dryers and fireplaces.

When you breathe the harmful pollutants, it may stress your immune system that leads to several health conditions. The effects of poor indoor air quality on each person may differ based on their relative health and age. In general, this poor indoor air quality also leads to many allergy symptoms such as weakened immune systems and respiratory problems, and so on.

Specifically, the children are susceptible to so many health issues of the contaminated indoor air because their lungs are very smaller, and also they have to take many breaths during the entire day. If you suffer from the allergy sign or asthma-related issues will find in your home when you may have the polluted or more dust in your home. Even some other sources of air-related problems may also include such as remaining odours, improper ventilation, and natural changes such as new furnishings, a new pet, recent construction, or water damage.

Src: indoorbreathing.com

Src: indoorbreathing.com

Src: indoorbreathing.com

One of the foremost steps to control the source of air pollution is finding out the cause of pollutants such as something like smoke,mold, or chemical off-gassing, and it also possible to eliminate from your house. However, this is one of the long-lasting and most effective methods of enhancing indoor air quality. Below are some of the best solutions to indoor air pollution that could be suggested by the EPA such as. Src: https://indoorbreathing.com/what-are-the-most-common-indoor-air-quality-complaints/

The Air Quality Terminal can be used as an indoor air quality meter to monitorVolatile organic compounds(VOCs),Carbon monoxide(CO), Nitrogen Dioxide(NO2), Ethyl alcohol(C2H5CH), Room Temperature and Humidity which can be used detect gas leaks and make alert..etc.

Carbon monoxide is a colourless and odourless gas which is not easily detectable by human senses and interferes with oxygen delivery throughout the body. Carbon monoxide causes headaches, dizziness, weakness, and nausea. Toxic amounts can lead to death.

Nitrogen dioxide, which is also a colourless and odourless gas, causes eye, nose and throat irritation, shortness of breath, and an increased risk for respiratory infections.

Volatile organic compounds (VOCs) - VOCs are organic chemicals that have a high vapour pressure at ordinary room temperature. Their high vapour pressure results from a low boiling point, which causes large numbers of molecules to evaporate or sublimate from the liquid or solid form of the compound and enter the surrounding air, a trait known as volatility. For example, formaldehyde, which evaporates from paint and releases from materials like resin, has a boiling point of only –19 °C (–2 °F).

Ethyl Alcohol- Ethanol, also called alcohol, ethyl alcohol and grain alcohol, is a clear, colourless liquid and the principle ingredient in alcoholic beverages like beer, wine or brandy. Because it can readily dissolve in water and other organic compounds, ethanol also is an ingredient in a range of products, from personal care and beauty products to paints and varnishes to fuel.

Here I will show you how to build the Air Quality Terminal step by step 🙂.

Components Required
  • Wio Terminal: Wio Terminal based on ATSAMD51-based microcontroller with wireless connectivity supported by Realtek RTL8720DN and is equipped with a 2.4” LCD Screen, onboard IMU(LIS3DHTR), Microphone, Buzzer, microSD card slot, Light sensor, and Infrared Emitter(IR 940nm). Realtek RTL8720DN chip supports both Bluetooth and Wi-Fi providing the backbone for IoT projects.
  • Grove - Multichannel Gas Sensor: Grove - Multichannel Gas Sensor V2 provides stable and reliable gases detecting function under the circumstances of any other four sorts of gases. It can detect a variety of gases, besides Carbon monoxide (CO), Nitrogen dioxide (NO2), Ethyl alcohol(C2H5CH), Volatile Organic Compounds (VOC), and etc.
  • Grove - Temperature & Humidity Sensor (DHT11): Grove - DHT11 Temperature & Humidity Sensor is a high quality, low-cost digital temperature, and humidity sensor based on the DHT11 module.
  • Wio Terminal Stand: You can find the.STL attached to this project, this not mandatory.

Steps Required:
  • Connect the Multichannel Sensor to Wio terminal and Read the value and display to the serial monitor
  • Draw UI Design
  • Convert UI Design to Code
  • Display Sensor data on Display with UI Design
  • Design Stand/Enclosures
  • 3D Print Stand/Enclosures
  • Assemble and Attach Sensors
  • Done!

Architecture

Architecture

Architecture

Architecture

Seeed Wio Terminal

The Wio Terminal based ATSAMD51-based microcontroller with wireless connectivity supported by Realtek RTL8720DN and is equipped with a 2.4” LCD Screen, onboard IMU(LIS3DHTR), Microphone, Buzzer, microSD card slot, Light sensor, and Infrared Emitter(IR 940nm). Realtek RTL8720DN chip supports both Bluetooth and Wi-Fi providing the backbone for IoT projects.

1 / 2Wio Terminal

Wio Terminal

Wio Terminal

Key Features

  • Powerful MCU: Microchip ATSAMD51P19 with ARM Cortex-M4F core running at 120MHz
  • Reliable Wireless Connectivity: Equipped with Realtek RTL8720DN, dual-band 2.4Ghz / 5Ghz Wi-Fi
  • Highly Integrated Design: 2.4” LCD Screen, IMU and more practical add-ons housed in a compact enclosure with built-in magnets & mounting holes
  • Raspberry Pi 40-pin Compatible GPIO
  • Compatible with over 300 plug&play Grove modules to explore with IoT
  • USB OTG Support
  • Support Arduino, CircuitPython, Micropython, ArduPy(What is ArduPy?), AT Firmware, Visual Studio Code
  • TELEC certificated

For more information go to https://www.seeedstudio.com/Wio-Terminal-p-4509.html.

Step 1: Setup Wio Terminal

For Setup, you can follow this wonderful guide provide by SeeedStudio. Get Started with Wio Terminal, anyway I'll go through quickly.

Step 1.1: Download and Install the Arduino IDE: We are using Arduino IDE to programme the Wio Terminal, so we need to install it on our computer first. Click here to download Arduino IDE

Step 1.2: Install Wio Terminal: Arduino IDE comes with official boards loaded from the Arduinio.cc so In order to program Wio Terminal we need to install the Wio Terminal Board packages and definition on the Arduino IDE.

1.2.2: Add Additional Boards Manager URL: For that Open your Arduino IDE, click on File > Preferences, and copy below URL to Additional Boards Manager URLs

https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json

Additional Board Manager

Additional Board Manager

Additional Board Manager

Note: If you have more additional boards manager URL's like me, make it separate with commas.

1.2.3: Install Wio Terminal Board Manager: For that Click on Tools > Board > Board Manager and Search Wio Terminal in the Boards Manager.

Installing Wio Terminal Board Manager

Installing Wio Terminal Board Manager

Installing Wio Terminal Board Manager

1.2.4: Select your board and port: For that, you'll need to select the entry in the Tools > Board menu that corresponds to your Arduino. Selecting the Wio Terminal.

Select Wio Terminal

Select Wio Terminal

Select Wio Terminal

Select the serial device of the Wio Terminal board from the Tools -> Port menu. This is likely to be COM3 or higher (COM1 and COM2 are usually reserved for hardware serial ports). To find out, you can disconnect your Wio Terminal board and re-open the menu; the entry that disappears should be the Arduino board. Reconnect the board and select that serial port.

Step 2: Sensor Test and Display it on Serial Monitor
  • Grove - Multichannel Gas Sensor: Grove - Multichannel Gas Sensor V2 provides stable and reliable gases detecting function under the circumstances of any other four sorts of gases. It can detect a variety of gases, besides Carbon monoxide (CO), Nitrogen dioxide (NO2), Ethyl alcohol(C2H5CH), Volatile Organic Compounds (VOC), and etc.

Grove - Multichannel Gas Sensor v2

Grove - Multichannel Gas Sensor v2

Grove - Multichannel Gas Sensor v2

Features

  • Four fully independent sensor elements on one package.
  • The ability to detect a variety of gases, besides Carbon monoxide (CO), Nitrogen dioxide (NO2), Ethyl alcohol(C2H5CH), Volatile Organic Compounds (VOC) and etc.
  • Qualitative detecting, rather than quantitative.
  • Compact size for easy deployment.

Step 2.1. Connect Grove - Multichannel Gas Sensor V2 to port I2C of Wio Terminal And connect Wio Terminal to PC via a USB cable.

Step 2.2. Download the Grove_Multichannel_Gas_Sensor_v2 Library from Github. And refer How to install library for Arduino.

Step 2.3. Copy the code into Wio Terminal and upload. If you do not know how to upload the code, please check how to upload code.

#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>GAS_GMXXX<TwoWire> gas;unsigned int no2, c2h5ch, voc, co;void setup() {  Serial.begin(115200);  gas.begin(Wire, 0x08);}void loop() {  //VOC  voc = gas.getGM502B();  Serial.print("VOC: ");  Serial.print(voc);  Serial.println(" ppm");  //CO  co = gas.getGM702B();  if (co > 999) co = 999;  Serial.print("CO: ");  Serial.print(co);  Serial.println(" ppm");  //NO2  no2 = gas.getGM102B();  if (no2 > 999) no2 = 999;  Serial.print("NO2: ");  Serial.print(no2);  Serial.println(" ppm");  //C2H5CH  c2h5ch = gas.getGM302B();  if (c2h5ch > 999) c2h5ch = 999;  Serial.print("C2H5CH: ");  Serial.print(c2h5ch);  Serial.println(" ppm");  Serial.println("----------------------------------------------------------------");  delay(2000);}

Step 2.4. After uploading code open the serial monitor

Serial Monitor

Serial Monitor

Serial Monitor

Done, now we interfaced our first sensor and obtained the data.

Grove - DHT Sensor

Grove - DHT Sensor

Grove - DHT Sensor

Features
  • Relative Humidity and temperature measurement
  • Full range temperature compensation Calibrated
  • Digital signal
  • Long term stability
  • Long transmission distance(>20m)
  • Low power consumption

Step 1. Download the Seeed DHT library from Github.

Step 2. Connect DHT11 sensor to Wio Terminal

Step 3. Refer How to install library for Arduino.

Step 4. Copy the code into Wio Terminal and upload. If you do not know how to upload the code, please check how to upload code.

        
#include "DHT.h"#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  dht.begin();}void loop() {  //Temp  float t = dht.readTemperature();  int tem = t;  Serial.print("Temperature: ");  Serial.print(tem);  Serial.println( "*C");  //Humidity  float h = dht.readHumidity();  if (h > 99) h = 99;  Serial.print("Humidity: ");  Serial.print(h);  Serial.println( "%");  Serial.println("----------------------------------------------------------------");  delay(2000);}

Step 5. After uploading code open the serial monitor

Serial Monitor

Serial Monitor

Serial Monitor

  • Combine both Multichannel Gas Sensor V2 and Grove - DHT11 Temperature & Humidity Sensor

Step 1. Connect both Multichannel Gas sensor and DHT11 sensor to Wio Terminal

Step 2. Copy the code into Wio Terminal and upload.

#include <TFT_eSPI.h>#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>#include "DHT.h"GAS_GMXXX<TwoWire> gas;unsigned int no2, c2h5ch, voc, co;#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  gas.begin(Wire, 0x08);  dht.begin();}void loop() {    // VOC  voc = gas.getGM502B();  if (voc > 999) voc = 999;  Serial.print("VOC: ");  Serial.print(voc);  Serial.println(" ppm");    //CO  co = gas.getGM702B();  if (co > 999) co = 999;  Serial.print("CO: ");  Serial.print(co);  Serial.println(" ppm");    //Temp  float t = dht.readTemperature();  //int tem = round(t);  int tem = t;  Serial.print("Temperature: ");  Serial.print(tem);  Serial.println( "*C");    //NO2  no2 = gas.getGM102B();  if (no2 > 999) no2 = 999;  Serial.print("NO2: ");  Serial.print(no2);  Serial.println(" ppm");    //Humidity  float h = dht.readHumidity();  if (h > 99) h = 99;  Serial.print("Humidity: ");  Serial.print(h);  Serial.println( "%");    //C2H5CH  c2h5ch = gas.getGM302B();  if (c2h5ch > 999) c2h5ch = 999;  Serial.print("C2H5CH: ");  Serial.print(c2h5ch);  Serial.println(" ppm");    Serial.println("----------------------------------------------------------------");  delay(2000);}    

Step 3. After uploading code open the serial monitor

Serial Monitor

Serial Monitor

Serial Monitor

Step 3: Design a User Interface.

I Designed simple UI with Draw.io, it's an awesome online tool to create diagrams very quickly. 🤗

UI Design 😁

UI Design 😁

UI Design 😁

The RED colours are the sensor value names, The GREEN colours are the sensor values.

Step 3: Convert Design to Code.

There is a video tutorial show from Wio Terminal Classroom! and Lakshantha will explain how to use the LCD: Wio Terminal Classroom #2 | Drawing Shapes on LCD.

By default, the TFT LCD Library is included inside the Wio Terminal Board Library. Hence, there is no need to download the TFT LCD library again.

First, we can start with the heading. Air Quality

#include <TFT_eSPI.h>#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>#include "DHT.h"GAS_GMXXX<TwoWire> gas;TFT_eSPI tft;TFT_eSprite spr = TFT_eSprite(&tft);  //spriteunsigned int no2, c2h5ch, voc, co;#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  tft.begin();  tft.setRotation(3);  gas.begin(Wire, 0x08);  dht.begin();  //Head  tft.fillScreen(TFT_BLACK);  tft.setFreeFont(&FreeSansBoldOblique18pt7b);  tft.setTextColor(TFT_WHITE);  tft.drawString("Air Quality", 70, 10 , 1);}void loop() { }  

Code review

tft.setFreeFont(&FreeSansBoldOblique24pt7b);

FF# where # is a number determined by looking at the list in the Free_Fonts.h

To draw Strings on the LCD screen:

drawString(const String& string, int32_t poX, int32_t poY);

where string is the text string, and (poX, poY) is the starting coordinates.

Here, we set the cursor on the 70 and 10 and drawstring "Air Quality" as white colour.

//Headtft.fillScreen(TFT_BLACK);tft.setFreeFont(&FreeSansBoldOblique18pt7b);tft.setTextColor(TFT_WHITE);tft.drawString("Air Quality", 70, 10 , 1);

To draw a line between two points on the LCD screen:

drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t color);

where the line starts drawing from (x0, y0) to (x1, y1) and colour.

Here, we draw a line horizontally with green colour.

//Linefor (int8_t line_index = 0; line_index < 5 ; line_index++){tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);}

Display output:

head and line

head and line

head and line

Next, we are daring rectangles for sensor values To draw or fill a rounded rectangle on the LCD screen for

drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t r, uint32_t color);

where (x, y) is the starting coordinate, w and h for width and height of rectangles, r for the corner radius and colour. So.

#include <TFT_eSPI.h>#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>#include "DHT.h"GAS_GMXXX<TwoWire> gas;TFT_eSPI tft;TFT_eSprite spr = TFT_eSprite(&tft);  //spriteunsigned int no2, c2h5ch, voc, co;#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  tft.begin();  tft.setRotation(3);  gas.begin(Wire, 0x08);  dht.begin();  //Head  tft.fillScreen(TFT_BLACK);  tft.setFreeFont(&FreeSansBoldOblique18pt7b);  tft.setTextColor(TFT_WHITE);  tft.drawString("Air Quality", 70, 10 , 1);  //Line  for (int8_t line_index = 0; line_index < 5 ; line_index++)  {    tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);  }  //VCO & CO Rect  tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1  // Temp rect  tft.drawRoundRect((tft.width() / 2) - 10  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1  //No2 rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2  //Humi Rect  tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3  //c2h5ch Rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4}void loop() {}

Here, we drawing rectangles for the sensor values

//VCO & CO Rect  tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1  // Temp rect  tft.drawRoundRect((tft.width() / 2) - 10  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1  //No2 rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2  //Humi Rect  tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3  //c2h5ch Rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4

Display output:

Rect

Rect

next, we need to add the appropriate sensor label name for that,

#include <TFT_eSPI.h>#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>#include "DHT.h"GAS_GMXXX<TwoWire> gas;TFT_eSPI tft;TFT_eSprite spr = TFT_eSprite(&tft);  //spriteunsigned int no2, c2h5ch, voc, co;#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  tft.begin();  tft.setRotation(3);  gas.begin(Wire, 0x08);  dht.begin();  //Head  tft.fillScreen(TFT_BLACK);  tft.setFreeFont(&FreeSansBoldOblique18pt7b);  tft.setTextColor(TFT_WHITE);  tft.drawString("Air Quality", 70, 10 , 1);  //Line  for (int8_t line_index = 0; line_index < 5 ; line_index++)  {    tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);  }  //VCO & CO Rect  tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1  //VCO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("VOC", 7 , 65 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 108, 1);  //CO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("CO", 7 , 150 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 193, 1);  // Temp rect  tft.drawRoundRect((tft.width() / 2) - 10  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Temp", (tft.width() / 2) - 1  , 70 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("o", (tft.width() / 2) + 30, 95, 1);  tft.drawString("C", (tft.width() / 2) + 40, 100, 1);  //No2 rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("NO2", ((tft.width() / 2) + (tft.width() / 2) / 2)   , 70 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , 120, 1);  //Humi Rect  tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Humi", (tft.width() / 2) - 1 , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("%", (tft.width() / 2) + 30, (tft.height() / 2) + 70, 1);  //c2h5ch Rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Ethyl", ((tft.width() / 2) + (tft.width() / 2) / 2)   , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , (tft.height() / 2) + 90, 1);}void loop() {}

Here, we using the drawString function to add the sensor label name.

display VOC and ppm label text

//VCO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("VOC", 7 , 65 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 108, 1);

display CO and ppm label text

//CO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("CO", 7 , 150 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 193, 1);

display Temperature and oc label text

//Temp tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Temp", (tft.width() / 2) - 1  , 70 , 1);   tft.setTextColor(TFT_GREEN);  tft.drawString("o", (tft.width() / 2) + 30, 95, 1);  tft.drawString("C", (tft.width() / 2) + 40, 100, 1);

display NO2 and ppm label name

//NO2tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("NO2", ((tft.width() / 2) + (tft.width() / 2) / 2)   , 70 , 1);   tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , 120, 1); 

display Humidity and % label name

//Humitft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Humi", (tft.width() / 2) - 1 , (tft.height() / 2) + 40 , 1);   tft.setTextColor(TFT_GREEN);  tft.drawString("%", (tft.width() / 2) + 30, (tft.height() / 2) + 70, 1);

display Ethyl and ppm label name

//Ethyltft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Ethyl", ((tft.width() / 2) + (tft.width() / 2) / 2)   , (tft.height() / 2) + 40 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , (tft.height() / 2) + 90, 1); 

Display output

lable name

Now we converted our design into code. 🥳

Step 4: Display sensor readings

Next, we can display the sensor readings within the UI we developed. The Final Code

#include <TFT_eSPI.h>#include <Multichannel_Gas_GMXXX.h>#include <Wire.h>#include "DHT.h"GAS_GMXXX<TwoWire> gas;TFT_eSPI tft;TFT_eSprite spr = TFT_eSprite(&tft);  //spriteunsigned int no2, c2h5ch, voc, co;#define DHTPIN 0#define DHTTYPE DHT11DHT dht(DHTPIN, DHTTYPE);void setup() {  Serial.begin(115200);  tft.begin();  tft.setRotation(3);  gas.begin(Wire, 0x08);  dht.begin();  //Head  tft.fillScreen(TFT_BLACK);  tft.setFreeFont(&FreeSansBoldOblique18pt7b);  tft.setTextColor(TFT_WHITE);  tft.drawString("Air Quality", 70, 10 , 1);  //Line  for (int8_t line_index = 0; line_index < 5 ; line_index++)  {    tft.drawLine(0, 50 + line_index, tft.width(), 50 + line_index, TFT_GREEN);  }  //VCO & CO Rect  tft.drawRoundRect(5, 60, (tft.width() / 2) - 20 , tft.height() - 65 , 10, TFT_WHITE); // L1  //VCO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("VOC", 7 , 65 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 108, 1);  //CO Text  tft.setFreeFont(&FreeSansBoldOblique12pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("CO", 7 , 150 , 1);  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", 55, 193, 1);  // Temp rect  tft.drawRoundRect((tft.width() / 2) - 10  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s1  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Temp", (tft.width() / 2) - 1  , 70 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("o", (tft.width() / 2) + 30, 95, 1);  tft.drawString("C", (tft.width() / 2) + 40, 100, 1);  //No2 rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , 60, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s2  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED);  tft.drawString("NO2", ((tft.width() / 2) + (tft.width() / 2) / 2)   , 70 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , 120, 1);  //Humi Rect  tft.drawRoundRect((tft.width() / 2) - 10 , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s3  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Humi", (tft.width() / 2) - 1 , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("%", (tft.width() / 2) + 30, (tft.height() / 2) + 70, 1);  //c2h5ch Rect  tft.drawRoundRect(((tft.width() / 2) + (tft.width() / 2) / 2) - 5  , (tft.height() / 2) + 30, (tft.width() / 2) / 2 , (tft.height() - 65) / 2 , 10, TFT_BLUE); // s4  tft.setFreeFont(&FreeSansBoldOblique9pt7b);  tft.setTextColor(TFT_RED) ;  tft.drawString("Ethyl", ((tft.width() / 2) + (tft.width() / 2) / 2)   , (tft.height() / 2) + 40 , 1); // Print the test text in the custom font  tft.setTextColor(TFT_GREEN);  tft.drawString("ppm", ((tft.width() / 2) + (tft.width() / 2) / 2) + 30 , (tft.height() / 2) + 90, 1);}void loop() {  // VOC  voc = gas.getGM502B();  if (voc > 999) voc = 999;  Serial.print("VOC: ");  Serial.print(voc);  Serial.println(" ppm");  spr.createSprite(40, 30);  spr.fillSprite(TFT_BLACK);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(voc, 0, 0, 1);  spr.pushSprite(15, 100);  spr.deleteSprite();  //CO  co = gas.getGM702B();  if (co > 999) co = 999;  Serial.print("CO: ");  Serial.print(co);  Serial.println(" ppm");  spr.createSprite(40, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(co, 0, 0, 1);  spr.setTextColor(TFT_GREEN);  spr.pushSprite(15, 185);  spr.deleteSprite();  //Temp  float t = dht.readTemperature();  //int tem = round(t);  int tem = t;  Serial.print("Temperature: ");  Serial.print(tem);  Serial.println( "*C");  spr.createSprite(30, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(t, 0, 0, 1);  spr.setTextColor(TFT_GREEN);  spr.pushSprite((tft.width() / 2) - 1, 100);  spr.deleteSprite();  //NO2  no2 = gas.getGM102B();  if (no2 > 999) no2 = 999;  Serial.print("NO2: ");  Serial.print(no2);  Serial.println(" ppm");  spr.createSprite(45, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(no2, 0, 0, 1);  spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), 97);  spr.deleteSprite();  //Humidity  float h = dht.readHumidity();  if (h > 99) h = 99;  Serial.print("Humidity: ");  Serial.print(h);  Serial.println( "%");  spr.createSprite(30, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(h, 0, 0, 1);  spr.pushSprite((tft.width() / 2) - 1, (tft.height() / 2) + 67);  spr.deleteSprite();  //C2H5CH  c2h5ch = gas.getGM302B();  if (c2h5ch > 999) c2h5ch = 999;  Serial.print("C2H5CH: ");  Serial.print(c2h5ch);  Serial.println(" ppm");  spr.createSprite(45, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(c2h5ch, 0 , 0, 1);  spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), (tft.height() / 2) + 67);  spr.deleteSprite();  delay(2000);} 

Here. we are reading the sensor values and displaying it with 2-sec delay.

code review

Reading and displaying the VOC value

// VOC  voc = gas.getGM502B();  if (voc > 999) voc = 999;  Serial.print("VOC: ");  Serial.print(voc);  Serial.println(" ppm");  spr.createSprite(40, 30);  spr.fillSprite(TFT_BLACK);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(voc, 0, 0, 1);  spr.pushSprite(15, 100);  spr.deleteSprite();

Reading and displaying the CO value

//CO  co = gas.getGM702B();  if (co > 999) co = 999;  Serial.print("CO: ");  Serial.print(co);  Serial.println(" ppm");  spr.createSprite(40, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(co, 0, 0, 1);  spr.setTextColor(TFT_GREEN);  spr.pushSprite(15, 185);  spr.deleteSprite();

Reading and displaying the Temperature value

//Temp  float t = dht.readTemperature();  //int tem = round(t);  int tem = t;  Serial.print("Temperature: ");  Serial.print(tem);  Serial.println( "*C");  spr.createSprite(30, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(t, 0, 0, 1);  spr.setTextColor(TFT_GREEN);  spr.pushSprite((tft.width() / 2) - 1, 100);  spr.deleteSprite();

Reading and displaying the NO2 value

//NO2  no2 = gas.getGM102B();  if (no2 > 999) no2 = 999;  Serial.print("NO2: ");  Serial.print(no2);  Serial.println(" ppm");  spr.createSprite(45, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(no2, 0, 0, 1);  spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), 97);  spr.deleteSprite();

Reading and displaying the Humidity value

//Humidity  float h = dht.readHumidity();  if (h > 99) h = 99;  Serial.print("Humidity: ");  Serial.print(h);  Serial.println( "%");  spr.createSprite(30, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(h, 0, 0, 1);  spr.pushSprite((tft.width() / 2) - 1, (tft.height() / 2) + 67);  spr.deleteSprite();

Reading and displaying the C2H5CH value

//C2H5CH  c2h5ch = gas.getGM302B();  if (c2h5ch > 999) c2h5ch = 999;  Serial.print("C2H5CH: ");  Serial.print(c2h5ch);  Serial.println(" ppm");  spr.createSprite(45, 30);  spr.setFreeFont(&FreeSansBoldOblique12pt7b);  spr.setTextColor(TFT_WHITE);  spr.drawNumber(c2h5ch, 0 , 0, 1);  spr.pushSprite(((tft.width() / 2) + (tft.width() / 2) / 2), (tft.height() / 2) + 67);  spr.deleteSprite();

Output Display

Final Display

Final Display

Step 5: Design Enclourse/Stand

I used Autodesk Fusion360 to design the stand.

Wio Terminal stand deisgn

Wio Terminal stand deisgn

Wio Terminal stand deisgn

Step 5: 3D Print Enclourse/Stand

Src: https://gifer.com/en/93vb

Src: https://gifer.com/en/93vb

Src: https://gifer.com/en/93vb

I used black ABS filament to print the stand.

3D printing .

3D printing .

3D printing .

Step 6: Assembling

src: https://tenor.com/

src: https://tenor.com/

src: https://tenor.com/

The final part is, assembling

Connect DHT11

Connect DHT11

Connect DHT11

. First I connected DHT11 and screwed.

Sensor connection

Sensor connection

Sensor connection

Side View

Side View

Side View

Step 7: Hero Shot!

Air Quality Terminal

Air Quality Terminal

Air Quality Terminal

Future Plan

Air Quality Terminal Project is not completed yet I was planning to push the data to cloud and do some analytics base on the value 😎. Please share your valuable comment and feedback!

Schematics, diagrams and documents

Air Quality Terminal Architecture

CAD, enclosures and custom parts

Wio Terminal Stand

Go to download

Code

AirQuality-Terminal.ino

Credits

Photo of salmanfarisvp

salmanfarisvp

Maker | Hardware Hacker | Electronics Enthusiast

   

Leave your feedback...