PMSerial
Arduino library for PM sensors with serial interface
Sensors
Plantower | Tested Works | Doesn't Work | Not Tested | Datasheet | Notes |
---|---|---|---|---|---|
PMS1003 (aka G1) | X | en, cn | |||
PMS3003 (aka G3) | X | en, cn | No passive mode read | ||
PMS5003 (aka G5) | X | en, cn | |||
PMS5003S (aka G5S) | X | cn | |||
PMS5003T (aka G5T) | X | ||||
PMS5003ST (aka G5ST) | X | ||||
PMS7003 (aka G7) | X | cn | |||
PMSA003 (aka G10) | X | cn |
Compatibility
MCU | Tested Works | Doesn't Work | Not Tested | Examples | Notes |
---|---|---|---|---|---|
ATmega168 @ 8MHz | X | SoftwareSerial | |||
Atmega168 @ 16MHz | X | 5V boards need 3.3V/5V level shifter | |||
Atmega328 @ 8MHz | X | SoftwareSerial | |||
Atmega328 @ 16MHz | X | 5V boards need 3.3V/5V level shifter | |||
Atmega32u4 @ 8MHz | X | ||||
Atmega32u4 @ 16MHz | X | HardwareSerial | 5V boards need 3.3V/5V level shifter | ||
Atmega2560 @ 16MHz | X | HardwareSerial | 5V boards need 3.3V/5V level shifter | ||
STM32f103c8 | X | HardwareSerial | |||
STM32f103cb | X | HardwareSerial | |||
ESP8266 | X | HardwareSerial SoftwareSerial OLED 64x48 | needs EspSoftwareSerial@>=6.7.1 | ||
ESP32 | X | HardwareSerial SoftwareSerial OLED 64x48 | Serial1 as SoftwareSerial |
Usage
PMSx003
sensor type
The PMSx003
sensor type will infer the sensor type from the message header.
The sensor type inference does not cover the PMS5003S
and PMS5003T
variants, see #10.
PMS5003S
and PMS5003T
sensors need to be declared explicitly on the SerialPM
constructor.
PMSx003 on HardwareSerial
#include <PMserial.h>
SerialPM pms(PMSx003, Serial); // PMSx003, UART
void setup() {
Serial.begin(9600);
pms.init(); // config serial port
}
void loop() {
pms.read(); // read the PM sensor
Serial.print(F("PM1.0 "));Serial.print(pms.pm01);Serial.print(F(", "));
Serial.print(F("PM2.5 "));Serial.print(pms.pm25);Serial.print(F(", "));
Serial.print(F("PM10 ")) ;Serial.print(pms.pm10);Serial.println(F(" [ug/m3]"));
delay(10000); // wait for 10 seconds
}
Setup for different MCU is covered on the HardwareSerial example.
PMSx003 on SoftwareSerial
#include <PMserial.h>
SerialPM pms(PMSx003, 10, 11); // PMSx003, RX, TX
void setup() {
Serial.begin(9600);
pms.init(); // config serial port
}
void loop() {
pms.read(); // read the PM sensor
Serial.print(F("PM1.0 "));Serial.print(pms.pm01);Serial.print(F(", "));
Serial.print(F("PM2.5 "));Serial.print(pms.pm25);Serial.print(F(", "));
Serial.print(F("PM10 ")) ;Serial.print(pms.pm10);Serial.println(F(" [ug/m3]"));
delay(10000); // wait for 10 seconds
}
Setup for different MCU is covered on the SoftwareSerial example.
ESP32 Serial1
On some ESP32 boards Serial1 default pins are connected to the flash. Using the standard constructor will cause a crash, see espressif/arduino-esp32#148.
// will crash the ESP32
SerialPM pms(PMSx003, Serial1);
Fortunately, it is possible to define alternative for pins by calling:
// define Serial1 pins
Serial1.begin(9600, SERIAL_8N1, <RX>, <TX>);
The PMSerial library uses this feature to implement the flexibility of SoftwareSerial
// define Serial1 pins
SerialPM pms(PMSx003, <RX>, <TX>);
The SoftwareSerial example uses Serial1 on pins 23 (RX) and 19 (TX). The HardwareSerial example uses Serial2.
Advanced usage
Sensor message/protocol
With the exemption of the PMS3003
and PMS5003ST
, all supported sensors
transmit particulate matter (PM) and number concentrations (NC)
measurements in a 32 byte long message.
The PMS3003
only transmit PM measurements in a 24 byte message.
The PMS5003ST
transmit PM, NC, temperature (T), relative humidity (RH) and formaldehyde concentration (HCHO) measurements
on a 40 byte message.
On the examples, the PMSx003
sensor type will infer the sensor type from the message header
and select the message length and decoding protocol accordingly.
The supported protocols are:
message/protocol | length | PM | NC | T & RH | HCHO | sensors (aliases) |
---|---|---|---|---|---|---|
PLANTOWER_AUTO |
self discovery | 3 | auto | PMSx003 |
||
PLANTOWER_24B |
24 bytes | 3 | PMS3003 |
|||
PLANTOWER_32B |
32 bytes | 3 | 6 | PMS1003 , PMS5003 , PMS7003 , PMSA003 |
||
PLANTOWER_32B_S |
32 bytes | 3 | 6 | X | PMS5003S , can not be self discovered |
|
PLANTOWER_32B_T |
32 bytes | 3 | 4 | X | PMS5003T , can not be self discovered |
|
PLANTOWER_40B |
40 bytes | 3 | 6 | X | X | PMS5003ST |
Additional measurements
The pms.read()
method will request a new measurement set from the sensor and decode the sensor message.
The has_particulate_matter()
/has_number_concentration()
methods indicate if the message was valid
and PM/NC measurements were successfully decoded.
Similarly the has_temperature_humidity
/has_formaldehyde
methods indicate if the message was valid
and T & RH/HCHO measurements were successfully decoded, however
this kind of additional measurements are only available on PMS5003S
, PMS5003T
and PMS5003ST
sensors.
Decoded measurements
All measurements found in the sensor message will be decoded and stored in following member variables:
variable | type[len] | measurement | particle diameter | unit | Notes |
---|---|---|---|---|---|
pm01 |
uint16_t |
PM | <= 1.0 µm | µg/m³ | PM1.0, ultra fine particles |
pm25 |
uint16_t |
PM | <= 2.5 µm | µg/m³ | PM2.5, fine particles |
pm10 |
uint16_t |
PM | <= 10 µm | µg/m³ | PM10 |
n0p3 |
uint16_t |
NC | >= 0.3 µm | #/100 cm³ | |
n0p5 |
uint16_t |
NC | >= 0.5 µm | #/100 cm³ | |
n1p0 |
uint16_t |
NC | >= 1.0 µm | #/100 cm³ | |
n2p5 |
uint16_t |
NC | >= 2.5 µm | #/100 cm³ | |
n5p0 |
uint16_t |
NC | >= 5.0 µm | #/100 cm³ | |
n10p0 |
uint16_t |
NC | >= 10 µm | #/100 cm³ | |
pm |
uint16_t[3] |
PM | <= 1,2.5,10 µm | µg/m³ | array containing pm01,pm25,pm10 |
nc |
uint16_t[6] |
NC | >= 0.3,0.5,1,5,10 µm | #/100cm³ | array containing n0p3,..,n10p0 |
data |
uint16_t[9] |
PM/NC | all PM/NC data pm01,..,n10p0 |
||
temp |
float |
T | °C | temperature | |
rhum |
float |
RH | % | relative humidity | |
hcho |
float |
HCHO | mg/m³ | formaldehyde concentration | |
extra |
float[3] |
T/RH/HCHO | array containing temp,rhum,hcho |
For an efficient use of memory, the data
, pm
and nc
arrays and the
individual measurement variables are implemented with a union/struct combination.
See the examples for an full PM/NC output.
Status and error codes
The pms.status
member variable contains the status and eventual error code
resulting from the last sensor read.
The available status/error codes and pre-defined error messages are:
status/error code | error message | pre-defined text |
---|---|---|
pms.OK |
||
pms.ERROR_TIMEOUT |
PMS_ERROR_TIMEOUT |
"Sensor read timeout" |
pms.ERROR_PMS_TYPE |
PMS_ERROR_PMS_TYPE |
"Wrong PMSx003 sensor type" |
pms.ERROR_MSG_UNKNOWN |
PMS_ERROR_MSG_UNKNOWN |
"Unknown message protocol" |
pms.ERROR_MSG_HEADER |
PMS_ERROR_MSG_HEADER |
"Incomplete message header" |
pms.ERROR_MSG_BODY |
PMS_ERROR_MSG_BODY |
"Incomplete message body" |
pms.ERROR_MSG_START |
PMS_ERROR_MSG_START |
"Wrong message start" |
pms.ERROR_MSG_LENGTH |
PMS_ERROR_MSG_LENGTH |
"Message too long" |
pms.ERROR_MSG_CKSUM |
PMS_ERROR_MSG_CKSUM |
"Wrong message checksum" |
For easy of use, the error message are pre-defined with #define
.
See the examples for error handling implementation.
Temperature and humidity offset correction (Optional)
Some sensors have a small deviation with temperature and humidity readings. The compensate is possible with a correction offset defined by set_temp_offset() and set_rhum_offset(). The result will be reading + offset. Default offset values are O.
Example:
set_temp_offset(-0.6);
set_rhum_offset(2);
Contribute
If you have read this far, this is the library for your project or you can not figure out how to use it. In any case, I can use your help.
If you find any typos or something is not clear, please go to issue #3 and leave a message. Reopen the issue if needed.
If you want something a bit more challenging. I would appreciate more example projects. See issue #4 for inspiration. PRs are welcomed.
Changelog
- 1.1.1
- 1.1.0
- 1.0.1
- Fix broken SoftwareSerial for ESP8266, #6
- ESP8266 use EspSoftwareSerial@>=6.7.1
- 1.0.0
- first complete release