@ -14,7 +14,158 @@
# include <PMS.h>
# include <SoftwareSerial.h>
class PMSX003Sensor : public BaseSensor {
/ /
# define PMS_TYPE_X003 0
# define PMS_TYPE_X003_9 1
# define PMS_TYPE_5003T 2
# define PMS_TYPE_5003ST 3
# ifndef PMS_TYPE
# define PMS_TYPE PMS_TYPE_X003
# endif
/ / You can enable smart sleep ( read 6 - times then sleep on 24 - reading - cycles ) to extend PMS sensor ' s life .
/ / Otherwise the default lifetime of PMS sensor is about 8000 - hours / 1 - years .
/ / The PMS ' s fan will stop working on sleeping cycle , and will wake up on reading cycle .
# ifndef PMS_SMART_SLEEP
# define PMS_SMART_SLEEP 0
# endif
/ / [ MAGIC ] [ LEN ] [ DATA9 | 13 | 17 ] [ SUM ]
# if PMS_TYPE == PMS_TYPE_5003ST
# define PMS_TYPE_NAME "PMS5003ST"
# define PMS_DATA_COUNT 17
# define PMS_SLOT_COUNT 4
# define PMS_SLOT_NAMES {"PM2.5", "TEMP", "HUMI", "HCHO"}
# define PMS_SLOT_TYPES {MAGNITUDE_PM2dot5, MAGNITUDE_TEMPERATURE, MAGNITUDE_HUMIDITY, MAGNITUDE_ANALOG}
# elif PMS_TYPE == PMS_TYPE_5003T
# define PMS_TYPE_NAME "PMS5003T"
# define PMS_DATA_COUNT 13
# define PMS_SLOT_COUNT 3
# define PMS_SLOT_NAMES {"PM2.5", "TEMP", "HUMI"}
# define PMS_SLOT_TYPES {MAGNITUDE_PM2dot5, MAGNITUDE_TEMPERATURE, MAGNITUDE_HUMIDITY}
# elif PMS_TYPE == PMS_TYPE_X003_9
# define PMS_TYPE_NAME "PMSX003_9"
# define PMS_DATA_COUNT 9
# define PMS_SLOT_COUNT 3
# define PMS_SLOT_NAMES {"PM1.0", "PM2.5", "PM10"}
# define PMS_SLOT_TYPES {MAGNITUDE_PM1dot0, MAGNITUDE_PM2dot5, MAGNITUDE_PM10}
# else
# define PMS_TYPE_NAME "PMSX003"
# define PMS_DATA_COUNT 13
# define PMS_SLOT_COUNT 3
# define PMS_SLOT_NAMES {"PM1.0", "PM2.5", "PM10"}
# define PMS_SLOT_TYPES {MAGNITUDE_PM1dot0, MAGNITUDE_PM2dot5, MAGNITUDE_PM10}
# endif
# define PMS_PACKET_SIZE ((PMS_DATA_COUNT + 3) * 2)
# define PMS_PAYLOAD_SIZE (PMS_DATA_COUNT * 2 + 2)
/ / PMSX003 sensor utils
/ / Command functions copied from : https : / / github . com / fu - hsi / PMS / blob / master / src / PMS . cpp
/ / Reading function is rewrited to support flexible reading for PMS5003T / PMS5003ST
class PMSX003 {
protected :
SoftwareSerial * _serial = NULL ; / / Should initialized by child class
public :
/ / Standby mode . For low power consumption and prolong the life of the sensor .
inline void sleep ( ) {
uint8_t command [ ] = { 0x42 , 0x4D , 0xE4 , 0x00 , 0x00 , 0x01 , 0x73 } ;
_serial - > write ( command , sizeof ( command ) ) ;
}
/ / Operating mode . Stable data should be got at least 30 seconds after the sensor wakeup from the sleep mode because of the fan ' s performance .
inline void wakeUp ( ) {
uint8_t command [ ] = { 0x42 , 0x4D , 0xE4 , 0x00 , 0x01 , 0x01 , 0x74 } ;
_serial - > write ( command , sizeof ( command ) ) ;
}
/ / Active mode . Default mode after power up . In this mode sensor would send serial data to the host automatically .
inline void activeMode ( ) {
uint8_t command [ ] = { 0x42 , 0x4D , 0xE1 , 0x00 , 0x01 , 0x01 , 0x71 } ;
_serial - > write ( command , sizeof ( command ) ) ;
}
/ / Passive mode . In this mode , sensor would send serial data to the host only for request .
inline void passiveMode ( ) {
uint8_t command [ ] = { 0x42 , 0x4D , 0xE1 , 0x00 , 0x00 , 0x01 , 0x70 } ;
_serial - > write ( command , sizeof ( command ) ) ;
}
/ / Request read , ONLY needed in Passive Mode ! !
inline void requestRead ( ) {
uint8_t command [ ] = { 0x42 , 0x4D , 0xE2 , 0x00 , 0x00 , 0x01 , 0x71 } ;
_serial - > write ( command , sizeof ( command ) ) ;
}
/ / Read sensor ' s data
bool readData ( uint16_t data [ PMS_DATA_COUNT ] ) {
do
{
int avail = _serial - > available ( ) ;
# if SENSOR_DEBUG
/ / debugSend ( " %s: Packet available = %d \n " , PMS_TYPE_NAME , avail ) ;
# endif
if ( avail < PMS_PACKET_SIZE )
break ;
if ( _serial - > read ( ) = = 0x42 & & _serial - > read ( ) = = 0x4D )
{
uint16_t sum = 0x42 + 0x4D ;
uint16_t size = read16 ( sum ) ;
# if SENSOR_DEBUG
debugSend ( " %s: Payload size = %d \n " , PMS_TYPE_NAME , size ) ;
# endif
if ( size ! = PMS_PAYLOAD_SIZE )
{
# if SENSOR_DEBUG
debugSend ( ( " %s: Payload size != %d \n " ) , PMS_TYPE_NAME , PMS_PAYLOAD_SIZE ) ;
# endif
break ;
}
for ( int i = 0 ; i < PMS_DATA_COUNT ; i + + )
{
data [ i ] = read16 ( sum ) ;
# if SENSOR_DEBUG
/ / debugSend ( ( " %s: data[%d] = %d \n " ) , PMS_TYPE_NAME , i , data [ i ] ) ;
# endif
}
uint16_t checksum = read16 ( ) ;
# if SENSOR_DEBUG
debugSend ( ( " %s: Sum=%04X, Checksum=%04X \n " ) , PMS_TYPE_NAME , sum , checksum ) ;
# endif
if ( sum = = checksum )
{
return true ;
}
break ;
}
}
while ( true ) ;
return false ;
}
private :
/ / Read 16 - bit
inline uint16_t read16 ( ) {
return ( ( uint16_t ) _serial - > read ( ) ) < < 8 | _serial - > read ( ) ;
}
/ / Read 16 - bit and calculate checksum
uint16_t read16 ( uint16_t & checksum ) {
uint8_t high = _serial - > read ( ) ;
uint8_t low = _serial - > read ( ) ;
checksum + = high ;
checksum + = low ;
return ( ( uint16_t ) high ) < < 8 | low ;
}
} ;
class PMSX003Sensor : public BaseSensor , PMSX003 {
public :
@ -23,13 +174,12 @@ class PMSX003Sensor : public BaseSensor {
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PMSX003Sensor ( ) : BaseSensor ( ) {
_count = 3 ;
_count = PMS_SLOT_COUNT ;
_sensor_id = SENSOR_PMSX003_ID ;
}
~ PMSX003Sensor ( ) {
if ( _serial ) delete _serial ;
if ( _pms ) delete _pms ;
}
void setRX ( unsigned char pin_rx ) {
@ -64,13 +214,12 @@ class PMSX003Sensor : public BaseSensor {
if ( ! _dirty ) return ;
if ( _serial ) delete _serial ;
if ( _pms ) delete _pms ;
_serial = new SoftwareSerial ( _pin_rx , _pin_tx , false , 32 ) ;
_serial = new SoftwareSerial ( _pin_rx , _pin_tx , false , 64 ) ;
_serial - > enableIntTx ( false ) ;
_serial - > begin ( 9600 ) ;
_pms = new PMS ( * _serial ) ;
_pms - > passiveMode ( ) ;
/ / _serial - > enableRx ( true ) ; / / TODO : Test
passiveMode ( ) ;
_startTime = millis ( ) ;
_ready = true ;
@ -81,16 +230,15 @@ class PMSX003Sensor : public BaseSensor {
/ / Descriptive name of the sensor
String description ( ) {
char buffer [ 28 ] ;
snprintf ( buffer , sizeof ( buffer ) , " PMSX003 @ SwSerial(%u,%u) " , _pin_rx , _pin_tx ) ;
snprintf ( buffer , sizeof ( buffer ) , " %s @ SwSerial(%u,%u) " , PMS_TYPE_NAME , _pin_rx , _pin_tx ) ;
return String ( buffer ) ;
}
/ / Descriptive name of the slot # index
String slot ( unsigned char index ) {
char buffer [ 36 ] = { 0 } ;
if ( index = = 0 ) snprintf ( buffer , sizeof ( buffer ) , " PM1.0 @ PMSX003 @ SwSerial(%u,%u) " , _pin_rx , _pin_tx ) ;
if ( index = = 1 ) snprintf ( buffer , sizeof ( buffer ) , " PM2.5 @ PMSX003 @ SwSerial(%u,%u) " , _pin_rx , _pin_tx ) ;
if ( index = = 2 ) snprintf ( buffer , sizeof ( buffer ) , " PM10 @ PMSX003 @ SwSerial(%u,%u) " , _pin_rx , _pin_tx ) ;
const static char * _slot_names [ ] = PMS_SLOT_NAMES ;
snprintf ( buffer , sizeof ( buffer ) , " %s @ %s @ SwSerial(%u,%u) " , _slot_names [ index ] , PMS_TYPE_NAME , _pin_rx , _pin_tx ) ;
return String ( buffer ) ;
}
@ -103,10 +251,8 @@ class PMSX003Sensor : public BaseSensor {
/ / Type for slot # index
unsigned char type ( unsigned char index ) {
if ( index = = 0 ) return MAGNITUDE_PM1dot0 ;
if ( index = = 1 ) return MAGNITUDE_PM2dot5 ;
if ( index = = 2 ) return MAGNITUDE_PM10 ;
return MAGNITUDE_NONE ;
const static unsigned char _slot_types [ ] = PMS_SLOT_TYPES ;
return _slot_types [ index ] ;
}
void pre ( ) {
@ -118,35 +264,71 @@ class PMSX003Sensor : public BaseSensor {
_error = SENSOR_ERROR_OK ;
if ( _pms - > read ( _data ) ) {
_pm1dot0 = _data . PM_AE_UG_1_0 ;
_pm2dot5 = _data . PM_AE_UG_2_5 ;
_pm10 = _data . PM_AE_UG_10_0 ;
# if PMS_SMART_SLEEP
unsigned int readCycle ;
if ( _readCount + + > 30 ) {
readCycle = _readCount % 30 ;
if ( readCycle = = 0 ) {
# if SENSOR_DEBUG
debugSend ( " %s: Wake up: %d \n " , PMS_TYPE_NAME , _readCount ) ;
# endif
wakeUp ( ) ;
return ;
} else if ( readCycle = = 1 ) {
requestRead ( ) ;
} else if ( readCycle > 6 ) {
return ;
}
} else {
readCycle = - 1 ;
}
# endif
uint16_t data [ PMS_DATA_COUNT ] ;
if ( readData ( data ) ) {
# if PMS_TYPE == PMS_TYPE_5003ST
_slot_values [ 0 ] = data [ 4 ] ;
_slot_values [ 1 ] = ( double ) data [ 13 ] / 10 ;
_slot_values [ 2 ] = ( double ) data [ 14 ] / 10 ;
_slot_values [ 3 ] = ( double ) data [ 12 ] / 1000 ;
# elif PMS_TYPE == PMS_TYPE_5003T
_slot_values [ 0 ] = data [ 4 ] ;
_slot_values [ 1 ] = ( double ) data [ 10 ] / 10 ;
_slot_values [ 2 ] = ( double ) data [ 11 ] / 10 ;
# else
_slot_values [ 0 ] = data [ 3 ] ;
_slot_values [ 1 ] = data [ 4 ] ;
_slot_values [ 2 ] = data [ 5 ] ;
# endif
}
_pms - > requestRead ( ) ;
# if PMS_SMART_SLEEP
if ( readCycle = = 6 ) {
sleep ( ) ;
# if SENSOR_DEBUG
debugSend ( " %s: Enter sleep mode: %d \n " , PMS_TYPE_NAME , _readCount ) ;
# endif
return ;
}
# endif
requestRead ( ) ;
}
/ / Current value for slot # index
double value ( unsigned char index ) {
if ( index = = 0 ) return _pm1dot0 ;
if ( index = = 1 ) return _pm2dot5 ;
if ( index = = 2 ) return _pm10 ;
return 0 ;
return _slot_values [ index ] ;
}
protected :
unsigned int _pm1dot0 ;
unsigned int _pm2dot5 ;
unsigned int _pm10 ;
unsigned int _pin_rx ;
unsigned int _pin_tx ;
unsigned long _startTime ;
SoftwareSerial * _serial = NULL ;
PMS * _pms = NULL ;
PMS : : DATA _data ;
double _slot_values [ PMS_SLOT_COUNT ] = { 0 } ;
# if PMS_SMART_SLEEP
unsigned int _readCount = 0 ;
# endif
} ;
# endif / / SENSOR_SUPPORT && PMSX003_SUPPORT