From be1a9778e69ad75116786c451bf4ae2f6b79e0b3 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Thu, 14 Mar 2024 21:17:43 +0700 Subject: [PATCH 1/8] Fix: PMS Read Failed --- README.md | 1 - examples/BASIC/BASIC.ino | 5 +- examples/ONE/ONE.ino | 7 +- examples/Open_Air/Open_Air.ino | 13 +- examples/TestPM/TestPM.ino | 74 +++--- src/PMS/PMS.cpp | 414 +++++++++++++++++++++------------ src/PMS/PMS.h | 96 +++----- src/PMS/PMS5003.cpp | 34 +-- src/PMS/PMS5003.h | 9 +- src/PMS/PMS5003T.cpp | 53 ++--- src/PMS/PMS5003T.h | 7 +- src/PMS/PMSUtils.cpp | 26 --- src/PMS/PMSUtils.h | 6 - 13 files changed, 409 insertions(+), 336 deletions(-) delete mode 100644 src/PMS/PMSUtils.cpp delete mode 100644 src/PMS/PMSUtils.h diff --git a/README.md b/README.md index 73c6279..b810332 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ If you have any questions or problems, check out [our forum](https://forum.airgr - [Sensirion Core](https://github.com/Sensirion/arduino-core/) - [Sensirion I2C SGP41](https://github.com/Sensirion/arduino-i2c-sgp41) - [Sensirion I2C SHT](https://github.com/Sensirion/arduino-sht) -- [PMS](https://github.com/fu-hsi/pms) ## License CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino index 45c29d7..45c9312 100644 --- a/examples/BASIC/BASIC.ino +++ b/examples/BASIC/BASIC.ino @@ -457,6 +457,9 @@ void loop() { } updateWiFiConnect(); + + /** Read PMS on loop */ + ag.pms5003.handle(); } static void sendPing() { @@ -629,7 +632,7 @@ static void co2Update() { } void pmUpdate() { - if (ag.pms5003.readData()) { + if (ag.pms5003.isFailed() == false) { pm25 = ag.pms5003.getPm25Ae(); Serial.printf("PMS2.5: %d\r\n", pm25); pmFailCount = 0; diff --git a/examples/ONE/ONE.ino b/examples/ONE/ONE.ino index 8768adc..5622076 100644 --- a/examples/ONE/ONE.ino +++ b/examples/ONE/ONE.ino @@ -845,6 +845,11 @@ void loop() { /** factory reset handle */ factoryConfigReset(); + + /** Read PMS on loop */ + if (hasSensorPMS) { + ag.pms5003.handle(); + } } static void setTestColor(char color) { @@ -2240,7 +2245,7 @@ static void tvocUpdate(void) { * */ static void pmUpdate(void) { - if (ag.pms5003.readData()) { + if (ag.pms5003.isFailed() == false) { pm01 = ag.pms5003.getPm01Ae(); pm25 = ag.pms5003.getPm25Ae(); pm10 = ag.pms5003.getPm10Ae(); diff --git a/examples/Open_Air/Open_Air.ino b/examples/Open_Air/Open_Air.ino index d8fe616..e39da41 100644 --- a/examples/Open_Air/Open_Air.ino +++ b/examples/Open_Air/Open_Air.ino @@ -57,7 +57,7 @@ enum { phone */ APP_SM_WIFI_MANAGER_STA_CONNECTING, /** After SSID and PW entered and OK clicked, connection to WiFI network is - attempted*/ + attempted*/ APP_SM_WIFI_MANAGER_STA_CONNECTED, /** Connecting to WiFi worked */ APP_SM_WIFI_OK_SERVER_CONNECTING, /** Once connected to WiFi an attempt to reach the server is performed */ @@ -802,6 +802,13 @@ void loop() { updateWiFiConnect(); factoryConfigReset(); + + if (hasSensorPMS1) { + ag.pms5003t_1.handle(); + } + if (hasSensorPMS2) { + ag.pms5003t_2.handle(); + } } void sendPing() { @@ -1101,7 +1108,7 @@ static void tvocUpdate(void) { static void pmUpdate(void) { bool pmsResult_1 = false; bool pmsResult_2 = false; - if (hasSensorPMS1 && ag.pms5003t_1.readData()) { + if (hasSensorPMS1 && (ag.pms5003t_1.isFailed() == false)) { pm01_1 = ag.pms5003t_1.getPm01Ae(); pm25_1 = ag.pms5003t_1.getPm25Ae(); pm10_1 = ag.pms5003t_1.getPm10Ae(); @@ -1127,7 +1134,7 @@ static void pmUpdate(void) { hum_1 = -1; } - if (hasSensorPMS2 && ag.pms5003t_2.readData()) { + if (hasSensorPMS2 && (ag.pms5003t_2.isFailed() == false)) { pm01_2 = ag.pms5003t_2.getPm01Ae(); pm25_2 = ag.pms5003t_2.getPm25Ae(); pm10_2 = ag.pms5003t_2.getPm10Ae(); diff --git a/examples/TestPM/TestPM.ino b/examples/TestPM/TestPM.ino index 556d1cf..db84f24 100644 --- a/examples/TestPM/TestPM.ino +++ b/examples/TestPM/TestPM.ino @@ -10,8 +10,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License #ifdef ESP8266 AirGradient ag = AirGradient(DIY_BASIC); #else -// AirGradient ag = AirGradient(ONE_INDOOR); -AirGradient ag = AirGradient(OPEN_AIR_OUTDOOR); +AirGradient ag = AirGradient(ONE_INDOOR); +// AirGradient ag = AirGradient(OPEN_AIR_OUTDOOR); #endif void failedHandler(String msg); @@ -35,42 +35,56 @@ void setup() { #endif } +uint32_t lastRead = 0; void loop() { int PM2; bool readResul = false; -#ifdef ESP8266 - if (ag.pms5003.readData()) { - 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", - ag.pms5003.convertPm25ToUsAqi(PM2)); - } -#else - if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { - if (ag.pms5003t_1.readData()) { - PM2 = ag.pms5003t_1.getPm25Ae(); - readResul = true; - } - } else { - if (ag.pms5003.readData()) { - PM2 = ag.pms5003.getPm25Ae(); - readResul = true; - } - } - if (readResul) { - Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2); - if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { - Serial.printf("PM2.5 in US AQI: %d\r\n", - ag.pms5003t_1.convertPm25ToUsAqi(PM2)); - } else { + uint32_t ms = (uint32_t)(millis() - lastRead); + if (ms >= 5000) { + lastRead = millis(); +#ifdef ESP8266 + if (ag.pms5003.isFailed() == false) { + 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", ag.pms5003.convertPm25ToUsAqi(PM2)); + } else { + Serial.println("PMS sensor failed"); + } +#else + if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { + if (ag.pms5003t_1.isFailed() == false) { + PM2 = ag.pms5003t_1.getPm25Ae(); + readResul = true; + } + } else { + if (ag.pms5003.isFailed() == false) { + PM2 = ag.pms5003.getPm25Ae(); + readResul = true; + } } - } -#endif - delay(5000); + if (readResul) { + Serial.printf("PM2.5 in ug/m3: %d\r\n", PM2); + if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { + Serial.printf("PM2.5 in US AQI: %d\r\n", + ag.pms5003t_1.convertPm25ToUsAqi(PM2)); + } else { + Serial.printf("PM2.5 in US AQI: %d\r\n", + ag.pms5003.convertPm25ToUsAqi(PM2)); + } + } else { + Serial.println("PMS sensor failed"); + } +#endif + } + + if (ag.getBoardType() == OPEN_AIR_OUTDOOR) { + ag.pms5003t_1.handle(); + } else { + ag.pms5003.handle(); + } } void failedHandler(String msg) { diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index be7e919..84a6a35 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -1,164 +1,288 @@ #include "PMS.h" +#include "../Main/BoardDef.h" -bool PMS::begin(Stream *stream) { - _stream = stream; +bool PMSBase::begin(Stream *stream) { + this->stream = stream; - DATA data; - if (readUntil(data, 5000)) { - return true; + failed = true; + lastRead = 0; // To read buffer on handle without wait after 1.5sec + + this->stream->flush(); + + // Run and check sensor data for 4sec + while (1) { + handle(); + if (failed == false) { + return true; + } + + delay(1); + uint32_t ms = (uint32_t)(millis() - lastRead); + if (ms >= 4000) { + break; + } } - 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)); +/** + * @brief Read PMS data as 1.5sec period + */ +void PMSBase::handle() { + uint32_t ms; + if (lastRead == 0) { + lastRead = millis(); + if (lastRead == 0) { + lastRead = 1; + } + } else { + ms = (uint32_t)(millis() - lastRead); + /** Ignore read data if two time call less then 1sec. In active mode the + * data sync perido is 1sec. Two times read must be large or equal 2.5sec */ + if (ms < 2500) { + return; + } } -} + bool result = false; + char buf[32]; + int bufIndex; + int step = 0; + int len = 0; + int bcount = 0; -// 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) { + while (stream->available()) { + char value = stream->read(); + switch (step) { + case 0: { + if (value == 0x42) { + step = 1; + bufIndex = 0; + buf[bufIndex++] = value; + } 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; + case 1: { + if (value == 0x4d) { + step = 2; + buf[bufIndex++] = value; + // Serial.println("Got 0x4d"); } else { - _calculatedChecksum += ch; - uint8_t payloadIndex = _index - 4; - - // Payload is common to all sensors (first 2x6 bytes). - if (payloadIndex < sizeof(_payload)) { - _payload[payloadIndex] = ch; + step = 0; + } + break; + } + case 2: { + buf[bufIndex++] = value; + if (bufIndex >= 4) { + len = toValue(&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; } } - + break; + } + case 3: { + bufIndex++; + if (bufIndex >= len) { + step = 0; + // Serial.println("Bad lengh read all buffer"); + } + break; + } + case 4: { + buf[bufIndex++] = value; + if (bufIndex >= 32) { + result |= validate(buf); + step = 0; + // Serial.println("Got data"); + } + break; + } + default: break; } - _index++; + // Reduce core panic: delay 1 ms each 32bytes data + bcount++; + if((bcount % 32) == 0){ + delay(1); + } + } + + if (result) { + lastRead = millis(); + if (lastRead == 0) { + lastRead = 1; + } + failed = false; + } else { + if (ms > 5000) { + failed = true; + } } } + +/** + * @brief Check that PMS send is failed or disconnected + * + * @return true Failed + * @return false No problem + */ +bool PMSBase::isFailed(void) { return failed; } + +/** + * @brief Read PMS 0.1 ug/m3 with CF = 1 PM estimates + * + * @return uint16_t + */ +uint16_t PMSBase::getRaw0_1(void) { return toValue(&package[4]); } + +/** + * @brief Read PMS 2.5 ug/m3 with CF = 1 PM estimates + * + * @return uint16_t + */ +uint16_t PMSBase::getRaw2_5(void) { return toValue(&package[6]); } + +/** + * @brief Read PMS 10 ug/m3 with CF = 1 PM estimates + * + * @return uint16_t + */ +uint16_t PMSBase::getRaw10(void) { return toValue(&package[8]); } + +/** + * @brief Read PMS 0.1 ug/m3 + * + * @return uint16_t + */ +uint16_t PMSBase::getPM0_1(void) { return toValue(&package[10]); } + +/** + * @brief Read PMS 2.5 ug/m3 + * + * @return uint16_t + */ +uint16_t PMSBase::getPM2_5(void) { return toValue(&package[12]); } + +/** + * @brief Read PMS 10 ug/m3 + * + * @return uint16_t + */ +uint16_t PMSBase::getPM10(void) { return toValue(&package[14]); } + +/** + * @brief Get numnber concentrations over 0.3 um/0.1L + * + * @return uint16_t + */ +uint16_t PMSBase::getCount0_3(void) { return toValue(&package[16]); } + +/** + * @brief Get numnber concentrations over 0.5 um/0.1L + * + * @return uint16_t + */ +uint16_t PMSBase::getCount0_5(void) { return toValue(&package[18]); } + +/** + * @brief Get numnber concentrations over 1.0 um/0.1L + * + * @return uint16_t + */ +uint16_t PMSBase::getCount1_0(void) { return toValue(&package[20]); } + +/** + * @brief Get numnber concentrations over 2.5 um/0.1L + * + * @return uint16_t + */ +uint16_t PMSBase::getCount2_5(void) { return toValue(&package[22]); } + +/** + * @brief Get numnber concentrations over 5.0 um/0.1L (only PMS5003) + * + * @return uint16_t + */ +uint16_t PMSBase::getCount5_0(void) { return toValue(&package[24]); } + +/** + * @brief Get numnber concentrations over 10.0 um/0.1L (only PMS5003) + * + * @return uint16_t + */ +uint16_t PMSBase::getCount10(void) { return toValue(&package[26]); } + +/** + * @brief Get temperature (only PMS5003T) + * + * @return uint16_t + */ +uint16_t PMSBase::getTemp(void) { return toValue(&package[24]); } + +/** + * @brief Get humidity (only PMS5003T) + * + * @return uint16_t + */ +uint16_t PMSBase::getHum(void) { return toValue(&package[26]); } + +/** + * @brief Convert PMS2.5 to US AQI unit + * + * @param pm02 + * @return int + */ +int PMSBase::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 Convert two byte value to uint16_t value + * + * @param buf bytes array (must be >= 2) + * @return uint16_t + */ +uint16_t PMSBase::toValue(char *buf) { return (buf[0] << 8) | buf[1]; } + +/** + * @brief Validate package data + * + * @param buf Package buffer + * @return true Success + * @return false Failed + */ +bool PMSBase::validate(char *buf) { + uint16_t sum = 0; + for (int i = 0; i < 30; i++) { + sum += buf[i]; + } + if (sum == toValue(&buf[30])) { + for (int i = 0; i < 32; i++) { + package[i] = buf[i]; + } + return true; + } + return false; +} diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index f1f32dc..4fa086a 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -1,75 +1,43 @@ -#ifndef _PMS_BASE_H_ -#define _PMS_BASE_H_ +#ifndef _PMS5003_BASE_H_ +#define _PMS5003_BASE_H_ #include -/** - * @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 { +class PMSBase { 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 handle(); + bool isFailed(void); + uint16_t getRaw0_1(void); + uint16_t getRaw2_5(void); + uint16_t getRaw10(void); + uint16_t getPM0_1(void); + uint16_t getPM2_5(void); + uint16_t getPM10(void); + uint16_t getCount0_3(void); + uint16_t getCount0_5(void); + uint16_t getCount1_0(void); + uint16_t getCount2_5(void); - void requestRead(); - bool read(DATA &data); - bool readUntil(DATA &data, uint16_t timeout = SINGLE_RESPONSE_TIME); + /** For PMS5003 */ + uint16_t getCount5_0(void); + uint16_t getCount10(void); + + /** For PMS5003T*/ + uint16_t getTemp(void); + uint16_t getHum(void); + + int pm25ToAQI(int pm02); private: - enum STATUS { STATUS_WAITING, STATUS_OK }; - enum MODE { MODE_ACTIVE, MODE_PASSIVE }; + Stream *stream; + char package[32]; + int packageIndex; + bool failed = false; + uint32_t lastRead; - 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]; + uint16_t toValue(char *buf); + bool validate(char *buf); }; -#endif +#endif /** _PMS5003_BASE_H_ */ diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index 268f9bb..d3e2e65 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -1,6 +1,5 @@ #include "PMS5003.h" #include "Arduino.h" -#include "PMSUtils.h" #if defined(ESP8266) #include @@ -83,48 +82,33 @@ bool PMS5003::begin(void) { return true; } -/** - * @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; } +int PMS5003::getPm01Ae(void) { return pms.getPM0_1(); } /** * @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; } +int PMS5003::getPm25Ae(void) { return pms.getPM2_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; } +int PMS5003::getPm10Ae(void) { return pms.getPM10(); } /** - * @brief Read PM3.0 must call this function after @ref readData success + * @brief Read PM0.3 must call this function after @ref readData success * - * @return int PM3.0 index + * @return int PM0.3 index */ -int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; } +int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); } /** * @brief Convert PM2.5 to US AQI @@ -132,7 +116,7 @@ int PMS5003::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; } * @param pm25 PM2.5 index * @return int PM2.5 US AQI */ -int PMS5003::convertPm25ToUsAqi(int pm25) { return pm25ToAQI(pm25); } +int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); } /** * @brief Check device initialized or not @@ -163,3 +147,7 @@ void PMS5003::end(void) { #endif AgLog("De-initialize"); } + +void PMS5003::handle(void) { pms.handle(); } + +bool PMS5003::isFailed(void) { return pms.isFailed(); } diff --git a/src/PMS/PMS5003.h b/src/PMS/PMS5003.h index 15b907c..cd66b07 100644 --- a/src/PMS/PMS5003.h +++ b/src/PMS/PMS5003.h @@ -17,8 +17,8 @@ public: bool begin(HardwareSerial &serial); #endif void end(void); - - bool readData(void); + void handle(void); + bool isFailed(void); int getPm01Ae(void); int getPm25Ae(void); int getPm10Ae(void); @@ -28,7 +28,7 @@ public: private: bool _isBegin = false; BoardType _boardDef; - PMS pms; + PMSBase pms; const BoardDef *bsp; #if defined(ESP8266) Stream *_debugStream; @@ -36,9 +36,6 @@ private: #else HardwareSerial *_serial; #endif - // Conplug_PMS5003T *pms; - PMS::DATA pmsData; - bool begin(void); bool isBegin(void); }; diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index 6d44528..b16513c 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -1,6 +1,5 @@ #include "PMS5003T.h" #include "Arduino.h" -#include "PMSUtils.h" #if defined(ESP8266) #include @@ -108,48 +107,33 @@ bool PMS5003T::begin(void) { return true; } -/** - * @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; } +int PMS5003T::getPm01Ae(void) { return pms.getPM0_1(); } /** * @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; } +int PMS5003T::getPm25Ae(void) { return pms.getPM2_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; } +int PMS5003T::getPm10Ae(void) { return pms.getPM10(); } /** - * @brief Read PM3.0 must call this function after @ref readData success + * @brief Read PM 0.3 Count must call this function after @ref readData success * - * @return int PM3.0 index + * @return int PM 0.3 Count index */ -int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; } +int PMS5003T::getPm03ParticleCount(void) { return pms.getCount0_3(); } /** * @brief Convert PM2.5 to US AQI @@ -157,7 +141,7 @@ int PMS5003T::getPm03ParticleCount(void) { return pmsData.PM_RAW_0_3; } * @param pm25 PM2.5 index * @return int PM2.5 US AQI */ -int PMS5003T::convertPm25ToUsAqi(int pm25) { return pm25ToAQI(pm25); } +int PMS5003T::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); } /** * @brief Get temperature, Must call this method after @ref readData() success @@ -165,7 +149,7 @@ int PMS5003T::convertPm25ToUsAqi(int pm25) { return pm25ToAQI(pm25); } * @return float Degree Celcius */ float PMS5003T::getTemperature(void) { - float temp = pmsData.AMB_TMP; + float temp = pms.getTemp(); return correctionTemperature(temp / 10.0f); } @@ -175,7 +159,7 @@ float PMS5003T::getTemperature(void) { * @return float Percent (%) */ float PMS5003T::getRelativeHumidity(void) { - float hum = pmsData.AMB_HUM; + float hum = pms.getHum(); return correctionRelativeHumidity(hum / 10.0f); } @@ -213,6 +197,23 @@ void PMS5003T::end(void) { AgLog("De-initialize"); } +/** + * @brief Read PMS on loop + * + */ +void PMS5003T::handle(void) { pms.handle(); } + +/** + * @brief Get PMS status + * @return true Failed + * @return false No Problem + */ +bool PMS5003T::isFailed(void) { return pms.isFailed(); } + float PMS5003T::correctionRelativeHumidity(float inHum) { - return inHum * 1.259 + 7.34; + float hum = inHum * 1.259 + 7.34; + if (hum > 100.0f) { + hum = 100.0f; + } + return hum; } diff --git a/src/PMS/PMS5003T.h b/src/PMS/PMS5003T.h index ec4d78e..151a8b8 100644 --- a/src/PMS/PMS5003T.h +++ b/src/PMS/PMS5003T.h @@ -19,7 +19,8 @@ public: #endif void end(void); - bool readData(void); + void handle(void); + bool isFailed(void); int getPm01Ae(void); int getPm25Ae(void); int getPm10Ae(void); @@ -40,10 +41,8 @@ private: #else HardwareSerial *_serial; #endif - + PMSBase pms; bool begin(void); - PMS pms; - PMS::DATA pmsData; bool isBegin(void); float correctionTemperature(float inTemp); float correctionRelativeHumidity(float inHum); diff --git a/src/PMS/PMSUtils.cpp b/src/PMS/PMSUtils.cpp deleted file mode 100644 index f47813f..0000000 --- a/src/PMS/PMSUtils.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "PMSUtils.h" - -/** - * @brief Convert PM2.5 to US AQI - * - * @param pm02 - * @return int - */ -int 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; -} diff --git a/src/PMS/PMSUtils.h b/src/PMS/PMSUtils.h deleted file mode 100644 index ffb5a84..0000000 --- a/src/PMS/PMSUtils.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _PMS_UTILS_H_ -#define _PMS_UTILS_H_ - -int pm25ToAQI(int pm02); - -#endif /** _PMS_UTILS_H_ */ From 87f2463233903753e551076ce9dcd4dedceed97f Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 08:21:14 +0700 Subject: [PATCH 2/8] Update comment --- src/PMS/PMS.cpp | 20 ++++++++++++++++---- src/PMS/PMS5003.cpp | 10 ++++++++++ src/PMS/PMS5003T.cpp | 17 ++++++++++++----- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 84a6a35..e9a1527 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -1,6 +1,13 @@ #include "PMS.h" #include "../Main/BoardDef.h" +/** + * @brief Init and check that sensor has connected + * + * @param stream UART stream + * @return true Sucecss + * @return false Failure + */ bool PMSBase::begin(Stream *stream) { this->stream = stream; @@ -26,7 +33,8 @@ bool PMSBase::begin(Stream *stream) { } /** - * @brief Read PMS data as 1.5sec period + * @brief Check and read sensor data then update variable. + * Check result from method @isFailed before get value */ void PMSBase::handle() { uint32_t ms; @@ -37,8 +45,12 @@ void PMSBase::handle() { } } else { ms = (uint32_t)(millis() - lastRead); - /** Ignore read data if two time call less then 1sec. In active mode the - * data sync perido is 1sec. Two times read must be large or equal 2.5sec */ + /** + * 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; } @@ -109,7 +121,7 @@ void PMSBase::handle() { // Reduce core panic: delay 1 ms each 32bytes data bcount++; - if((bcount % 32) == 0){ + if ((bcount % 32) == 0) { delay(1); } } diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index d3e2e65..0e7c68b 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -148,6 +148,16 @@ void PMS5003::end(void) { AgLog("De-initialize"); } +/** + * @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(); } diff --git a/src/PMS/PMS5003T.cpp b/src/PMS/PMS5003T.cpp index b16513c..5c091fc 100644 --- a/src/PMS/PMS5003T.cpp +++ b/src/PMS/PMS5003T.cpp @@ -198,18 +198,25 @@ void PMS5003T::end(void) { } /** - * @brief Read PMS on loop - * + * @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 PMS status - * @return true Failed - * @return false No Problem + * @brief Get sensor status + * + * @return true No problem + * @return false Communication timeout or sensor has removed */ bool PMS5003T::isFailed(void) { return pms.isFailed(); } +/** + * @brief Correct the PMS5003T relactive humidity + * + * @param inHum Input humidity + * @return float Corrected humidity + */ float PMS5003T::correctionRelativeHumidity(float inHum) { float hum = inHum * 1.259 + 7.34; if (hum > 100.0f) { From ea3e976232d17b70591f0c510cb2141deb40d7f8 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 08:21:44 +0700 Subject: [PATCH 3/8] update next version `3.0.7` --- library.properties | 2 +- src/AirGradient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 37e65a9..a5128b1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AirGradient Air Quality Sensor -version=3.0.7 +version=3.0.8 author=AirGradient maintainer=AirGradient sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. diff --git a/src/AirGradient.cpp b/src/AirGradient.cpp index 294d0db..bc29648 100644 --- a/src/AirGradient.cpp +++ b/src/AirGradient.cpp @@ -1,6 +1,6 @@ #include "AirGradient.h" -#define AG_LIB_VER "3.0.7" +#define AG_LIB_VER "3.0.8" AirGradient::AirGradient(BoardType type) : pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type), From 471448a0f1c9dac2e016eb3318236573923ee19c Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 08:50:43 +0700 Subject: [PATCH 4/8] Prevent reboot in offline mode --- examples/ONE/ONE.ino | 17 +++++++++++++++++ examples/Open_Air/Open_Air.ino | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/examples/ONE/ONE.ino b/examples/ONE/ONE.ino index 5622076..a2fe1e4 100644 --- a/examples/ONE/ONE.ino +++ b/examples/ONE/ONE.ino @@ -705,6 +705,7 @@ static void webServerInit(void); static String getServerSyncData(bool localServer); static void createMqttTask(void); static void factoryConfigReset(void); +static void wdgFeedUpdate(void); /** Init schedule */ bool hasSensorS8 = true; @@ -717,6 +718,8 @@ String mdnsModelName = "I-9PSL"; int getCO2FailCount = 0; uint32_t addToDashboardTime; bool isAddToDashboard = true; +bool offlineMode = false; + AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, displayAndLedBarUpdate); AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, updateServerConfiguration); @@ -725,6 +728,7 @@ AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update); AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate); AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate); AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocUpdate); +AgSchedule wdgFeedSchedule(60000, wdgFeedUpdate); void setup() { EEPROM.begin(512); @@ -807,6 +811,8 @@ void setup() { } else { ag.ledBar.setEnable(agServer.getLedBarMode() != UseLedBarOff); } + } else { + offlineMode = true; } /** Show display Warning up */ @@ -840,6 +846,10 @@ void loop() { tvocSchedule.run(); } + if (offlineMode) { + wdgFeedSchedule.run(); + } + /** Check for handle WiFi reconnect */ updateWiFiConnect(); @@ -1253,6 +1263,13 @@ static void factoryConfigReset(void) { } } +static void wdgFeedUpdate(void) { + ag.watchdog.reset(); + Serial.println(); + Serial.println("External watchdog feed"); + Serial.println(); +} + static void sendPing() { JSONVar root; root["wifi"] = WiFi.RSSI(); diff --git a/examples/Open_Air/Open_Air.ino b/examples/Open_Air/Open_Air.ino index e39da41..1145563 100644 --- a/examples/Open_Air/Open_Air.ino +++ b/examples/Open_Air/Open_Air.ino @@ -723,6 +723,7 @@ static void webServerInit(void); static String getServerSyncData(bool localServer); static void createMqttTask(void); static void factoryConfigReset(void); +static void wdgFeedUpdate(void); bool hasSensorS8 = true; bool hasSensorPMS1 = true; @@ -731,12 +732,15 @@ bool hasSensorSGP = true; uint32_t factoryBtnPressTime = 0; String mdnsModelName = ""; int getCO2FailCount = 0; +bool offlineMode = false; + AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, updateServerConfiguration); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update); AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, pmUpdate); AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, tvocUpdate); +AgSchedule wdgFeedSchedule(60000, wdgFeedUpdate); void setup() { EEPROM.begin(512); @@ -775,6 +779,8 @@ void setup() { ledSmHandler(APP_SM_WIFI_OK_SERVER_OK_SENSOR_CONFIG_FAILED); delay(DISPLAY_DELAY_SHOW_CONTENT_MS); } + } else { + offlineMode = true; } ledSmHandler(APP_SM_NORMAL); @@ -809,6 +815,10 @@ void loop() { if (hasSensorPMS2) { ag.pms5003t_2.handle(); } + + if (offlineMode) { + wdgFeedSchedule.run(); + } } void sendPing() { @@ -1819,6 +1829,13 @@ static void factoryConfigReset(void) { } } +static void wdgFeedUpdate(void) { + ag.watchdog.reset(); + Serial.println(); + Serial.println("External watchdog feed"); + Serial.println(); +} + static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; From 3d243cb8ca6559d93ff93ce5c7cf021c91447c73 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 08:52:50 +0700 Subject: [PATCH 5/8] Revert: version 3.0.7 --- library.properties | 2 +- src/AirGradient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index a5128b1..37e65a9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AirGradient Air Quality Sensor -version=3.0.8 +version=3.0.7 author=AirGradient maintainer=AirGradient sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. diff --git a/src/AirGradient.cpp b/src/AirGradient.cpp index bc29648..294d0db 100644 --- a/src/AirGradient.cpp +++ b/src/AirGradient.cpp @@ -1,6 +1,6 @@ #include "AirGradient.h" -#define AG_LIB_VER "3.0.8" +#define AG_LIB_VER "3.0.7" AirGradient::AirGradient(BoardType type) : pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type), From 6926abd6f7375644635965c2b79761fb9b59e7d1 Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 10:02:46 +0700 Subject: [PATCH 6/8] Standardize result of /measures/current for `OpenAir` --- examples/Open_Air/Open_Air.ino | 89 ++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/examples/Open_Air/Open_Air.ino b/examples/Open_Air/Open_Air.ino index 1145563..33d6b26 100644 --- a/examples/Open_Air/Open_Air.ino +++ b/examples/Open_Air/Open_Air.ino @@ -244,15 +244,7 @@ public: uint8_t ledBarMode = UseLedBarOff; if (JSON.typeof_(root["ledBarMode"]) == "string") { String mode = root["ledBarMode"]; - if (mode == "co2") { - ledBarMode = UseLedBarCO2; - } else if (mode == "pm") { - ledBarMode = UseLedBarPM; - } else if (mode == "off") { - ledBarMode = UseLedBarOff; - } else { - ledBarMode = UseLedBarOff; - } + ledBarMode = parseLedBarMode(mode); } /** Get model */ @@ -447,6 +439,24 @@ public: */ UseLedBar getLedBarMode(void) { return (UseLedBar)config.useRGBLedBar; } + /** + * @brief Return the name of the led bare mode. + * + * @return String + */ + String getLedBarModeName(void) { + UseLedBar ledBarMode = getLedBarMode(); + if (ledBarMode == UseLedBarOff) { + return String("off"); + } else if (ledBarMode == UseLedBarPM) { + return String("pm"); + } else if (ledBarMode == UseLedBarCO2) { + return String("co2"); + } else { + return String("off"); + } + } + /** * @brief Get the Country * @@ -516,6 +526,20 @@ private: EEPROM.commit(); Serial.println("Save config"); } + + UseLedBar parseLedBarMode(String mode) { + UseLedBar ledBarMode = UseLedBarOff; + if (mode == "co2") { + ledBarMode = UseLedBarCO2; + } else if (mode == "pm") { + ledBarMode = UseLedBarPM; + } else if (mode == "off") { + ledBarMode = UseLedBarOff; + } else { + ledBarMode = UseLedBarOff; + } + return ledBarMode; + } }; AgServer agServer; @@ -1664,7 +1688,11 @@ static String getServerSyncData(bool localServer) { root["pm10"] = pm10_1; } if (pm03PCount_1 >= 0) { - root["pm003_count"] = pm03PCount_1; + if (localServer) { + root["pm003Count"] = pm03PCount_1; + } else { + root["pm003_count"] = pm03PCount_1; + } } if (temp_1 > -1001) { root["atmp"] = ag.round2(temp_1); @@ -1683,7 +1711,11 @@ static String getServerSyncData(bool localServer) { root["pm10"] = pm10_2; } if (pm03PCount_2 >= 0) { - root["pm003_count"] = pm03PCount_2; + if (localServer) { + root["pm003Count"] = pm03PCount_2; + } else { + root["pm003_count"] = pm03PCount_2; + } } if (temp_2 > -1001) { root["atmp"] = ag.round2(temp_2); @@ -1697,13 +1729,21 @@ static String getServerSyncData(bool localServer) { if ((fw_mode == FW_MODE_PPT) || (fw_mode == FW_MODE_PST)) { if (hasSensorSGP) { if (tvocIndex >= 0) { - root["tvoc_index"] = tvocIndex; + if (localServer) { + root["tvocIndex"] = tvocIndex; + } else { + root["tvoc_index"] = tvocIndex; + } } if (tvocRawIndex >= 0) { root["tvoc_raw"] = tvocRawIndex; } if (noxIndex >= 0) { - root["nox_index"] = noxIndex; + if (localServer) { + root["noxIndex"] = noxIndex; + } else { + root["nox_index"] = noxIndex; + } } if (noxRawIndex >= 0) { root["nox_raw"] = noxRawIndex; @@ -1716,7 +1756,11 @@ static String getServerSyncData(bool localServer) { root["pm01"] = ag.round2((pm01_1 + pm01_2) / 2.0); root["pm02"] = ag.round2((pm25_1 + pm25_2) / 2.0); root["pm10"] = ag.round2((pm10_1 + pm10_2) / 2.0); - root["pm003_count"] = ag.round2((pm03PCount_1 + pm03PCount_2) / 2.0); + if (localServer) { + root["pm003Count"] = ag.round2((pm03PCount_1 + pm03PCount_2) / 2.0); + } else { + root["pm003_count"] = ag.round2((pm03PCount_1 + pm03PCount_2) / 2.0); + } root["atmp"] = ag.round2((temp_1 + temp_2) / 2.0); root["rhum"] = ag.round2((hum_1 + hum_2) / 2.0); } @@ -1724,7 +1768,11 @@ static String getServerSyncData(bool localServer) { root["channels"]["1"]["pm01"] = pm01_1; root["channels"]["1"]["pm02"] = pm25_1; root["channels"]["1"]["pm10"] = pm10_1; - root["channels"]["1"]["pm003_count"] = pm03PCount_1; + if (localServer) { + root["channels"]["1"]["pm003Count"] = pm03PCount_1; + } else { + root["channels"]["1"]["pm003_count"] = pm03PCount_1; + } root["channels"]["1"]["atmp"] = ag.round2(temp_1); root["channels"]["1"]["rhum"] = hum_1; } @@ -1732,12 +1780,21 @@ static String getServerSyncData(bool localServer) { root["channels"]["2"]["pm01"] = pm01_2; root["channels"]["2"]["pm02"] = pm25_2; root["channels"]["2"]["pm10"] = pm10_2; - root["channels"]["2"]["pm003_count"] = pm03PCount_2; + if (localServer) { + root["channels"]["2"]["pm003Count"] = pm03PCount_2; + } else { + root["channels"]["2"]["pm003_count"] = pm03PCount_2; + } root["channels"]["2"]["atmp"] = ag.round2(temp_2); root["channels"]["2"]["rhum"] = hum_2; } } + if (localServer) { + root["ledMode"] = agServer.getLedBarModeName(); + root["firmwareVersion"] = ag.getVersion(); + } + return JSON.stringify(root); } From aceecde7b6193510ceb61535e01121676093ee8f Mon Sep 17 00:00:00 2001 From: Phat Nguyen Date: Sat, 16 Mar 2024 10:02:59 +0700 Subject: [PATCH 7/8] Format code --- examples/ONE/ONE.ino | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/ONE/ONE.ino b/examples/ONE/ONE.ino index 9426246..1bc4d72 100644 --- a/examples/ONE/ONE.ino +++ b/examples/ONE/ONE.ino @@ -528,19 +528,19 @@ private: } UseLedBar parseLedBarMode(String mode) { - UseLedBar ledBarMode = UseLedBarOff; - if (mode == "co2") { - ledBarMode = UseLedBarCO2; - } else if (mode == "pm") { - ledBarMode = UseLedBarPM; - } else if (mode == "off") { - ledBarMode = UseLedBarOff; - } else { - ledBarMode = UseLedBarOff; - } + UseLedBar ledBarMode = UseLedBarOff; + if (mode == "co2") { + ledBarMode = UseLedBarCO2; + } else if (mode == "pm") { + ledBarMode = UseLedBarPM; + } else if (mode == "off") { + ledBarMode = UseLedBarOff; + } else { + ledBarMode = UseLedBarOff; + } - return ledBarMode; - } + return ledBarMode; + } }; AgServer agServer; From ce1373141acf4f883f7bfc5f84555a1f1efc6c13 Mon Sep 17 00:00:00 2001 From: Achim Date: Sat, 16 Mar 2024 11:13:04 +0700 Subject: [PATCH 8/8] Updated version number --- library.properties | 2 +- src/AirGradient.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 37e65a9..a5128b1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AirGradient Air Quality Sensor -version=3.0.7 +version=3.0.8 author=AirGradient maintainer=AirGradient sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. diff --git a/src/AirGradient.cpp b/src/AirGradient.cpp index 294d0db..bc29648 100644 --- a/src/AirGradient.cpp +++ b/src/AirGradient.cpp @@ -1,6 +1,6 @@ #include "AirGradient.h" -#define AG_LIB_VER "3.0.7" +#define AG_LIB_VER "3.0.8" AirGradient::AirGradient(BoardType type) : pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type),