Fix capitalize folder and file name ignored

This commit is contained in:
Phat Nguyen
2024-02-17 17:28:51 +07:00
parent 781fb51c6f
commit 6cdbb8a0a3
24 changed files with 1469 additions and 0 deletions

164
src/PMS/PMS.cpp Normal file
View File

@ -0,0 +1,164 @@
#include "PMS.h"
bool PMS::begin(Stream *stream) {
_stream = stream;
DATA data;
if (readUntil(data, 5000)) {
return true;
}
return false;
}
// Standby mode. For low power consumption and prolong the life of the sensor.
void PMS::sleep() {
uint8_t command[] = {0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73};
_stream->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.
void PMS::wakeUp() {
uint8_t command[] = {0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74};
_stream->write(command, sizeof(command));
}
// Active mode. Default mode after power up. In this mode sensor would send
// serial data to the host automatically.
void PMS::activeMode() {
uint8_t command[] = {0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71};
_stream->write(command, sizeof(command));
_mode = MODE_ACTIVE;
}
// Passive mode. In this mode sensor would send serial data to the host only for
// request.
void PMS::passiveMode() {
uint8_t command[] = {0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70};
_stream->write(command, sizeof(command));
_mode = MODE_PASSIVE;
}
// Request read in Passive Mode.
void PMS::requestRead() {
if (_mode == MODE_PASSIVE) {
uint8_t command[] = {0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71};
_stream->write(command, sizeof(command));
}
}
// Non-blocking function for parse response.
bool PMS::read(DATA &data) {
_data = &data;
loop();
return _status == STATUS_OK;
}
// Blocking function for parse response. Default timeout is 1s.
bool PMS::readUntil(DATA &data, uint16_t timeout) {
_data = &data;
uint32_t start = millis();
do {
loop();
if (_status == STATUS_OK) {
break;
}
/** Relax task to avoid watchdog reset */
delay(1);
} while (millis() - start < timeout);
return _status == STATUS_OK;
}
void PMS::loop() {
_status = STATUS_WAITING;
if (_stream->available()) {
uint8_t ch = _stream->read();
switch (_index) {
case 0:
if (ch != 0x42) {
return;
}
_calculatedChecksum = ch;
break;
case 1:
if (ch != 0x4D) {
_index = 0;
return;
}
_calculatedChecksum += ch;
break;
case 2:
_calculatedChecksum += ch;
_frameLen = ch << 8;
break;
case 3:
_frameLen |= ch;
// Unsupported sensor, different frame length, transmission error e.t.c.
if (_frameLen != 2 * 9 + 2 && _frameLen != 2 * 13 + 2) {
_index = 0;
return;
}
_calculatedChecksum += ch;
break;
default:
if (_index == _frameLen + 2) {
_checksum = ch << 8;
} else if (_index == _frameLen + 2 + 1) {
_checksum |= ch;
if (_calculatedChecksum == _checksum) {
_status = STATUS_OK;
// Standard Particles, CF=1.
_data->PM_SP_UG_1_0 = makeWord(_payload[0], _payload[1]);
_data->PM_SP_UG_2_5 = makeWord(_payload[2], _payload[3]);
_data->PM_SP_UG_10_0 = makeWord(_payload[4], _payload[5]);
// Atmospheric Environment.
_data->PM_AE_UG_1_0 = makeWord(_payload[6], _payload[7]);
_data->PM_AE_UG_2_5 = makeWord(_payload[8], _payload[9]);
_data->PM_AE_UG_10_0 = makeWord(_payload[10], _payload[11]);
// Total particles count per 100ml air
_data->PM_RAW_0_3 = makeWord(_payload[12], _payload[13]);
_data->PM_RAW_0_5 = makeWord(_payload[14], _payload[15]);
_data->PM_RAW_1_0 = makeWord(_payload[16], _payload[17]);
_data->PM_RAW_2_5 = makeWord(_payload[18], _payload[19]);
_data->PM_RAW_5_0 = makeWord(_payload[20], _payload[21]);
_data->PM_RAW_10_0 = makeWord(_payload[22], _payload[23]);
// Formaldehyde concentration (PMSxxxxST units only)
_data->AMB_HCHO = makeWord(_payload[24], _payload[25]) / 1000;
// Temperature & humidity (PMSxxxxST units only)
_data->AMB_TMP = makeWord(_payload[20], _payload[21]);
_data->AMB_HUM = makeWord(_payload[22], _payload[23]);
}
_index = 0;
return;
} else {
_calculatedChecksum += ch;
uint8_t payloadIndex = _index - 4;
// Payload is common to all sensors (first 2x6 bytes).
if (payloadIndex < sizeof(_payload)) {
_payload[payloadIndex] = ch;
}
}
break;
}
_index++;
}
}

75
src/PMS/PMS.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _PMS_BASE_H_
#define _PMS_BASE_H_
#include <Arduino.h>
/**
* @brief Class define how to handle plantower PMS sensor it's upport for
* PMS5003 and PMS5003T series. The data @ref AMB_TMP and @ref AMB_HUM only
* valid on PMS5003T
*/
class PMS {
public:
static const uint16_t SINGLE_RESPONSE_TIME = 1000;
static const uint16_t TOTAL_RESPONSE_TIME = 1000 * 10;
static const uint16_t STEADY_RESPONSE_TIME = 1000 * 30;
// static const uint16_t BAUD_RATE = 9600;
struct DATA {
// Standard Particles, CF=1
uint16_t PM_SP_UG_1_0;
uint16_t PM_SP_UG_2_5;
uint16_t PM_SP_UG_10_0;
// Atmospheric environment
uint16_t PM_AE_UG_1_0;
uint16_t PM_AE_UG_2_5;
uint16_t PM_AE_UG_10_0;
// Raw particles count (number of particles in 0.1l of air
uint16_t PM_RAW_0_3;
uint16_t PM_RAW_0_5;
uint16_t PM_RAW_1_0;
uint16_t PM_RAW_2_5;
uint16_t PM_RAW_5_0;
uint16_t PM_RAW_10_0;
// Formaldehyde (HCHO) concentration in mg/m^3 - PMSxxxxST units only
uint16_t AMB_HCHO;
// Temperature & humidity - PMSxxxxST units only
int16_t AMB_TMP;
uint16_t AMB_HUM;
};
bool begin(Stream *stream);
void sleep();
void wakeUp();
void activeMode();
void passiveMode();
void requestRead();
bool read(DATA &data);
bool readUntil(DATA &data, uint16_t timeout = SINGLE_RESPONSE_TIME);
private:
enum STATUS { STATUS_WAITING, STATUS_OK };
enum MODE { MODE_ACTIVE, MODE_PASSIVE };
uint8_t _payload[50];
Stream *_stream;
DATA *_data;
STATUS _status;
MODE _mode = MODE_ACTIVE;
uint8_t _index = 0;
uint16_t _frameLen;
uint16_t _checksum;
uint16_t _calculatedChecksum;
void loop();
char Char_PM2[10];
};
#endif

188
src/PMS/PMS5003.cpp Normal file
View File

@ -0,0 +1,188 @@
#include "PMS5003.h"
#include "Arduino.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
/**
* @brief Init sensor
*
* @param _debugStream Serial use for print debug log
* @return true Success
* @return false Failure
*/
bool PMS5003::begin(Stream *_debugStream) {
this->_debugStream = _debugStream;
return this->begin();
}
#else
/**
* @brief Init Sensor
*
* @param serial Serial communication with sensor
* @return true Success
* @return false Failure
*/
bool PMS5003::begin(HardwareSerial &serial) {
this->_serial = &serial;
return this->begin();
}
#endif
/**
* @brief Construct a new PMS5003::PMS5003 object
*
* @param def Board type @ref BoardType
*/
PMS5003::PMS5003(BoardType def) : _boardDef(def) {}
/**
* @brief Init sensor
*
* @return true Success
* @return false Failure
*/
bool PMS5003::begin(void) {
if (this->_isBegin) {
AgLog("Initialized, call end() then try again");
return true;
}
#if defined(ESP32)
#endif
this->bsp = getBoardDef(this->_boardDef);
if (bsp == NULL) {
AgLog("Board [%d] not supported", this->_boardDef);
return false;
}
if (bsp->Pms5003.supported == false) {
AgLog("Board [%d] PMS50035003 not supported", this->_boardDef);
return false;
}
#if defined(ESP8266)
bsp->Pms5003.uart_tx_pin;
SoftwareSerial *uart = new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin);
uart->begin(9600);
if (pms.begin(uart) == false) {
AgLog("PMS failed");
return false;
}
#else
this->_serial->begin(9600);
if (pms.begin(this->_serial) == false) {
AgLog("PMS failed");
return false;
}
#endif
this->_isBegin = true;
return true;
}
/**
* @brief Convert PM2.5 to US AQI
*
* @param pm02
* @return int
*/
int PMS5003::pm25ToAQI(int pm02) {
if (pm02 <= 12.0)
return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
else if (pm02 <= 35.4)
return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
else if (pm02 <= 55.4)
return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
else if (pm02 <= 150.4)
return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
else if (pm02 <= 250.4)
return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
else if (pm02 <= 350.4)
return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
else if (pm02 <= 500.4)
return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
else
return 500;
}
/**
* @brief Read all package data then call to @ref getPMxxx to get the target
* data
*
* @return true Success
* @return false Failure
*/
bool PMS5003::readData(void) {
if (this->isBegin() == false) {
return false;
}
return pms.readUntil(pmsData);
}
/**
* @brief Read PM1.0 must call this function after @ref readData success
*
* @return int PM1.0 index
*/
int PMS5003::getPm01Ae(void) { return pmsData.PM_AE_UG_1_0; }
/**
* @brief Read PM2.5 must call this function after @ref readData success
*
* @return int PM2.5 index
*/
int PMS5003::getPm25Ae(void) { return pmsData.PM_AE_UG_2_5; }
/**
* @brief Read PM10.0 must call this function after @ref readData success
*
* @return int PM10.0 index
*/
int PMS5003::getPm10Ae(void) { return pmsData.PM_AE_UG_10_0; }
/**
* @brief Read PM3.0 must call this function after @ref readData success
*
* @return int PM3.0 index
*/
int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
/**
* @brief Convert PM2.5 to US AQI
*
* @param pm25 PM2.5 index
* @return int PM2.5 US AQI
*/
int PMS5003::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
/**
* @brief Check device initialized or not
*
* @return true Initialized
* @return false No-initialized
*/
bool PMS5003::isBegin(void) {
if (this->_isBegin == false) {
AgLog("Not-initialized");
return false;
}
return true;
}
/**
* @brief De-initialize sensor
*/
void PMS5003::end(void) {
if (_isBegin == false) {
return;
}
_isBegin = false;
#if defined(ESP8266)
_debugStream = NULL;
#else
delete _serial;
#endif
AgLog("De-initialize");
}

