A low-cost, smart, indoor air quality monitor based on the SM300D2 sensor module, an ESP32 and ESPHome.io for use with Home Assistant.
The SM300D2 module provides the following sensors:
Sensor | Range | Accuracy |
---|---|---|
CO2 | 400 - 5000 ppm | ± 50ppm |
Formaldehyde | 1 - 1000 µg/m³ | ? |
TVOC | 0 - 2000 µg/m³ | Calculated |
PM2.5 | 5 - 100 µg/m³ | ± 10% |
PM10 | 5 - 100 µg/m³ | ± 10% |
Temperature | -40 to +125 °C | ± 0.5 °C |
Humidity | 0 - 100% | ± 3% |
It should be noted that the CO2 sensor is in fact an eCO2 (equivalent carbon dioxide) sensor, which means that the CO2 is not measured, but rather calculated (or approximated) from the TVOC reading.
- Easy setup/use
- Consistent values
- Inexpensive (when compared to getting each module seperately)
- No assembly necessary
- Relatively stable and accurate
Part | Price | Link |
---|---|---|
SM300D2 | ~ 40 € | Click me |
ESP32 Board | ~ 5 € | Click me |
Cables with JST connectors where included when ordering from above shop in late January 2021.
The SM300D2 module is connected to the ESP32 via UART. The interface on the SM300D2 module is defined as:
Pin | Name | Description |
---|---|---|
1 | 5V | Power |
2 | T(X)D | Data output |
3 | N/A | Not in use |
4 | G(N)D | Power ground |
The module uses:
- Baud rate: 9600
- Data bits: 8 bits
- Stop bit: 1 bit
- Check digit: None
To connect the module to the ESP32, I cut the included cable with the JST connector in half, and soldered female jumper wires onto it, including heatshrinks.
Connect the modules 5V to VIN on the ESP32, GND to GND, and the TD to the RX2 pin.
When connected to the UART the module provides outputs in the following format:
3C 02 08 FC 00 79 01 D7 00 13 00 22 1B 03 30 02 18
This output is generated so that:
- B01 - always 0x3C
- B02 - always 0x02
- B03 - eCO2 high byte
- B04 - eCO2 low byte
- B05 - eCH2O high byte
- B06 - eCH2O low byte
- B07 - TVOC high byte
- B08 - TVOC low byte
- B09 - PM2.5 high byte
- B10 - PM2.5 low byte
- B11 - PM10 high byte
- B12 - PM10 low byte
- B13 - Temperature pre-decimal
- B14 - Temperature decimal
- B15 - Humidity pre-decimal
- B16 - Humidity decimal
- B17 - Checksum
Following the above example output, the output needs to be interpreted like this:
- Calculate the checksum, to see if no transmission errors occured. Sum up all values except the checksum:
0x3C + 0x02 + 0x08 + 0xFC + 0x00 + 0x79 + 0x01 + 0xD7 + 0x00 + 0x13 + 0x00 + 0x22 + 0x1B + 0x03 + 0x30 + 0x02 = 0x18
and check if the check sum is equal to the sum. - Calculate CO2:
Byte03 * 256 + Byte04 = 0x08 * 256 + 0xFC = 2300
(ppm) - Calculate Formaldehyde:
Byte05 * 256 + Byte06 = 0x00 * 256 + 0x79 = 121
(µg/m³) - Calculate TVOC:
Byte07 * 256 + Byte08 = 0x01 * 256 + 0xD7 = 471
(µg/m³) - Calculate PM2.5:
Byte09 * 256 + Byte10 = 0x00 * 256 + 0x13 = 19
(µg/m³) - Calculate PM10:
Byte11 * 256 + Byte12 = 0x00 * 256 + 0x22 = 34
(µg/m³) - Temperature:
Byte13 + Byte14 * 0.1 = 0x1B + 0x03 * 0.1 = 27.3
(°C) - Humidity:
Byte15 + Byte16 * 0.1 = 0x30 + 0x02 * 0.1 = 48.2
(% RH)
The sensor module may be debugged and its values read, using any UART-capable device, such as a USB-TTL adapter or even an Arduino/Raspberry Pi. Hook up the 5V to the 5V of your adapter, GND to GND and TX of the module to the RX of the UART adapter.
The serial connection tool minicom
may be used for displaying the values, make sure to set the correct baud rate and stop and parity settings. Sample command:
minicom --device /dev/cu.usbserial-141220 -H -w
Use the -H
flag to enable hex output and the -w
flag to enable automatic line wrap.
Furthermore, this repository includes a Python script which can be used to debug the module on your device.
In order to debug the actual air quality values and see actual changes there are some options available. I tried flooding the sensor with a CO2 bottle (Sodastream) but that didn't do much, because the sensor does not detect CO2 directly but calculates its value. What works way better is using a pen with solvents like a Sharpie, Edding or other permanent markers and waving it near the sensors and above the fan. You'll see within about 30 seconds the values will go through the roof, e.g. CO2 will be up to 1700ppm to 2000ppm. Then you'll know your sensor is working.
The SM300D2 module (or rather its onboard sensors) needs some time (at least 48h of continued use) to "burn in" before reporting correct values. For example, right after unboxing, the module reported an indoor temperature of 26.5 °C - well above any other thermometer which all claimed the correct 22.5 °C. After 5 hours the module already showed a more accurate reading of 23.5 °C (without an actual temperature change).
I've noticed there are some newer versions of this sensors available via Aliexpress. They seem to be designed by the same manufacturing company, judging by their UART output description which stayed more or less the same. I've found three new models with model codes:
- SM400D2
- SM400D2MOD
- MAQ7A-US
Should anyone have any of these devices I'd be interested in their review. Feel free to open an issue here.
Following values are considered acceptable for private, indoor air.
- CO2 should be lower than 1000 ppm (Source)
- Formaldehyde should be lower than 50 µg/m³ (Source)
- TVOC recommended levels will need to be analysed.
- PM2.5 should be lower than 25 µg/m³ (Source)
- PM10 should be lower than 50 µg/m³ (Source)
- Temperature should be between 18 and 24 °C (Source)
- Humidity should be between 30 and 50 % RH (Source)
These values should be read as suggestions for long-term indoor exposure.
This hardware/software product is only for private use. No medical advice is given whatsoever. Please consult your doctor first. This is only for information purposes. I am not affiliated with any shops/websites/vendors/hardware producers whatsoever.