|
|
@ -1,5 +1,5 @@ |
|
|
|
// ----------------------------------------------------------------------------- |
|
|
|
// PMSX003 Dust Sensor |
|
|
|
// PMS Dust Sensor |
|
|
|
// Uses SoftwareSerial library |
|
|
|
// Contribution by Òscar Rovira López |
|
|
|
// Refine to support PMS5003T/PMS5003ST by Yonsm Guo |
|
|
@ -12,25 +12,16 @@ |
|
|
|
#include "Arduino.h" |
|
|
|
#include "BaseSensor.h" |
|
|
|
|
|
|
|
#include <PMS.h> |
|
|
|
#include <SoftwareSerial.h> |
|
|
|
|
|
|
|
// |
|
|
|
#define PMS_TYPE_X003 0 |
|
|
|
#define PMS_TYPE_X003_9 1 |
|
|
|
#define PMS_TYPE_5003T 2 |
|
|
|
#define PMS_TYPE_5003ST 3 |
|
|
|
// Type of sensor |
|
|
|
#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 |
|
|
|
// These should not be static, instead a setType method should be used to |
|
|
|
// dinamically choose the type of sensor... |
|
|
|
|
|
|
|
// [MAGIC][LEN][DATA9|13|17][SUM] |
|
|
|
#if PMS_TYPE == PMS_TYPE_5003ST |
|
|
@ -38,7 +29,7 @@ |
|
|
|
#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} |
|
|
|
#define PMS_SLOT_TYPES {MAGNITUDE_PM2dot5, MAGNITUDE_TEMPERATURE, MAGNITUDE_HUMIDITY, MAGNITUDE_HCHO} |
|
|
|
#elif PMS_TYPE == PMS_TYPE_5003T |
|
|
|
#define PMS_TYPE_NAME "PMS5003T" |
|
|
|
#define PMS_DATA_COUNT 13 |
|
|
@ -63,107 +54,112 @@ |
|
|
|
#define PMS_PAYLOAD_SIZE (PMS_DATA_COUNT * 2 + 2) |
|
|
|
|
|
|
|
|
|
|
|
// PMSX003 sensor utils |
|
|
|
// PMS 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("[SENSOR] %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); |
|
|
|
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("[SENSOR] %s: Payload size = %d\n", PMS_TYPE_NAME, size); |
|
|
|
//debugSend("[SENSOR] %s: Packet available = %d\n", PMS_TYPE_NAME, avail); |
|
|
|
#endif |
|
|
|
if (size != PMS_PAYLOAD_SIZE) |
|
|
|
{ |
|
|
|
#if SENSOR_DEBUG |
|
|
|
debugSend(("[SENSOR] %s: Payload size != %d \n"), PMS_TYPE_NAME, PMS_PAYLOAD_SIZE); |
|
|
|
#endif |
|
|
|
if (avail < PMS_PACKET_SIZE) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = 0; i < PMS_DATA_COUNT; i++) |
|
|
|
{ |
|
|
|
data[i] = read16(sum); |
|
|
|
if (_serial->read() == 0x42 && _serial->read() == 0x4D) { |
|
|
|
|
|
|
|
uint16_t sum = 0x42 + 0x4D; |
|
|
|
uint16_t size = read16(sum); |
|
|
|
#if SENSOR_DEBUG |
|
|
|
//debugSend(("[SENSOR] %s: data[%d] = %d\n"), PMS_TYPE_NAME, i, data[i]); |
|
|
|
debugSend("[SENSOR] %s: Payload size = %d\n", PMS_TYPE_NAME, size); |
|
|
|
#endif |
|
|
|
} |
|
|
|
if (size != PMS_PAYLOAD_SIZE) { |
|
|
|
#if SENSOR_DEBUG |
|
|
|
debugSend(("[SENSOR] %s: Payload size != %d \n"), PMS_TYPE_NAME, PMS_PAYLOAD_SIZE); |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
uint16_t checksum = read16(); |
|
|
|
#if SENSOR_DEBUG |
|
|
|
debugSend(("[SENSOR] %s: Sum=%04X, Checksum=%04X\n"), PMS_TYPE_NAME, sum, checksum); |
|
|
|
#endif |
|
|
|
if (sum == checksum) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
for (int i = 0; i < PMS_DATA_COUNT; i++) { |
|
|
|
data[i] = read16(sum); |
|
|
|
#if SENSOR_DEBUG |
|
|
|
//debugSend(("[SENSOR] %s: data[%d] = %d\n"), PMS_TYPE_NAME, i, data[i]); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
uint16_t checksum = read16(); |
|
|
|
#if SENSOR_DEBUG |
|
|
|
debugSend(("[SENSOR] %s: Sum=%04X, Checksum=%04X\n"), PMS_TYPE_NAME, sum, checksum); |
|
|
|
#endif |
|
|
|
if (sum == checksum) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
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; |
|
|
|
} |
|
|
|
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 { |
|
|
@ -313,6 +309,7 @@ class PMSX003Sensor : public BaseSensor, PMSX003 { |
|
|
|
#endif |
|
|
|
|
|
|
|
requestRead(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Current value for slot # index |
|
|
@ -326,9 +323,10 @@ class PMSX003Sensor : public BaseSensor, PMSX003 { |
|
|
|
unsigned long _startTime; |
|
|
|
double _slot_values[PMS_SLOT_COUNT] = {0}; |
|
|
|
|
|
|
|
#if PMS_SMART_SLEEP |
|
|
|
unsigned int _readCount = 0; |
|
|
|
#endif |
|
|
|
#if PMS_SMART_SLEEP |
|
|
|
unsigned int _readCount = 0; |
|
|
|
#endif |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
#endif // SENSOR_SUPPORT && PMSX003_SUPPORT |
|
|
|
#endif // SENSOR_SUPPORT && PMS_SUPPORT |