4. Sensors
Posted April 11, 2024
As per My previous research I have to collect (CO2 , Particulate Matter (PM), Volatile organic compounds (VOC), Temperature, and Humidity) to obtain the quality of the indoor AIR so below I will list the needed sensors to collect the required data and their primary test.
List of sensors.
ID | Sensor | Measured Value | LINK | Price | Datasheet |
---|---|---|---|---|---|
1 | SCD30 | CO2, Temp, Hum | LINK | $51.4 | LINK |
2 | PMS5003 | PM1, PM2.5, PM10 | LINK | $39.95 | LINK |
3 | AGS02MA | TVOC | LINK | $4.95 | LINK |
4 | AM2302 | Temp and Humidity | LINK | $7.42 | LINK |
These are the sensors I want to use to build this project.
Now I will test each sensor alone.
SCD30
The SCD30 is a highly accurate CO2 sensor module based on CMOSens® Technology for IR detection that includes a best-in-class humidity and temperature sensor.
This is NDIR (non-dispersive infrared) Sensor which work by using an infrared (IR) lamp to direct waves of light through a tube filled with a sample of air. –> This air moves toward an optical filter in front of an IR light detector. The IR light detector measures the amount of IR light that passes through the optical filter.
Working principle
In an NDIR CO2 sensor, the band of IR radiation also produced by the lamp is very close to the 4.26-micron absorption band of CO2. Because the IR spectrum of CO2 is unique, matching the light source wavelength serves as a signature or “fingerprint” to identify the CO2 molecule.
As the IR light passes through the sample tube of air, the CO2 gas molecules absorb the specific band of IR light while letting other wavelengths of light pass through. At the detector end, the remaining light hits an optical filter that absorbs every wavelength of light except the wavelength absorbed by CO2 molecules in the sample tube.
Finally, an IR detector reads the remaining amount of light that was not absorbed by the CO2 molecules or the optical filter.
For more information about the sensor please refer to links below:
Testing
- I will test the sensor by connecting it to my previously built board.
-
Then I will Use Arduino IDE to code.
-
I will start by downloading the library (Adafruit SCD30 with its dependency) then I will use the example code to check the sensor and its data.
- The example I will use is (adafruit_scd30_test).
- Then I will just upload the code and test how it works.
Great I have a good CO2 percentage.
Code I have used
// Basic demo for readings from Adafruit SCD30
#include <Adafruit_SCD30.h>
Adafruit_SCD30 scd30;
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit SCD30 test!");
// Try to initialize!
if (!scd30.begin()) {
Serial.println("Failed to find SCD30 chip");
while (1) { delay(10); }
}
Serial.println("SCD30 Found!");
// if (!scd30.setMeasurementInterval(10)){
// Serial.println("Failed to set measurement interval");
// while(1){ delay(10);}
// }
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
}
void loop() {
if (scd30.dataReady()){
Serial.println("Data available!");
if (!scd30.read()){ Serial.println("Error reading sensor data"); return; }
Serial.print("Temperature: ");
Serial.print(scd30.temperature);
Serial.println(" degrees C");
Serial.print("Relative Humidity: ");
Serial.print(scd30.relative_humidity);
Serial.println(" %");
Serial.print("CO2: ");
Serial.print(scd30.CO2, 3);
Serial.println(" ppm");
Serial.println("");
} else {
//Serial.println("No data");
}
delay(100);
}
- Now I will compare the temperature and humidity from DHT22 and this sensor.
- Both are close to each other and gives almost the same values.
I have to re-consider having the DHT on my board.
According to this documentation
There is no wide difference between the integrated temperature & Humidity sensors on the SCD30 and the DHT22 but DHT22 lacks the integrated technology that SCD30 offers.
So I will drop the DHT22 from my list (80%)–> I will do it
Code I have Used
// Basic demo for readings from Adafruit SCD30
#include <Adafruit_SCD30.h>
#include <DHT.h>
// Where the DHT data pin is connected
#define PIN 8
// DHT sensor Type.
#define TYPE DHT22
DHT zaid(PIN,TYPE); // Constructor
Adafruit_SCD30 scd30;
void setup(void) {
Serial.begin(115200);
while (!Serial) delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit SCD30 test!");
// Try to initialize!
if (!scd30.begin()) {
Serial.println("Failed to find SCD30 chip");
while (1) { delay(10); }
}
Serial.println("SCD30 Found!");
// if (!scd30.setMeasurementInterval(10)){
// Serial.println("Failed to set measurement interval");
// while(1){ delay(10);}
// }
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
zaid.begin(); // DHT sensor with zaid name started.
}
void loop() {
float temp = zaid.readTemperature();
float hum = zaid.readHumidity();
Serial.println("DHT22 Data : ");
Serial.print("Temperature = ");Serial.println(temp);
Serial.print("Humidity = ");Serial.println(hum);
delay(1000);
Serial.println("SCD30 DATA");
if (scd30.dataReady()){
Serial.println("Data available!");
if (!scd30.read()){ Serial.println("Error reading sensor data"); return; }
Serial.print("Temperature: ");
Serial.print(scd30.temperature);
Serial.println(" degrees C");
Serial.print("Relative Humidity: ");
Serial.print(scd30.relative_humidity);
Serial.println(" %");
Serial.print("CO2: ");
Serial.print(scd30.CO2, 3);
Serial.println(" ppm");
Serial.println("");
} else {
//Serial.println("No data");
}
delay(100);
}
Reflection
-
This sensor is very sensitive as if someone blow to the sensor from a distance it will affect the reading.
-
This sensor have a sampling rate of 0.5 Hz.
PMS5003
PMS5003 is a kind of digital and universal particle concentration sensor, which can be used to obtain the number of suspended particles in the air.
The Sensor uses a Laser Scattering principle where a laser beam hit a light diffuser so the light scatter and hit the air particles then this goes to a receiver to be analyzed.
Working Principle
The Laser pm 2.5 air quality sensor can assess air quality by measuring the concentration of suspended particulate matter (PM2.5) in the air. It works as follows:
- Laser Emitter: First, the laser sensor generates a laser beam through a laser emitter.
- High-efficiency scatterer: The laser beam is directed to a high-efficiency scatterer (also known as a diffuser), which allows the laser beam to scatter with airborne particles.
- Receiver: During the scattering process, the scattered light enters a receiver inside the sensor, which converts the received light signal into an electrical signal for processing.
- Light scattering signal analysis: the received light signal will be analyzed to determine the concentration of particulate matter in the air by measuring the angle and intensity of light scattering.
- PM2.5 Concentration Calculation: By estimating the size of the particulate matter based on the angle and intensity of scattering, the PM2.5 concentration is then calculated.
Testing
I will connect it now with the Board I have made.
- This sensor uses serial communication to send its data.
- For the connection with the XIAOESP32C3. –> The Sensor return data in TTL (3.3) so I don’t have to worry (Because the sensor is taking 5V).
-
Now I will use the Arduino IDE to code it.
-
I will Install the Library (Adafruit_PM25AQI).
- Then I will use the example code coming with the library.
- As for this code it uses software serial library which comes with all the Arduino boards but for the ESP32 This is not achievable so I have to use Hardware serial library.
I will clarify it more in the code file.
- Now I will Upload the code and check the values.
These data shocked me (I thought i may have more dust particles) but this is good I’m within the recommended values from the World health Organization.
Please refer to this Article for more information.
Code USED
#include "Adafruit_PM25AQI.h"
#include <HardwareSerial.h>
HardwareSerial pmSerial(0);
Adafruit_PM25AQI aqi = Adafruit_PM25AQI();
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while(!Serial) delay(10);
delay(1000);
pmSerial.begin(9600,SERIAL_8N1, -1, -1);// hardware serial default for tx 6 and rx 7 in xiaoesp32c3
if (! aqi.begin_UART(&pmSerial)) {
Serial.println("Could not find PM 2.5 sensor!");
while (1) delay(10);
}else {Serial.println("PM25 found!");}
}
void loop() {
// put your main code here, to run repeatedly:
PM25_AQI_Data data;
if (! aqi.read(&data)) {
Serial.println("Could not read from AQI");
delay(500); // try again in a bit!
return;
}
Serial.println("AQI reading success");
Serial.println();
Serial.println(F("---------------------------------------"));
Serial.println(F("Concentration Units (standard)"));
Serial.println(F("---------------------------------------"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_standard);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_standard);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_standard);
Serial.println(F("Concentration Units (environmental)"));
Serial.println(F("---------------------------------------"));
Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_env);
Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_env);
Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_env);
Serial.println(F("---------------------------------------"));
Serial.print(F("Particles > 0.3um / 0.1L air:")); Serial.println(data.particles_03um);
Serial.print(F("Particles > 0.5um / 0.1L air:")); Serial.println(data.particles_05um);
Serial.print(F("Particles > 1.0um / 0.1L air:")); Serial.println(data.particles_10um);
Serial.print(F("Particles > 2.5um / 0.1L air:")); Serial.println(data.particles_25um);
Serial.print(F("Particles > 5.0um / 0.1L air:")); Serial.println(data.particles_50um);
Serial.print(F("Particles > 10 um / 0.1L air:")); Serial.println(data.particles_100um);
Serial.println(F("---------------------------------------"));
delay(1000);
}
So Among all of these data I will Only need 3 DATA (PM1.0, PM2.5, and PM10)
- Now Let me try to trigger the sensor by using a lighter.
It took the sensor a couple of seconds to respond but the change was very big.
Reflection
-
The sensor is very easy to use and connect.
-
The coding are very simple just a few things to know about the XIAO hardware serial.
-
The sensor is big in size so there is no way to fit in what i would like to build so I need to have alternative solution for this.
AGS02MA (TVOC)
AGS02MA is a high-performance TVOC sensor which is equipped with a dedicated ASIC chip, which detect and monitor variety of organic volatile gases, such as ethanol, ammonia, sulfide, benzene steam, smoke.
Working Principle
When the sensor works in air environment, the conductivity of the gas-sensitive material changes with the concentration of the gas being detected in the air. The higher the concentration of the gas being detected, the higher the conductivity of the gas-sensitive material will be. Based on this principle, a special integrated circuit is adopted to convert the change in conductivity into an output signal corresponding to the concentration of the gas.
So in brief there is a sensitive substance on the top of the sensor its resistivity changes according to the VOC in the air, –> the more the VOC the conductivity increases which means the resistivity decrease.
Testing
This sensor is very simple sensor and Have to be connected using I2C, The sensor is analog but there is a chip inside change the data to digital and then communicate it by I2C to the MCU.
Note this sensor needs pull ups on the I2C lines and the speed of communication has not to exceed 30KHz.
I have to keep an Eye on the speed and check how to manage two different clocking sensors on the same MCU.
- I will connect and test this sensor using the Arduino UNO first.
Note : The Sensor operate from 3.3 to 5V
- Now I will code it starting by downloading the Library (Adafruit_AGS02MA), With its dependencies.
- Then I will use the library example.
- Then I will just upload it.
- Now as seen the data locks unrealistic.
the sensor needs to to be powered on for stabilization –> As per the data sheet the stabilization for the first time takes between 12 hours to 96 hours depends on the storage period.
I will leave it for 12 hours then I will check back if the data are still unrealistic I will leave it for 72 hours.
- So these are the data after leaving the sensor for almost 40 hours plugged.
I can tell the sensor needs more until I see stability in the reading for a while.
According to Kaiterra the (a good TVOC amount is under 220 ppb)
For more information Please check this LINK
-
Now this sensor is bothering me with the I2C bus speed ( The sensor can’t operate above 30K bus speed).
-
So I need to find a way to manage SCD30 to work on this level as it by default it works on (100K bus speed).
-
I will try now to connect both sensors on the Arduino for testing then I will jump to the XIAO.
I’m Worried of one thing the SCD30 has internal 45K pull-up resister to 3.3v on the I2C bus and the TVOC sensor needs between 1k to 10k.
I think I can come over this as long as the current is not exceeding 3mA on the bus (I=V/R –> 3.3/10K = 0.33mA even if the Resister is 1K –> I = 3.3mA which is acceptable)
So I will connect a 10K pull-up on the I2C bus and connect both sensors and check if they will work.
-
Uploading the code I will try now to combine both codes together.
-
Unfortunately it did not work.
- I will bypass this argument in the code and check how it will act.
-
So as seen the same problem still appearing but at least the SCD30 works very fine.
-
Now I will try to set the clock bus to 20K by using the (
Wire.setClock(20000);
).
- Nice both sensors are giving the needed data –> However I’m unable to read the TVOC sensor resistance but as long as the value of the TVOC is correct that is fine for now.
The code USED
/* Note this sensor is very very picky about I2C speed - it wants maximum 20KHz which is way
* below the standard 100KHz. Not all Arduino-compatible platforms successfully set the clock
* speed that low. We've tested this library with Atmega328 (Arduino UNO etc) and ESP32 sucessfully!
*/
#include "Adafruit_AGS02MA.h"
#include <Adafruit_SCD30.h>
Adafruit_AGS02MA ags;
Adafruit_SCD30 scd30;
void setup() {
Serial.begin(115200);
Serial.println(F("Adafruit AGS20MA Test"));
if (! ags.begin(&Wire, 0x1A)) {
// if (! ags.begin(&Wire1, 0x1A)) { // or use Wire1 instead!
Serial.println("Couldn't find AGS20MA sensor, check your wiring and pullup resistors!");
while (1) yield();
}
if (!scd30.begin()) {
Serial.println("Failed to find SCD30 chip");
while (1) { delay(10); }
}
Serial.println("SCD30 Found!");
/*if (ags.getFirmwareVersion() == 0) {
Serial.println(F("Could not read firmware, I2C communications issue?"));
while (1) yield();
}*/
Serial.print("Firmware version: 0x");
Serial.println(ags.getFirmwareVersion(), HEX);
ags.printSensorDetails();
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
Wire.setClock(20000);
// uncomment to change address, will need to restart and update the begin() argument!
//ags.setAddress(0x1A); while (1);
}
void loop() {
uint32_t resistance = ags.getGasResistance();
uint32_t tvoc = ags.getTVOC();
if (resistance == 0) {
Serial.println(F("Failure reading resistance, I2C communications issue?"));
} else {
float kohm = resistance / 1000.0;
Serial.print(F("Gas resistance: "));
Serial.print(kohm);
Serial.println(" Kohms");
}
if (tvoc == 0) {
Serial.println(F("Failure reading TVOC, I2C communications issue?"));
} else {
Serial.print(F("TVOC: "));
Serial.print(tvoc);
Serial.println(" ppb");
}
delay(2000);
s30();
}
void s30 (){
if (scd30.dataReady()){
Serial.println("Data available!");
if (!scd30.read()){ Serial.println("Error reading sensor data"); return; }
Serial.print("Temperature: ");
Serial.print(scd30.temperature);
Serial.println(" degrees C");
Serial.print("Relative Humidity: ");
Serial.print(scd30.relative_humidity);
Serial.println(" %");
Serial.print("CO2: ");
Serial.print(scd30.CO2, 3);
Serial.println(" ppm");
Serial.println("");
} else {
//Serial.println("No data");
}
delay(100);
}
- Great News I kept trying different bus speeds until the resistance worked.
I have set the bus to 16k speed.
Great at this point I have them both working together, –> Now is the moment of truth ; I have to build all of this on the XIAO.
I will do it all as it is but changing the UNO to My XIAO board and check.
- I will start by uploading the code first then I will change the connection.
I used the exact same code.
Alhamdollelah, All the sensors are tested and they are working as I want.
Now I will prepare the code to be then linked with one of the Platforms.