46
src/PMS/PMS5003.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef _AIR_GRADIENT_PMS5003_H_
#define _AIR_GRADIENT_PMS5003_H_
#include "../Main/BoardDef.h"
#include "Stream.h"
#include "PMS.h"
/**
* @brief The class define how to handle PMS5003 sensor bas on @ref PMS class
*/
class PMS5003 {
public:
PMS5003(BoardType def);
#if defined(ESP8266)
bool begin(Stream *_debugStream);
#else
bool begin(HardwareSerial &serial);
#endif
void end(void);
bool readData(void);
int getPm01Ae(void);
int getPm25Ae(void);
int getPm10Ae(void);
int getPm03ParticleCount(void);
int convertPm25ToUsAqi(int pm25);
private:
bool _isBegin = false;
BoardType _boardDef;
PMS pms;
const BoardDef *bsp;
#if defined(ESP8266)
Stream *_debugStream;
const char *TAG = "PMS5003";
#else
HardwareSerial *_serial;
#endif
// Conplug_PMS5003T *pms;
PMS::DATA pmsData;
bool begin(void);
bool isBegin(void);
int pm25ToAQI(int pm02);
};
#endif /** _AIR_GRADIENT_PMS5003_H_ */

236
src/PMS/PMS5003T.cpp Normal file
View File

