From 21232ec49d1bdd32d3ca37e8e9575613fa5dcbe9 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 14 Sep 2024 14:05:35 +0700 Subject: [PATCH 1/9] Optimize PMS sensor read data on active mode send each second --- examples/OneOpenAir/OneOpenAir.ino | 11 +- src/PMS/PMS.cpp | 235 +++++++++++++---------------- src/PMS/PMS.h | 41 +++-- src/PMS/PMS5003.cpp | 20 +-- src/PMS/PMS5003.h | 2 +- src/PMS/PMS5003T.cpp | 20 +-- src/PMS/PMS5003T.h | 2 +- 7 files changed, 169 insertions(+), 162 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index ee7314e7..45ab1c12 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -288,6 +288,11 @@ void loop() { if (ag->isOne()) { if (configuration.hasSensorPMS1) { ag->pms5003.handle(); + static bool pmsConnected = false; + if (pmsConnected != ag->pms5003.connected()) { + pmsConnected = ag->pms5003.connected(); + Serial.printf("PMS sensor %s ", pmsConnected?"connected":"removed"); + } } } else { if (configuration.hasSensorPMS1) { @@ -1009,7 +1014,7 @@ static void updateTvoc(void) { static void updatePm(void) { bool restart = false; if (ag->isOne()) { - if (ag->pms5003.isFailed() == false) { + if (ag->pms5003.connected()) { measurements.pm01_1 = ag->pms5003.getPm01Ae(); measurements.pm25_1 = ag->pms5003.getPm25Ae(); measurements.pm10_1 = ag->pms5003.getPm10Ae(); @@ -1038,7 +1043,7 @@ static void updatePm(void) { } else { bool pmsResult_1 = false; bool pmsResult_2 = false; - if (configuration.hasSensorPMS1 && (ag->pms5003t_1.isFailed() == false)) { + if (configuration.hasSensorPMS1 && ag->pms5003t_1.connected()) { measurements.pm01_1 = ag->pms5003t_1.getPm01Ae(); measurements.pm25_1 = ag->pms5003t_1.getPm25Ae(); measurements.pm10_1 = ag->pms5003t_1.getPm10Ae(); @@ -1081,7 +1086,7 @@ static void updatePm(void) { } } - if (configuration.hasSensorPMS2 && (ag->pms5003t_2.isFailed() == false)) { + if (configuration.hasSensorPMS2 && ag->pms5003t_2.connected()) { measurements.pm01_2 = ag->pms5003t_2.getPm01Ae(); measurements.pm25_2 = ag->pms5003t_2.getPm25Ae(); measurements.pm10_2 = ag->pms5003t_2.getPm10Ae(); diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 11071856..9fefb553 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -8,146 +8,111 @@ * @return true Sucecss * @return false Failure */ -bool PMSBase::begin(Stream *stream) { - this->stream = stream; - - failed = true; +bool PMSBase::begin(HardwareSerial& serial) { failCount = 0; - lastRead = 0; // To read buffer on handle without wait after 1.5sec - - this->stream->flush(); + _connected = false; // Run and check sensor data for 4sec - while (1) { - handle(); - if (failed == false) { - return true; + serial.flush(); + + unsigned long lastInit = millis(); + while (true) { + readPackage(serial); + if (_connected) { + break; } delay(1); - uint32_t ms = (uint32_t)(millis() - lastRead); + unsigned long ms = (unsigned long)(millis() - lastInit); if (ms >= 4000) { break; } } - return false; + return _connected; } /** - * @brief Check and read sensor data then update variable. - * Check result from method @isFailed before get value + * @brief Read PMS package send to device each 1sec + * + * @param serial */ -void PMSBase::handle() { - uint32_t ms; - if (lastRead == 0) { - lastRead = millis(); - if (lastRead == 0) { - lastRead = 1; - } - } else { - ms = (uint32_t)(millis() - lastRead); - /** - * The PMS in Active mode sends an update data every 1 second. If we read - * exactly every 1 sec then we may or may not get an update (depending on - * timing tolerances). Hence we read every 2.5 seconds and expect 2 ..3 - * updates, - */ - if (ms < 2500) { - return; - } - } - bool result = false; - char buf[32]; - int bufIndex; - int step = 0; - int len = 0; - int bcount = 0; - - while (stream->available()) { - char value = stream->read(); - switch (step) { - case 0: { +void PMSBase::readPackage(HardwareSerial& serial) { + uint8_t delayCount = 0; + while (serial.available()) { + /** Get value */ + uint8_t value = (uint8_t)serial.read(); + + /** Process receiving package... */ + switch (readBufferIndex) { + case 0: /** Start byte 1 */ if (value == 0x42) { - step = 1; - bufIndex = 0; - buf[bufIndex++] = value; + readBuffer[readBufferIndex++] = value; } break; - } - case 1: { + case 1: /** Start byte 2 */ if (value == 0x4d) { - step = 2; - buf[bufIndex++] = value; - // Serial.println("Got 0x4d"); + readBuffer[readBufferIndex++] = value; } else { - step = 0; + readBufferIndex = 0; } break; - } - case 2: { - buf[bufIndex++] = value; - if (bufIndex >= 4) { - len = toI16(&buf[2]); - if (len != 28) { - // Serial.printf("Got good bad len %d\r\n", len); - len += 4; - step = 3; - } else { - // Serial.println("Got good len"); - step = 4; - } + case 2: /** Frame length */ + if (value == 0x00) { + readBuffer[readBufferIndex++] = value; + } else { + readBufferIndex = 0; } break; - } - case 3: { - bufIndex++; - if (bufIndex >= len) { - step = 0; - // Serial.println("Bad lengh read all buffer"); + case 3: /** Frame length */ + if (value == 0x1C) { + readBuffer[readBufferIndex++] = value; + } else { + readBufferIndex = 0; } break; - } - case 4: { - buf[bufIndex++] = value; - if (bufIndex >= 32) { - result |= validate(buf); - step = 0; - // Serial.println("Got data"); + default: /** Data */ + readBuffer[readBufferIndex++] = value; + + /** Check that received full bufer */ + if (readBufferIndex >= sizeof(readBuffer)) { + /** validata package */ + if (validate(readBuffer)) { + _connected = true; /** Set connected status */ + + /** Parse data */ + parse(readBuffer); + + /** Set last received package */ + lastPackage = millis(); + if (lastPackage == 0) { + lastPackage = 1; + } + } + + /** Clear buffer index */ + readBufferIndex = 0; } break; } - default: - break; - } - // Reduce core panic: delay 1 ms each 32bytes data - bcount++; - if ((bcount % 32) == 0) { - delay(1); + /** Avoid task watchdog timer reset... */ + delayCount++; + if(delayCount >= 32) + { + delay(1); } } - if (result) { - lastRead = millis(); - if (lastRead == 0) { - lastRead = 1; - } - failed = false; - } else { - if (ms > 5000) { - failed = true; + /** Check that sensor removed */ + if (lastPackage) { + unsigned long ms = (unsigned long)(millis() - lastPackage); + if (ms >= 1500) { + lastPackage = 0; + _connected = false; } } } -/** - * @brief Check that PMS send is failed or disconnected - * - * @return true Failed - * @return false No problem - */ -bool PMSBase::isFailed(void) { return failed; } - /** * @brief Increate number of fail * @@ -174,112 +139,114 @@ int PMSBase::getFailCountMax(void) { return failCountMax; } * * @return uint16_t */ -uint16_t PMSBase::getRaw0_1(void) { return toU16(&package[4]); } +uint16_t PMSBase::getRaw0_1(void) { return pms_raw0_1; } /** * @brief Read PMS 2.5 ug/m3 with CF = 1 PM estimates * * @return uint16_t */ -uint16_t PMSBase::getRaw2_5(void) { return toU16(&package[6]); } +uint16_t PMSBase::getRaw2_5(void) { return pms_raw2_5; } /** * @brief Read PMS 10 ug/m3 with CF = 1 PM estimates * * @return uint16_t */ -uint16_t PMSBase::getRaw10(void) { return toU16(&package[8]); } +uint16_t PMSBase::getRaw10(void) { return pms_raw10; } /** * @brief Read PMS 0.1 ug/m3 * * @return uint16_t */ -uint16_t PMSBase::getPM0_1(void) { return toU16(&package[10]); } +uint16_t PMSBase::getPM0_1(void) { return pms_pm0_1; } /** * @brief Read PMS 2.5 ug/m3 * * @return uint16_t */ -uint16_t PMSBase::getPM2_5(void) { return toU16(&package[12]); } +uint16_t PMSBase::getPM2_5(void) { return pms_pm2_5; } /** * @brief Read PMS 10 ug/m3 * * @return uint16_t */ -uint16_t PMSBase::getPM10(void) { return toU16(&package[14]); } +uint16_t PMSBase::getPM10(void) { return pms_pm10; } /** * @brief Get numnber concentrations over 0.3 um/0.1L * * @return uint16_t */ -uint16_t PMSBase::getCount0_3(void) { return toU16(&package[16]); } +uint16_t PMSBase::getCount0_3(void) { return pms_count0_3; } /** * @brief Get numnber concentrations over 0.5 um/0.1L * * @return uint16_t */ -uint16_t PMSBase::getCount0_5(void) { return toU16(&package[18]); } +uint16_t PMSBase::getCount0_5(void) { return pms_count0_5; } /** * @brief Get numnber concentrations over 1.0 um/0.1L * * @return uint16_t */ -uint16_t PMSBase::getCount1_0(void) { return toU16(&package[20]); } +uint16_t PMSBase::getCount1_0(void) { return pms_count1_0; } /** * @brief Get numnber concentrations over 2.5 um/0.1L * * @return uint16_t */ -uint16_t PMSBase::getCount2_5(void) { return toU16(&package[22]); } +uint16_t PMSBase::getCount2_5(void) { return pms_count2_5; } + +bool PMSBase::connected(void) { return _connected; } /** * @brief Get numnber concentrations over 5.0 um/0.1L (only PMS5003) * * @return uint16_t */ -uint16_t PMSBase::getCount5_0(void) { return toU16(&package[24]); } +uint16_t PMSBase::getCount5_0(void) { return pms_count5_0; } /** * @brief Get numnber concentrations over 10.0 um/0.1L (only PMS5003) * * @return uint16_t */ -uint16_t PMSBase::getCount10(void) { return toU16(&package[26]); } +uint16_t PMSBase::getCount10(void) { return pms_count10; } /** * @brief Get temperature (only PMS5003T) * * @return uint16_t */ -int16_t PMSBase::getTemp(void) { return toI16(&package[24]); } +int16_t PMSBase::getTemp(void) { return pms_temp; } /** * @brief Get humidity (only PMS5003T) * * @return uint16_t */ -uint16_t PMSBase::getHum(void) { return toU16(&package[26]); } +uint16_t PMSBase::getHum(void) { return pms_hum; } /** * @brief Get firmware version code * * @return uint8_t */ -uint8_t PMSBase::getFirmwareVersion(void) { return package[28]; } +uint8_t PMSBase::getFirmwareVersion(void) { return pms_firmwareVersion; } /** * @brief Ge PMS5003 error code * * @return uint8_t */ -uint8_t PMSBase::getErrorCode(void) { return package[29]; } +uint8_t PMSBase::getErrorCode(void) { return pms_errorCode; } /** * @brief Convert PMS2.5 to US AQI unit @@ -350,13 +317,13 @@ int PMSBase::compensate(int pm25, float humidity) { * @param buf bytes array (must be >= 2) * @return int16_t */ -int16_t PMSBase::toI16(char *buf) { +int16_t PMSBase::toI16(const uint8_t *buf) { int16_t value = buf[0]; value = (value << 8) | buf[1]; return value; } -uint16_t PMSBase::toU16(char *buf) { +uint16_t PMSBase::toU16(const uint8_t *buf) { uint16_t value = buf[0]; value = (value << 8) | buf[1]; return value; @@ -369,16 +336,32 @@ uint16_t PMSBase::toU16(char *buf) { * @return true Success * @return false Failed */ -bool PMSBase::validate(char *buf) { +bool PMSBase::validate(const uint8_t *buf) { uint16_t sum = 0; for (int i = 0; i < 30; i++) { sum += buf[i]; } if (sum == toU16(&buf[30])) { - for (int i = 0; i < 32; i++) { - package[i] = buf[i]; - } return true; } return false; } + +void PMSBase::parse(const uint8_t *buf) { + pms_raw0_1 = toU16(&buf[4]); + pms_raw2_5 = toU16(&buf[6]); + pms_raw10 = toU16(&buf[8]); + pms_pm0_1 = toU16(&buf[10]); + pms_pm2_5 = toU16(&buf[12]); + pms_pm10 = toU16(&buf[14]); + pms_count0_3 = toU16(&buf[16]); + pms_count0_5 = toU16(&buf[18]); + pms_count1_0 = toU16(&buf[20]); + pms_count2_5 = toU16(&buf[22]); + pms_count5_0 = toU16(&buf[24]); + pms_count10 = toU16(&buf[26]); + pms_temp = toU16(&buf[24]); + pms_hum = toU16(&buf[26]); + pms_firmwareVersion = buf[28]; + pms_errorCode = buf[29]; +} diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index e79480ee..3e6ec9fb 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -7,9 +7,8 @@ class PMSBase { public: - bool begin(Stream *stream); - void handle(); - bool isFailed(void); + bool begin(HardwareSerial& serial); + void readPackage(HardwareSerial& serial); void updateFailCount(void); void resetFailCount(void); int getFailCount(void); @@ -24,6 +23,7 @@ class PMSBase { uint16_t getCount0_5(void); uint16_t getCount1_0(void); uint16_t getCount2_5(void); + bool connected(void); /** For PMS5003 */ uint16_t getCount5_0(void); @@ -39,17 +39,36 @@ class PMSBase { int compensate(int pm25, float humidity); private: - Stream *stream; - char package[32]; - int packageIndex; - bool failed = false; - uint32_t lastRead; + static const uint8_t package_size = 32; const int failCountMax = 10; int failCount = 0; - int16_t toI16(char *buf); - uint16_t toU16(char* buf); - bool validate(char *buf); + uint8_t readBuffer[package_size]; + uint8_t readBufferIndex = 0; + unsigned long lastPackage = 0; + bool _connected; + + uint16_t pms_raw0_1; + uint16_t pms_raw2_5; + uint16_t pms_raw10; + uint16_t pms_pm0_1; + uint16_t pms_pm2_5; + uint16_t pms_pm10; + uint16_t pms_count0_3; + uint16_t pms_count0_5; + uint16_t pms_count1_0; + uint16_t pms_count2_5; + uint16_t pms_count5_0; + uint16_t pms_count10; + int16_t pms_temp; + uint16_t pms_hum; + uint8_t pms_errorCode; + uint8_t pms_firmwareVersion; + + int16_t toI16(const uint8_t *buf); + uint16_t toU16(const uint8_t *buf); + bool validate(const uint8_t *buf); + void parse(const uint8_t* buf); }; #endif /** _PMS5003_BASE_H_ */ diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index b6326279..3e52896f 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -73,7 +73,7 @@ bool PMS5003::begin(void) { } #else this->_serial->begin(9600); - if (pms.begin(this->_serial) == false) { + if (pms.begin(*this->_serial) == false) { AgLog("PMS failed"); return false; } @@ -148,6 +148,14 @@ int PMS5003::getFirmwareVersion(void) { return _ver; } */ uint8_t PMS5003::getErrorCode(void) { return pms.getErrorCode(); } +/** + * @brief Is sensor connect with device + * + * @return true Connected + * @return false Removed + */ +bool PMS5003::connected(void) { return pms.connected(); } + /** * @brief Check device initialized or not * @@ -182,15 +190,7 @@ void PMS5003::end(void) { * @brief Check and read PMS sensor data. This method should be callack from * loop process to continoue check sensor data if it's available */ -void PMS5003::handle(void) { pms.handle(); } - -/** - * @brief Get sensor status - * - * @return true No problem - * @return false Communication timeout or sensor has removed - */ -bool PMS5003::isFailed(void) { return pms.isFailed(); } +void PMS5003::handle(void) { pms.readPackage(*this->_serial); } void PMS5003::updateFailCount(void) { pms.updateFailCount(); diff --git a/src/PMS/PMS5003.h b/src/PMS/PMS5003.h index 88fda3bb..66af3a7e 100644 --- a/src/PMS/PMS5003.h +++ b/src/PMS/PMS5003.h @@ -18,7 +18,6 @@ class PMS5003 { #endif void end(void); void handle(void); - bool isFailed(void); void updateFailCount(void); void resetFailCount(void); int getFailCount(void); @@ -31,6 +30,7 @@ class PMS5003 { int compensate(int pm25, float humidity); int getFirmwareVersion(void); uint8_t getErrorCode(void); + bool connected(void); private: bool _isBegin = false; diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index b5e65f3c..0e1a8bff 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -98,7 +98,7 @@ bool PMS5003T::begin(void) { this->_serial->begin(9600, SERIAL_8N1, bsp->SenseAirS8.uart_rx_pin, bsp->SenseAirS8.uart_tx_pin); } - if (pms.begin(this->_serial) == false) { + if (pms.begin(*this->_serial) == false) { AgLog("PMS failed"); return false; } @@ -191,6 +191,14 @@ int PMS5003T::getFirmwareVersion(void) { return _ver; } */ uint8_t PMS5003T::getErrorCode(void) { return pms.getErrorCode(); } +/** + * @brief Is sensor connect to device + * + * @return true Connected + * @return false Removed + */ +bool PMS5003T::connected(void) { return pms.connected(); } + /** * @brief Check device initialized or not * @@ -222,15 +230,7 @@ void PMS5003T::end(void) { * @brief Check and read PMS sensor data. This method should be callack from * loop process to continoue check sensor data if it's available */ -void PMS5003T::handle(void) { pms.handle(); } - -/** - * @brief Get sensor status - * - * @return true No problem - * @return false Communication timeout or sensor has removed - */ -bool PMS5003T::isFailed(void) { return pms.isFailed(); } +void PMS5003T::handle(void) { pms.readPackage(*this->_serial); } void PMS5003T::updateFailCount(void) { pms.updateFailCount(); diff --git a/src/PMS/PMS5003T.h b/src/PMS/PMS5003T.h index a35a6055..ea9cbed9 100644 --- a/src/PMS/PMS5003T.h +++ b/src/PMS/PMS5003T.h @@ -21,7 +21,6 @@ class PMS5003T: public PMS5003TBase { void end(void); void handle(void); - bool isFailed(void); void updateFailCount(void); void resetFailCount(void); int getFailCount(void); @@ -36,6 +35,7 @@ class PMS5003T: public PMS5003TBase { int compensate(int pm25, float humidity); int getFirmwareVersion(void); uint8_t getErrorCode(void); + bool connected(void); private: bool _isBegin = false; From d108b63a57bdf13cd75f43f883812f6d9d84fc46 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 21 Sep 2024 17:47:59 +0700 Subject: [PATCH 2/9] Update read proccess --- src/PMS/PMS.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 9fefb553..d4ed49b4 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -71,6 +71,7 @@ void PMSBase::readPackage(HardwareSerial& serial) { } break; default: /** Data */ + { readBuffer[readBufferIndex++] = value; /** Check that received full bufer */ @@ -94,12 +95,13 @@ void PMSBase::readPackage(HardwareSerial& serial) { } break; } + } /** Avoid task watchdog timer reset... */ delayCount++; - if(delayCount >= 32) - { - delay(1); + if (delayCount >= 32) { + delayCount = 0; + delay(1); } } From 12c6ec9910d2e1fcc1e4e0c7a85ee0475d5bd3cc Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 21 Sep 2024 17:48:18 +0700 Subject: [PATCH 3/9] format code --- src/PMS/PMS.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index d4ed49b4..e7d7af3f 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -8,7 +8,7 @@ * @return true Sucecss * @return false Failure */ -bool PMSBase::begin(HardwareSerial& serial) { +bool PMSBase::begin(HardwareSerial &serial) { failCount = 0; _connected = false; @@ -33,10 +33,10 @@ bool PMSBase::begin(HardwareSerial& serial) { /** * @brief Read PMS package send to device each 1sec - * - * @param serial + * + * @param serial */ -void PMSBase::readPackage(HardwareSerial& serial) { +void PMSBase::readPackage(HardwareSerial &serial) { uint8_t delayCount = 0; while (serial.available()) { /** Get value */ @@ -117,7 +117,7 @@ void PMSBase::readPackage(HardwareSerial& serial) { /** * @brief Increate number of fail - * + * */ void PMSBase::updateFailCount(void) { if (failCount < failCountMax) { @@ -129,8 +129,8 @@ void PMSBase::resetFailCount(void) { failCount = 0; } /** * @brief Get number of fail - * - * @return int + * + * @return int */ int PMSBase::getFailCount(void) { return failCount; } @@ -238,15 +238,15 @@ uint16_t PMSBase::getHum(void) { return pms_hum; } /** * @brief Get firmware version code - * - * @return uint8_t + * + * @return uint8_t */ uint8_t PMSBase::getFirmwareVersion(void) { return pms_firmwareVersion; } /** * @brief Ge PMS5003 error code - * - * @return uint8_t + * + * @return uint8_t */ uint8_t PMSBase::getErrorCode(void) { return pms_errorCode; } @@ -277,12 +277,12 @@ int PMSBase::pm25ToAQI(int pm02) { /** * @brief Correction PM2.5 - * + * * Formula: https://www.airgradient.com/documentation/correction-algorithms/ - * + * * @param pm25 Raw PM2.5 value * @param humidity Humidity value (%) - * @return int + * @return int */ int PMSBase::compensate(int pm25, float humidity) { float value; @@ -306,7 +306,7 @@ int PMSBase::compensate(int pm25, float humidity) { value = 2.966f + (0.69f * fpm25) + (8.84f * (1.e-4) * fpm25 * fpm25); } - if(value < 0) { + if (value < 0) { value = 0; } From 2a6fce674ea9d1f4a40124e64cbb213a8e2e1db9 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Mon, 23 Sep 2024 06:51:01 +0700 Subject: [PATCH 4/9] add variable comment --- src/PMS/PMS.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index 3e6ec9fb..2cc8e7be 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -45,6 +45,11 @@ class PMSBase { uint8_t readBuffer[package_size]; uint8_t readBufferIndex = 0; + + /** + * Save last time received package success. 0 to disable check package + * timeout. + */ unsigned long lastPackage = 0; bool _connected; From c1a4758c6c037749c61d610c52b1c9462a29dfd0 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Tue, 24 Sep 2024 10:28:41 +0700 Subject: [PATCH 5/9] update timeout handle --- src/PMS/PMS.cpp | 29 ++++++++++++++++++++++++++++- src/PMS/PMS.h | 7 +++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index e7d7af3f..3faf9195 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -37,6 +37,33 @@ bool PMSBase::begin(HardwareSerial &serial) { * @param serial */ void PMSBase::readPackage(HardwareSerial &serial) { + /** If readPackage has process as period larger than READ_PACKAGE_TIMEOUT, + * should be clear the lastPackage and readBufferIndex */ + if (lastReadPackage) { + unsigned long ms = (unsigned long)(millis() - lastReadPackage); + if (ms >= READ_PACKGE_TIMEOUT) { + /** Clear buffer */ + readBufferIndex = 0; + + /** Disable check read package timeout */ + lastPackage = 0; + + Serial.println("Last process timeout, clear buffer and last handle package"); + } + + lastReadPackage = millis(); + if (!lastReadPackage) { + lastReadPackage = 1; + } + } else { + lastReadPackage = millis(); + if (!lastReadPackage) { + lastReadPackage = 1; + } + } + + /** Count to call delay() to release the while loop MCU resource for avoid the + * watchdog time reset */ uint8_t delayCount = 0; while (serial.available()) { /** Get value */ @@ -108,7 +135,7 @@ void PMSBase::readPackage(HardwareSerial &serial) { /** Check that sensor removed */ if (lastPackage) { unsigned long ms = (unsigned long)(millis() - lastPackage); - if (ms >= 1500) { + if (ms >= READ_PACKGE_TIMEOUT) { lastPackage = 0; _connected = false; } diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index 2cc8e7be..20872bcd 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -40,6 +40,11 @@ class PMSBase { private: static const uint8_t package_size = 32; + + /** In normal package interval is 200-800ms, In case small changed on sensor + * it's will interval reach to 2.3sec + */ + const uint16_t READ_PACKGE_TIMEOUT = 3000; /** ms */ const int failCountMax = 10; int failCount = 0; @@ -53,6 +58,8 @@ class PMSBase { unsigned long lastPackage = 0; bool _connected; + unsigned long lastReadPackage = 0; + uint16_t pms_raw0_1; uint16_t pms_raw2_5; uint16_t pms_raw10; From ebb3f01dcde4b6674388580b090cd5c80702a4b1 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Tue, 24 Sep 2024 10:39:17 +0700 Subject: [PATCH 6/9] set active mode on init --- src/PMS/PMS.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index f77cea16..59e525cd 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -4,7 +4,7 @@ /** * @brief Initializes the sensor and attempts to read data. * - * @param stream UART stream + * @param HardwareSerial UART stream * @return true Sucecss * @return false Failure */ @@ -13,7 +13,19 @@ bool PMSBase::begin(HardwareSerial &serial) { _connected = false; // Run and check sensor data for 4sec + int bytesCleared = serial.available(); serial.flush(); + if (bytesCleared) { + Serial.printf("cleared %d byte(s)\n", bytesCleared); + } + + // explicitly put the sensor into active mode, this seems to be be needed for + // the Cubic PM2009X + Serial.printf("Setting active mode\n"); + uint8_t activeModeCommand[] = {0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71}; + size_t bytesWritten = + serial.write(activeModeCommand, sizeof(activeModeCommand)); + Serial.printf("%d byte(s) written\n", bytesWritten); unsigned long lastInit = millis(); while (true) { @@ -25,9 +37,15 @@ bool PMSBase::begin(HardwareSerial &serial) { delay(1); unsigned long ms = (unsigned long)(millis() - lastInit); if (ms >= 4000) { + Serial.println("Initialize PMS sensor: Timeout"); break; } } + + if (_connected) { + Serial.println("Initialize PMS sensor"); + } + return _connected; } From cb511903ef626158d410c40dcccf15e048325465 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Tue, 24 Sep 2024 20:07:14 +0700 Subject: [PATCH 7/9] Update the API use Stream instead of Hardware/Software serial --- src/PMS/PMS.cpp | 41 ++++++++++++++++++----------------------- src/PMS/PMS.h | 4 ++-- src/PMS/PMS5003.cpp | 12 +++++------- src/PMS/PMS5003.h | 4 ++++ src/PMS/PMS5003T.cpp | 11 +++++------ src/PMS/PMS5003T.h | 4 ++++ 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 59e525cd..4bf4da6d 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -4,32 +4,33 @@ /** * @brief Initializes the sensor and attempts to read data. * - * @param HardwareSerial UART stream + * @param stream UART stream * @return true Sucecss * @return false Failure */ -bool PMSBase::begin(HardwareSerial &serial) { +bool PMSBase::begin(Stream *stream) { + Serial.printf("initializing PM sensor\n"); + failCount = 0; _connected = false; - // Run and check sensor data for 4sec - int bytesCleared = serial.available(); - serial.flush(); - if (bytesCleared) { - Serial.printf("cleared %d byte(s)\n", bytesCleared); + // empty first + int bytesCleared = 0; + while (stream->read() != -1) { + bytesCleared++; } + Serial.printf("cleared %d byte(s)\n", bytesCleared); - // explicitly put the sensor into active mode, this seems to be be needed for - // the Cubic PM2009X - Serial.printf("Setting active mode\n"); - uint8_t activeModeCommand[] = {0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71}; - size_t bytesWritten = - serial.write(activeModeCommand, sizeof(activeModeCommand)); + // explicitly put the sensor into active mode, this seems to be be needed for the Cubic PM2009X + Serial.printf("setting active mode\n"); + uint8_t activeModeCommand[] = { 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71 }; + size_t bytesWritten = stream->write(activeModeCommand, sizeof(activeModeCommand)); Serial.printf("%d byte(s) written\n", bytesWritten); + // Run and check sensor data for 4sec unsigned long lastInit = millis(); while (true) { - readPackage(serial); + readPackage(stream); if (_connected) { break; } @@ -37,15 +38,9 @@ bool PMSBase::begin(HardwareSerial &serial) { delay(1); unsigned long ms = (unsigned long)(millis() - lastInit); if (ms >= 4000) { - Serial.println("Initialize PMS sensor: Timeout"); break; } } - - if (_connected) { - Serial.println("Initialize PMS sensor"); - } - return _connected; } @@ -54,7 +49,7 @@ bool PMSBase::begin(HardwareSerial &serial) { * * @param serial */ -void PMSBase::readPackage(HardwareSerial &serial) { +void PMSBase::readPackage(Stream *serial) { /** If readPackage has process as period larger than READ_PACKAGE_TIMEOUT, * should be clear the lastPackage and readBufferIndex */ if (lastReadPackage) { @@ -83,9 +78,9 @@ void PMSBase::readPackage(HardwareSerial &serial) { /** Count to call delay() to release the while loop MCU resource for avoid the * watchdog time reset */ uint8_t delayCount = 0; - while (serial.available()) { + while (serial->available()) { /** Get value */ - uint8_t value = (uint8_t)serial.read(); + uint8_t value = (uint8_t)serial->read(); /** Process receiving package... */ switch (readBufferIndex) { diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index 617cdf38..d381d696 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -10,8 +10,8 @@ */ class PMSBase { public: - bool begin(HardwareSerial& serial); - void readPackage(HardwareSerial& serial); + bool begin(Stream *stream); + void readPackage(Stream *stream); void updateFailCount(void); void resetFailCount(void); int getFailCount(void); diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index bf576891..7488bd69 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -3,7 +3,6 @@ #include "../Main/utils.h" #if defined(ESP8266) -#include /** * @brief Init sensor * @@ -60,17 +59,16 @@ bool PMS5003::begin(void) { } #if defined(ESP8266) - bsp->Pms5003.uart_tx_pin; - SoftwareSerial *uart = + this->_serial = new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin); - uart->begin(9600); - if (pms.begin(uart) == false) { + this->_serial->begin(9600); + if (pms.begin(this->_serial) == false) { AgLog("PMS failed"); return false; } #else this->_serial->begin(9600); - if (pms.begin(*this->_serial) == false) { + if (pms.begin(this->_serial) == false) { AgLog("PMS failed"); return false; } @@ -187,7 +185,7 @@ void PMS5003::end(void) { * @brief Check and read PMS sensor data. This method should be callack from * loop process to continoue check sensor data if it's available */ -void PMS5003::handle(void) { pms.readPackage(*this->_serial); } +void PMS5003::handle(void) { pms.readPackage(this->_serial); } void PMS5003::updateFailCount(void) { pms.updateFailCount(); diff --git a/src/PMS/PMS5003.h b/src/PMS/PMS5003.h index 66af3a7e..5bfadde1 100644 --- a/src/PMS/PMS5003.h +++ b/src/PMS/PMS5003.h @@ -4,6 +4,9 @@ #include "../Main/BoardDef.h" #include "PMS.h" #include "Stream.h" +#ifdef ESP8266 +#include +#endif /** * @brief The class define how to handle PMS5003 sensor bas on @ref PMS class @@ -41,6 +44,7 @@ class PMS5003 { #if defined(ESP8266) Stream *_debugStream; const char *TAG = "PMS5003"; + SoftwareSerial *_serial; #else HardwareSerial *_serial; #endif diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index 0e1a8bff..4294ec57 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -67,11 +67,10 @@ bool PMS5003T::begin(void) { } #if defined(ESP8266) - bsp->Pms5003.uart_tx_pin; - SoftwareSerial *uart = + this->_serial = new SoftwareSerial(bsp->Pms5003.uart_tx_pin, bsp->Pms5003.uart_rx_pin); - uart->begin(9600); - if (pms.begin(uart) == false) { + this->_serial->begin(9600); + if (pms.begin(this->_serial) == false) { AgLog("PMS failed"); return false; } @@ -98,7 +97,7 @@ bool PMS5003T::begin(void) { this->_serial->begin(9600, SERIAL_8N1, bsp->SenseAirS8.uart_rx_pin, bsp->SenseAirS8.uart_tx_pin); } - if (pms.begin(*this->_serial) == false) { + if (pms.begin(this->_serial) == false) { AgLog("PMS failed"); return false; } @@ -230,7 +229,7 @@ void PMS5003T::end(void) { * @brief Check and read PMS sensor data. This method should be callack from * loop process to continoue check sensor data if it's available */ -void PMS5003T::handle(void) { pms.readPackage(*this->_serial); } +void PMS5003T::handle(void) { pms.readPackage(this->_serial); } void PMS5003T::updateFailCount(void) { pms.updateFailCount(); diff --git a/src/PMS/PMS5003T.h b/src/PMS/PMS5003T.h index ea9cbed9..7c3e0df0 100644 --- a/src/PMS/PMS5003T.h +++ b/src/PMS/PMS5003T.h @@ -6,6 +6,9 @@ #include "PMS5003TBase.h" #include "Stream.h" #include +#ifdef ESP8266 +#include +#endif /** * @brief The class define how to handle PMS5003T sensor bas on @ref PMS class @@ -47,6 +50,7 @@ class PMS5003T: public PMS5003TBase { #if defined(ESP8266) Stream *_debugStream; const char *TAG = "PMS5003T"; + SoftwareSerial *_serial; #else HardwareSerial *_serial; #endif From b8e10f473eb8ed70071866c1e0e19cd1ebea04df Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Tue, 24 Sep 2024 20:07:31 +0700 Subject: [PATCH 8/9] update API change on example --- examples/BASIC/BASIC.ino | 2 +- examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 2 +- examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 2 +- examples/TestPM/TestPM.ino | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino index 76b5d07f..b3be0466 100644 --- a/examples/BASIC/BASIC.ino +++ b/examples/BASIC/BASIC.ino @@ -503,7 +503,7 @@ static void updateTvoc(void) { } static void updatePm(void) { - if (ag.pms5003.isFailed() == false) { + if (ag.pms5003.connected()) { measurements.pm01_1 = ag.pms5003.getPm01Ae(); measurements.pm25_1 = ag.pms5003.getPm25Ae(); measurements.pm10_1 = ag.pms5003.getPm10Ae(); diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino index 44e401ac..b67e262d 100644 --- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino +++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino @@ -555,7 +555,7 @@ static void updateTvoc(void) { } static void updatePm(void) { - if (ag.pms5003.isFailed() == false) { + if (ag.pms5003.connected()) { measurements.pm01_1 = ag.pms5003.getPm01Ae(); measurements.pm25_1 = ag.pms5003.getPm25Ae(); measurements.pm10_1 = ag.pms5003.getPm10Ae(); diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino index ac4a690f..bac20a57 100644 --- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino +++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino @@ -596,7 +596,7 @@ static void updateTvoc(void) { } static void updatePm(void) { - if (ag.pms5003.isFailed() == false) { + if (ag.pms5003.connected()) { measurements.pm01_1 = ag.pms5003.getPm01Ae(); measurements.pm25_1 = ag.pms5003.getPm25Ae(); measurements.pm10_1 = ag.pms5003.getPm10Ae(); diff --git a/examples/TestPM/TestPM.ino b/examples/TestPM/TestPM.ino index db84f24c..92f297de 100644 --- a/examples/TestPM/TestPM.ino +++ b/examples/TestPM/TestPM.ino @@ -44,7 +44,7 @@ void loop() { if (ms >= 5000) { lastRead = millis(); #ifdef ESP8266 - if (ag.pms5003.isFailed() == false) { + if (ag.pms5003.connected()) { PM2 = ag.pms5003.getPm25Ae(); Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2); Serial.printf("PM2.5 in US AQI: %d\r\n", From 359394af536dc8fc94903881ba7ffe703bcc9639 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Tue, 24 Sep 2024 20:13:01 +0700 Subject: [PATCH 9/9] fix: compile failed for esp32-c3 --- examples/TestPM/TestPM.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/TestPM/TestPM.ino b/examples/TestPM/TestPM.ino index 92f297de..0f5e4102 100644 --- a/examples/TestPM/TestPM.ino +++ b/examples/TestPM/TestPM.ino @@ -54,12 +54,12 @@ void loop() { } #else if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { - if (ag.pms5003t_1.isFailed() == false) { + if (ag.pms5003t_1.connected()) { PM2 = ag.pms5003t_1.getPm25Ae(); readResul = true; } } else { - if (ag.pms5003.isFailed() == false) { + if (ag.pms5003.connected()) { PM2 = ag.pms5003.getPm25Ae(); readResul = true; }