Air quality sensor – first tests

Previously I wrote why I decided to measure the air quality in my neighborhood. Now I will focus on a technical aspect of the a PM sensor.
Firstly I had to choose the air quality sensor. Based on opinions and prices I chose the PMS3003. Additionally I assumed that the sensor will be sending a data using a WiFi connection. Since I had some experience in using WiFi modules, that’s why i took an ESP module.


If I do not care about delivery time I buy electronics on AliExpress. Delivery usually takes about 14-30 days, but prices are really low.

  • PMS3003 – a laser dust PM1.0, PM2.5 and PM10 sensor with built-in fan
  • ESP-12F – a WiFi module
  • LF33 – a 3.3 voltage regulator
  • a prototype board
  • a bunch of cables
  • an USB programator – I’am using the FT232 (about $5-6)
The PMS3003 air quality sensor
The PMS3003 air quality sensor

The PM sensor – How does it work?

The sensor use a light scattering process to measure particles. It has a laser diode as a near-infrared source of light. This kind of light is used to avoid interference with the day light. PMS module has a built-in fan which causes an air flow. When particles go through the detecting area the beam is diffracted onto particles along its path. The scattered light of the beam go to the sensor where is transformed into electrical signals which are amplified and processed. Next, the signal waveform is analysed to classify the particles by size.

The PMS 3003 air quality PM10 sensor air flow
The PMS 3003 air flow schema

WiFi connection

ESP modules are often used in IoT projects. They combine simplicity of usage with a low cost. Each module can connect to Wi-Fi 2.4 GHz b/g/n WPA/WPA2 protected networks. They have a integrated low power 32-bit MCU, 10-bit ADC and TCP/IP protocol stack. I worked with ESP modules earlier and I noticed that there is a lot of information and tutorials about how to use them which is really helpful. You can find many version of the ESP. In general the main difference is they have a various number of outputs. I chose to buy a few ESP-12 modules because I wanted to use an analog input in another project.

ESP-12F pins schema
Pins of the ESP-12F module

First test

The first delivered package contained the air quality sensor. I wanted to know if the sensor worked properly, before WiFi modules arrived. To do that I just connect it to Arduino and LCD.


  • PMS3003
  • Arduino UNO R3 (ATmega328)
  • LCD shield 2X16
  • Logic level converter (5V <-> 3.3V) *

* Arduino based on 5V logic. PMS3003 require 5V for power, but the working voltage is 3.3V. That’s why I needed logic level converter.

Air quality test parts
Parts used in first test of the air quality sensor


The PMS3003 sensor use the UART protocol, so I only need to connect RX/TX with TX/RX via the Logical level converter. Sensor’s power is provided from Arduino’s 5V pin.

Pins of the PMS3003 air quality sensor
Pins of the PMS3003 sensor


Below you can find the full connection schema.

PMS3003-Arduino schema of connections
PMS3003-Arduino schema of connections


The idea is simple – the program reads values of PM2.5 and PM10 from the sensor and then display them on the screen. To read values we should seek for 0x42 0x4d sequence of bytes. When we find them next bytes will have values we are looking for. Below you can find a table with schema of sensor’s data frame.


Byte buffer index Description
1 Constant value (0x42)
2 0 Constant value (0x4d)
3 1 Frame length
4 2
5 3 PM1.0 concentration unit (μg/m3)
6 4
7 5 PM2.5 concentration unit (μg/m3)
8 6
9 7 PM10 concentration unit (μg/m3)
10 8
11 9 PM1.0 concentration unit under atmospheric environment  (μg/m3)
12 10
13 11 PM2.5 concentration unit under atmospheric environment  (μg/m3)
14 12
15 13 PM10 concentration unit under atmospheric environment  (μg/m3)
16 14
17 15 reserved
18 16
19 17 reserved
20 18
21 19 reserved
22 20
23 21 Control sum
24 22

The program is listed below. Most important parts:

  • Line 10 – function that checks a sum control
  • Line 39 – frame’s first byte detection
  • Line 43 – second byte check
  • Lines 47,48 – read PM values
#include <LiquidCrystal.h>
#include <stdio.h>
#define N 23

char line1[16], line2[16];
unsigned char buffer [N];
int PM25 = 0, PM10 = 0;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  

bool checkValue(unsigned char *buf, int length)
  bool flag=0;
  int sum=0;

  for(int i=0; i<(length-2); i++)
  sum=sum + 0x42;
  if(sum == ((buf[length-2]<<8)+buf[length-1]))  
    sum = 0;
    flag = 1;
  return flag;

void setup() {

void loop() {
  char fel = 0x42;
  if(Serial.find(&fel, 1)) {

  if(buffer[0] == 0x4d)
        PM25=((buffer[5]<<8) + buffer[6]);
        PM10=((buffer[7]<<8) + buffer[8]);
		// rest of values (if you want to use it)
        //PM1=((buffer[3]<<8) + buffer[4]);
        //PM1a=((buffer[9]<<8) + buffer[10]);
        //PM25a=((buffer[11]<<8) + buffer[12]);
        //PM10a=((buffer[13]<<8) + buffer[14]);
  sprintf(line1,"PM2.5=%d ug/m3",PM25);
  sprintf(line2,"PM10=%d ug/m3",PM10);


Below you can find few examples of measurements just to show you how much the air in Poland can be polluted.

PM2.5 and PM10 concentration units on the 6 of January 2018
PM2.5 and PM10 concentration units on the 6 of January 2018
PM2.5 and PM10 concentration units on the 13 of January 2018
PM2.5 and PM10 concentration units on the 13 of January 2018
PM2.5 and PM10 concentration units on the 8 of February 2018
PM2.5 and PM10 concentration units on the 8 of February 2018

Be the first to comment

Leave a Reply

Your email address will not be published.