@ -0,0 +1,236 @@
#include "PMS5003T.h"
#include "Arduino.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
/**
* @brief Init sensor
*
* @param _debugStream Serial use for print debug log
* @return true Success
* @return false Failure
*/
bool PMS5003T::begin(Stream *_debugStream) {
this->_debugStream = _debugStream;
return this->begin();
}
#else
/**
* @brief Init Sensor
*
* @param serial Serial communication with sensor
* @return true Success
* @return false Failure
*/
bool PMS5003T::begin(HardwareSerial &serial) {
this->_serial = &serial;
return this->begin();
}
#endif
/**
* @brief Construct a new PMS5003T::PMS5003T object
*
* @param def Board type @ref BoardType
*/
PMS5003T::PMS5003T(BoardType def) : _boardDef(def) {}
/**
* @brief Init sensor
*
* @return true Success
* @return false Failure
*/
bool PMS5003T::begin(void) {
if (this->_isBegin) {
return true;
}
#if defined(ESP32)
// if (this->_serial != &Serial) {
// AgLog("Hardware serial must be Serial(0)");
// return false;
// }
#endif
this->bsp = getBoardDef(this->_boardDef);
if (bsp == NULL) {
AgLog("Board [%d] not supported", this->_boardDef);
return false;
}
if (bsp->Pms5003.supported == false) {
AgLog("Board [%d] PMS5003 not supported", this->_boardDef);
return false;
}
#if defined(ESP8266)
bsp->Pms5003.uart_tx_pin;
SoftwareSerial *uart =
new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin);
uart->begin(9600);
if (pms.begin(uart) == false) {
AgLog("PMS failed");
return false;
}
#else
#if ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC
if (this->_serial == &Serial0) {
#else
if (this->_serial == &Serial) {
#endif
AgLog("Init Serial");
this->_serial->begin(9600, SERIAL_8N1, bsp->Pms5003.uart_rx_pin,
bsp->Pms5003.uart_tx_pin);
} else {
if (bsp->SenseAirS8.supported == false) {
AgLog("Board [%d] PMS5003T_2 not supported", this->_boardDef);
return false;
}
/** Share with sensor air s8*/
AgLog("Init Serialx");
this->_serial->begin(9600, SERIAL_8N1, bsp->SenseAirS8.uart_rx_pin,
bsp->SenseAirS8.uart_tx_pin);
}
if (pms.begin(this->_serial) == false) {
AgLog("PMS failed");
return false;
}
#endif
this->_isBegin = true;
return true;
}
/**
* @brief Convert PM2.5 to US AQI
*
* @param pm02
* @return int
*/
int PMS5003T::pm25ToAQI(int pm02) {
if (pm02 <= 12.0)
return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
else if (pm02 <= 35.4)
return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
else if (pm02 <= 55.4)
return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
else if (pm02 <= 150.4)
return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
else if (pm02 <= 250.4)
return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
else if (pm02 <= 350.4)
return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
else if (pm02 <= 500.4)
return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
else
return 500;
}
/**
* @brief Read all package data then call to @ref getPMxxx to get the target
* data
*
* @return true Success
* @return false Failure
*/
bool PMS5003T::readData(void) {
if (this->isBegin() == false) {
return false;
}
return pms.readUntil(pmsData);
}
/**
* @brief Read PM1.0 must call this function after @ref readData success
*
* @return int PM1.0 index
*/
int PMS5003T::getPm01Ae(void) { return pmsData.PM_AE_UG_1_0; }
/**
* @brief Read PM2.5 must call this function after @ref readData success
*
* @return int PM2.5 index
*/
int PMS5003T::getPm25Ae(void) { return pmsData.PM_AE_UG_2_5; }
/**
* @brief Read PM10.0 must call this function after @ref readData success
*
* @return int PM10.0 index
*/
int PMS5003T::getPm10Ae(void) { return pmsData.PM_AE_UG_10_0; }
/**
* @brief Read PM3.0 must call this function after @ref readData success
*
* @return int PM3.0 index
*/
int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; }
/**
* @brief Convert PM2.5 to US AQI
*
* @param pm25 PM2.5 index
* @return int PM2.5 US AQI
*/
int PMS5003T::convertPm25ToUsAqi(int pm25) { return this->pm25ToAQI(pm25); }
/**
* @brief Get temperature, Must call this method after @ref readData() success
*
* @return float Degree Celcius
*/
float PMS5003T::getTemperature(void) {
float temp = pmsData.AMB_TMP;
return correctionTemperature(temp / 10.0f);
}
/**
* @brief Get humidity, Must call this method after @ref readData() success
*
* @return float Percent (%)
*/
float PMS5003T::getRelativeHumidity(void) {
float temp = pmsData.AMB_HUM;
return temp / 10.0f;
}
/**
* @brief Check device initialized or not
*
* @return true Initialized
* @return false No-initialized
*/
bool PMS5003T::isBegin(void) {
if (this->_isBegin == false) {
AgLog("Not-initialized");
return false;
}
return true;
}
float PMS5003T::correctionTemperature(float inTemp) {
if (inTemp < 10.0f) {
return inTemp * 1.327f - 6.738f;
}
return inTemp * 1.181f - 5.113f;
}
void PMS5003T::end(void) {
if (_isBegin == false) {
return;
}
_isBegin = false;
#if defined(ESP8266)
_debugStream = NULL;
#else
delete _serial;
#endif
AgLog("De-initialize");
}

52
src/PMS/PMS5003T.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _PMS5003T_H_
#define _PMS5003T_H_
#include <HardwareSerial.h>
#include "../Main/BoardDef.h"
#include "PMS.h"
#include "Stream.h"
/**
* @brief The class define how to handle PMS5003T sensor bas on @ref PMS class
*/
class PMS5003T {
public:
PMS5003T(BoardType def);
#if defined(ESP8266)
bool begin(Stream *_debugStream);
#else
bool begin(HardwareSerial &serial);
#endif
void end(void);
bool readData(void);
int getPm01Ae(void);
int getPm25Ae(void);
int getPm10Ae(void);
int getPm03ParticleCount(void);
int convertPm25ToUsAqi(int pm25);
float getTemperature(void);
float getRelativeHumidity(void);
private:
bool _isBegin = false;
bool _isSleep = false;
BoardType _boardDef;
const BoardDef *bsp;
#if defined(ESP8266)
Stream *_debugStream;
const char *TAG = "PMS5003T";
#else
HardwareSerial *_serial;
#endif
bool begin(void);
int pm25ToAQI(int pm02);
PMS pms;
PMS::DATA pmsData;
bool isBegin(void);
float correctionTemperature(float inTemp);
};
#endif /** _PMS5003T_H_ */