diff --git a/docs/local-server.md b/docs/local-server.md index 1daede0..307ad8c 100644 --- a/docs/local-server.md +++ b/docs/local-server.md @@ -41,33 +41,35 @@ You get the following response: "bootCount": 6, "ledMode": "pm", "firmware": "3.1.3", - "model": "I-9PSL" + "model": "I-9PSL", + "monitorDisplayCompensatedValues": true } ``` -| Properties | Type | Explanation | -|------------------|--------|--------------------------------------------------------------------| -| `serialno` | String | Serial Number of the monitor | -| `wifi` | Number | WiFi signal strength | -| `pm01` | Number | PM1 in ug/m3 | -| `pm02` | Number | PM2.5 in ug/m3 | -| `pm10` | Number | PM10 in ug/m3 | -| `pm02Compensated` | Number | PM2.5 in ug/m3 with correction applied (from fw version 3.1.4 onwards) | -| `rco2` | Number | CO2 in ppm | -| `pm003Count` | Number | Particle count per dL | -| `atmp` | Number | Temperature in Degrees Celsius | -| `atmpCompensated` | Number | Temperature in Degrees Celsius with correction applied | -| `rhum` | Number | Relative Humidity | -| `rhumCompensated` | Number | Relative Humidity with correction applied | -| `tvocIndex` | Number | Senisiron VOC Index | -| `tvocRaw` | Number | VOC raw value | -| `noxIndex` | Number | Senisirion NOx Index | -| `noxRaw` | Number | NOx raw value | -| `boot` | Number | Counts every measurement cycle. Low boot counts indicate restarts. | -| `bootCount` | Number | Same as boot property. Required for Home Assistant compatability. Will be depreciated. | -| `ledMode` | String | Current configuration of the LED mode | -| `firmware` | String | Current firmware version | -| `model` | String | Current model name | +| Properties | Type | Explanation | +|-----------------------------------|---------|----------------------------------------------------------------------------------------| +| `serialno` | String | Serial Number of the monitor | +| `wifi` | Number | WiFi signal strength | +| `pm01` | Number | PM1 in ug/m3 | +| `pm02` | Number | PM2.5 in ug/m3 | +| `pm10` | Number | PM10 in ug/m3 | +| `pm02Compensated` | Number | PM2.5 in ug/m3 with correction applied (from fw version 3.1.4 onwards) | +| `rco2` | Number | CO2 in ppm | +| `pm003Count` | Number | Particle count per dL | +| `atmp` | Number | Temperature in Degrees Celsius | +| `atmpCompensated` | Number | Temperature in Degrees Celsius with correction applied | +| `rhum` | Number | Relative Humidity | +| `rhumCompensated` | Number | Relative Humidity with correction applied | +| `tvocIndex` | Number | Senisiron VOC Index | +| `tvocRaw` | Number | VOC raw value | +| `noxIndex` | Number | Senisirion NOx Index | +| `noxRaw` | Number | NOx raw value | +| `boot` | Number | Counts every measurement cycle. Low boot counts indicate restarts. | +| `bootCount` | Number | Same as boot property. Required for Home Assistant compatability. Will be depreciated. | +| `ledMode` | String | Current configuration of the LED mode | +| `firmware` | String | Current firmware version | +| `model` | String | Current model name | +| `monitorDisplayCompensatedValues` | Boolean | Switching Display of AirGradient ONE to Compensated / Non Compensated Values | Compensated values apply correction algorithms to make the sensor values more accurate. Temperature and relative humidity correction is only applied on the outdoor monitor Open Air but the properties _compensated will still be send also for the indoor monitor AirGradient ONE. @@ -75,17 +77,21 @@ Compensated values apply correction algorithms to make the sensor values more ac With the path "/config" you can get the current configuration. ```json { - "country": "US", + "country": "TH", "pmStandard": "ugm3", "ledBarMode": "pm", - "displayMode": "on", - "abcDays": 30, + "abcDays": 7, "tvocLearningOffset": 12, "noxLearningOffset": 12, "mqttBrokerUrl": "", - "temperatureUnit": "f", - "configurationControl": "both", - "postDataToAirGradient": true + "temperatureUnit": "c", + "configurationControl": "local", + "postDataToAirGradient": true, + "ledBarBrightness": 100, + "displayBrightness": 100, + "offlineMode": false, + "model": "I-9PSL", + "monitorDisplayCompensatedValues": true } ``` @@ -110,21 +116,22 @@ If the monitor is set up on the AirGradient dashboard, it will also receive conf #### Configuration Parameters (GET/PUT) -| Properties | Description | Type | Accepted Values | Example | -|-------------------------|:-------------------------------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------| -| `country` | Country where the device is. | String | Country code as [ALPHA-2 notation](https://www.iban.com/country-codes) | {"country": "TH"} | -| `model` | Hardware identifier (only GET). | String | I-9PSL-DE | {"model": "I-9PSL-DE"} | -| `pmStandard` | Particle matter standard used on the display. | String | `ugm3`: ug/m3
`us-aqi`: USAQI | {"pmStandard": "ugm3"} | -| `ledBarMode` | Mode in which the led bar can be set. | String | `co2`: LED bar displays CO2
`pm`: LED bar displays PM
`off`: Turn off LED bar | {"ledBarMode": "off"} | -| `displayBrightness` | Brightness of the Display. | Number | 0-100 | {"displayBrightness": 50} | -| `ledBarBrightness` | Brightness of the LEDBar. | Number | 0-100 | {"ledBarBrightness": 40} | -| `abcDays` | Number of days for CO2 automatic baseline calibration. | Number | Maximum 200 days. Default 8 days. | {"abcDays": 8} | -| `mqttBrokerUrl` | MQTT broker URL. | String | | {"mqttBrokerUrl": "mqtt://192.168.0.18:1883"} | -| `temperatureUnit` | Temperature unit shown on the display. | String | `c` or `C`: Degree Celsius °C
`f` or `F`: Degree Fahrenheit °F | {"temperatureUnit": "c"} | -| `configurationControl` | The configuration source of the device. | String | `both`: Accept local and cloud configuration
`local`: Accept only local configuration
`cloud`: Accept only cloud configuration | {"configurationControl": "both"} | -| `postDataToAirGradient` | Send data to AirGradient cloud. | Boolean | `true`: Enabled
`false`: Disabled | {"postDataToAirGradient": true} | -| `co2CalibrationRequested` | Can be set to trigger a calibration. | Boolean | `true`: CO2 calibration (400ppm) will be triggered | {"co2CalibrationRequested": true} | -| `ledBarTestRequested` | Can be set to trigger a test. | Boolean | `true` : LEDs will run test sequence | {"ledBarTestRequested": true} | -| `noxLearningOffset` | Set NOx learning gain offset. | Number | 0-720 (default 12) | {"noxLearningOffset": 12} | -| `tvocLearningOffset` | Set VOC learning gain offset. | Number | 0-720 (default 12) | {"tvocLearningOffset": 12} | -| `offlineMode` | Set monitor to run without WiFi. | Boolean | `false`: Disabled (default)
`true`: Enabled | {"offlineMode": true} | +| Properties | Description | Type | Accepted Values | Example | +|-----------------------------------|:-----------------------------------------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------| +| `country` | Country where the device is. | String | Country code as [ALPHA-2 notation](https://www.iban.com/country-codes) | `{"country": "TH"}` | +| `model` | Hardware identifier (only GET). | String | I-9PSL-DE | `{"model": "I-9PSL-DE"}` | +| `pmStandard` | Particle matter standard used on the display. | String | `ugm3`: ug/m3
`us-aqi`: USAQI | `{"pmStandard": "ugm3"}` | +| `ledBarMode` | Mode in which the led bar can be set. | String | `co2`: LED bar displays CO2
`pm`: LED bar displays PM
`off`: Turn off LED bar | `{"ledBarMode": "off"}` | +| `displayBrightness` | Brightness of the Display. | Number | 0-100 | `{"displayBrightness": 50}` | +| `ledBarBrightness` | Brightness of the LEDBar. | Number | 0-100 | `{"ledBarBrightness": 40}` | +| `abcDays` | Number of days for CO2 automatic baseline calibration. | Number | Maximum 200 days. Default 8 days. | `{"abcDays": 8}` | +| `mqttBrokerUrl` | MQTT broker URL. | String | | `{"mqttBrokerUrl": "mqtt://192.168.0.18:1883"}` | +| `temperatureUnit` | Temperature unit shown on the display. | String | `c` or `C`: Degree Celsius °C
`f` or `F`: Degree Fahrenheit °F | `{"temperatureUnit": "c"}` | +| `configurationControl` | The configuration source of the device. | String | `both`: Accept local and cloud configuration
`local`: Accept only local configuration
`cloud`: Accept only cloud configuration | `{"configurationControl": "both"}` | +| `postDataToAirGradient` | Send data to AirGradient cloud. | Boolean | `true`: Enabled
`false`: Disabled | `{"postDataToAirGradient": true}` | +| `co2CalibrationRequested` | Can be set to trigger a calibration. | Boolean | `true`: CO2 calibration (400ppm) will be triggered | `{"co2CalibrationRequested": true}` | +| `ledBarTestRequested` | Can be set to trigger a test. | Boolean | `true` : LEDs will run test sequence | `{"ledBarTestRequested": true}` | +| `noxLearningOffset` | Set NOx learning gain offset. | Number | 0-720 (default 12) | `{"noxLearningOffset": 12}` | +| `tvocLearningOffset` | Set VOC learning gain offset. | Number | 0-720 (default 12) | `{"tvocLearningOffset": 12}` | +| `offlineMode` | Set monitor to run without WiFi. | Boolean | `false`: Disabled (default)
`true`: Enabled | `{"offlineMode": true}` | +| `monitorDisplayCompensatedValues` | Set the display show the PM value with/without compensate value (From [3.1.9]()) | Boolean | `false`: Without compensate (default)
`true`: with compensate | `{"monitorDisplayCompensatedValues": false }` | diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino index 7419f13..76b5d07 100644 --- a/examples/BASIC/BASIC.ino +++ b/examples/BASIC/BASIC.ino @@ -206,11 +206,7 @@ void loop() { tvocSchedule.run(); } - /** Auto reset watchdog timer if offline mode or postDataToAirGradient */ - if (configuration.isOfflineMode() || - (configuration.isPostDataToAirGradient() == false)) { - watchdogFeedSchedule.run(); - } + watchdogFeedSchedule.run(); /** Check for handle WiFi reconnect */ wifiConnector.handle(); @@ -266,18 +262,23 @@ static void mdnsInit(void) { } static void initMqtt(void) { - if (mqttClient.begin(configuration.getMqttBrokerUri())) { - Serial.println("Setup connect to MQTT broker successful"); + String mqttUri = configuration.getMqttBrokerUri(); + if (mqttUri.isEmpty()) { + Serial.println( + "MQTT is not configured, skipping initialization of MQTT client"); + return; + } + + if (mqttClient.begin(mqttUri)) { + Serial.println("Successfully connected to MQTT broker"); } else { - Serial.println("setup Connect to MQTT broker failed"); + Serial.println("Connection to MQTT broker failed"); } } static void wdgFeedUpdate(void) { ag.watchdog.reset(); - Serial.println(); - Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset"); - Serial.println(); + Serial.println("External watchdog feed!"); } static bool sgp41Init(void) { @@ -513,6 +514,7 @@ static void updatePm(void) { Serial.printf("PM2.5 ug/m3: %d\r\n", measurements.pm25_1); Serial.printf("PM10 ug/m3: %d\r\n", measurements.pm10_1); Serial.printf("PM0.3 Count: %d\r\n", measurements.pm03PCount_1); + Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion()); ag.pms5003.resetFailCount(); } else { ag.pms5003.updateFailCount(); @@ -541,13 +543,11 @@ static void sendDataToServer(void) { String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), &ag, &configuration); if (apiClient.postToServer(syncData)) { - ag.watchdog.reset(); Serial.println(); Serial.println( "Online mode and isPostToAirGradient = true: watchdog reset"); Serial.println(); } - measurements.bootCount++; } diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino index d842fff..44e401a 100644 --- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino +++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino @@ -204,11 +204,7 @@ void loop() { tvocSchedule.run(); } - /** Auto reset watchdog timer if offline mode or postDataToAirGradient */ - if (configuration.isOfflineMode() || - (configuration.isPostDataToAirGradient() == false)) { - watchdogFeedSchedule.run(); - } + watchdogFeedSchedule.run(); /** Check for handle WiFi reconnect */ wifiConnector.handle(); @@ -264,10 +260,17 @@ static void mdnsInit(void) { } static void initMqtt(void) { - if (mqttClient.begin(configuration.getMqttBrokerUri())) { - Serial.println("Setup connect to MQTT broker successful"); + String mqttUri = configuration.getMqttBrokerUri(); + if (mqttUri.isEmpty()) { + Serial.println( + "MQTT is not configured, skipping initialization of MQTT client"); + return; + } + + if (mqttClient.begin(mqttUri)) { + Serial.println("Successfully connected to MQTT broker"); } else { - Serial.println("setup Connect to MQTT broker failed"); + Serial.println("Connection to MQTT broker failed"); } } @@ -332,9 +335,7 @@ static void factoryConfigReset(void) { static void wdgFeedUpdate(void) { ag.watchdog.reset(); - Serial.println(); - Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset"); - Serial.println(); + Serial.println("External watchdog feed!"); } static bool sgp41Init(void) { @@ -565,6 +566,7 @@ static void updatePm(void) { Serial.printf("PM2.5 ug/m3: %d\r\n", measurements.pm25_1); Serial.printf("PM10 ug/m3: %d\r\n", measurements.pm10_1); Serial.printf("PM0.3 Count: %d\r\n", measurements.pm03PCount_1); + Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion()); ag.pms5003.resetFailCount(); } else { ag.pms5003.updateFailCount(); @@ -593,13 +595,11 @@ static void sendDataToServer(void) { String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), &ag, &configuration); if (apiClient.postToServer(syncData)) { - ag.watchdog.reset(); Serial.println(); Serial.println( "Online mode and isPostToAirGradient = true: watchdog reset"); Serial.println(); } - measurements.bootCount++; } diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino index 305d4a2..ac4a690 100644 --- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino +++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino @@ -231,11 +231,7 @@ void loop() { tvocSchedule.run(); } - /** Auto reset watchdog timer if offline mode or postDataToAirGradient */ - if (configuration.isOfflineMode() || - (configuration.isPostDataToAirGradient() == false)) { - watchdogFeedSchedule.run(); - } + watchdogFeedSchedule.run(); /** Check for handle WiFi reconnect */ wifiConnector.handle(); @@ -291,10 +287,17 @@ static void mdnsInit(void) { } static void initMqtt(void) { - if (mqttClient.begin(configuration.getMqttBrokerUri())) { - Serial.println("Setup connect to MQTT broker successful"); + String mqttUri = configuration.getMqttBrokerUri(); + if (mqttUri.isEmpty()) { + Serial.println( + "MQTT is not configured, skipping initialization of MQTT client"); + return; + } + + if (mqttClient.begin(mqttUri)) { + Serial.println("Successfully connected to MQTT broker"); } else { - Serial.println("setup Connect to MQTT broker failed"); + Serial.println("Connection to MQTT broker failed"); } } @@ -327,7 +330,7 @@ static void factoryConfigReset(void) { // } /** Reset WIFI */ - WiFi.disconnect(true, true); + wifiConnector.reset(); /** Reset local config */ configuration.reset(); @@ -355,9 +358,7 @@ static void factoryConfigReset(void) { static void wdgFeedUpdate(void) { ag.watchdog.reset(); - Serial.println(); - Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset"); - Serial.println(); + Serial.println("External watchdog feed!"); } static bool sgp41Init(void) { @@ -606,6 +607,7 @@ static void updatePm(void) { Serial.printf("PM2.5 ug/m3: %d\r\n", measurements.pm25_1); Serial.printf("PM10 ug/m3: %d\r\n", measurements.pm10_1); Serial.printf("PM0.3 Count: %d\r\n", measurements.pm03PCount_1); + Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion()); ag.pms5003.resetFailCount(); } else { ag.pms5003.updateFailCount(); @@ -634,13 +636,11 @@ static void sendDataToServer(void) { String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), &ag, &configuration); if (apiClient.postToServer(syncData)) { - ag.watchdog.reset(); Serial.println(); Serial.println( "Online mode and isPostToAirGradient = true: watchdog reset"); Serial.println(); } - measurements.bootCount++; } diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 45ab1c1..f4bf37b 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -98,9 +98,7 @@ static String fwNewVersion; static void boardInit(void); static void failedHandler(String msg); static void configurationUpdateSchedule(void); -static void appLedHandler(void); -static void appDispHandler(void); -static void oledDisplayLedBarSchedule(void); +static void updateDisplayAndLedBar(void); static void updateTvoc(void); static void updatePm(void); static void sendDataToServer(void); @@ -118,7 +116,7 @@ static void otaHandlerCallback(OtaState state, String mesasge); static void displayExecuteOta(OtaState state, String msg, int processing); -AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, oledDisplayLedBarSchedule); +AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDisplayAndLedBar); AgSchedule configSchedule(SERVER_CONFIG_SYNC_INTERVAL, configurationUpdateSchedule); AgSchedule agApiPostSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); @@ -261,8 +259,8 @@ void setup() { oledDisplay.setBrightness(configuration.getDisplayBrightness()); } - appLedHandler(); - appDispHandler(); + // Update display and led bar after finishing setup to show dashboard + updateDisplayAndLedBar(); } void loop() { @@ -303,11 +301,7 @@ void loop() { } } - /** Auto reset watchdog timer if offline mode or postDataToAirGradient */ - if (configuration.isOfflineMode() || - (configuration.isPostDataToAirGradient() == false)) { - watchdogFeedSchedule.run(); - } + watchdogFeedSchedule.run(); /** Check for handle WiFi reconnect */ wifiConnector.handle(); @@ -387,11 +381,18 @@ static void createMqttTask(void) { } static void initMqtt(void) { - if (mqttClient.begin(configuration.getMqttBrokerUri())) { - Serial.println("Connect to MQTT broker successful"); + String mqttUri = configuration.getMqttBrokerUri(); + if (mqttUri.isEmpty()) { + Serial.println( + "MQTT is not configured, skipping initialization of MQTT client"); + return; + } + + if (mqttClient.begin(mqttUri)) { + Serial.println("Successfully connected to MQTT broker"); createMqttTask(); } else { - Serial.println("Connect to MQTT broker failed"); + Serial.println("Connection to MQTT broker failed"); } } @@ -447,7 +448,7 @@ static void factoryConfigReset(void) { /** Show current content cause reset ignore */ factoryBtnPressTime = 0; if (ag->isOne()) { - appDispHandler(); + updateDisplayAndLedBar(); } } } @@ -455,7 +456,7 @@ static void factoryConfigReset(void) { if (factoryBtnPressTime != 0) { if (ag->isOne()) { /** Restore last display content */ - appDispHandler(); + updateDisplayAndLedBar(); } } factoryBtnPressTime = 0; @@ -464,9 +465,7 @@ static void factoryConfigReset(void) { static void wdgFeedUpdate(void) { ag->watchdog.reset(); - Serial.println(); - Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset"); - Serial.println(); + Serial.println("External watchdog feed!"); } static void ledBarEnabledUpdate(void) { @@ -702,7 +701,7 @@ static void oneIndoorInit(void) { ledBarEnabledUpdate(); /** Show message init sensor */ - oledDisplay.setText("Sensor", "initializing...", ""); + oledDisplay.setText("Monitor", "initializing...", ""); /** Init sensor SGP41 */ if (sgp41Init() == false) { @@ -783,27 +782,27 @@ static void openAirInit(void) { } } - /** Try to find the PMS on other difference port with S8 */ + /** Attempt to detect PM sensors */ if (fwMode == FW_MODE_O_1PST) { bool pmInitSuccess = false; if (serial0Available) { if (ag->pms5003t_1.begin(Serial0) == false) { configuration.hasSensorPMS1 = false; - Serial.println("PMS1 sensor not found"); + Serial.println("No PM sensor detected on Serial0"); } else { serial0Available = false; pmInitSuccess = true; - Serial.println("Found PMS 1 on Serial0"); + Serial.println("Detected PM 1 on Serial0"); } } if (pmInitSuccess == false) { if (serial1Available) { if (ag->pms5003t_1.begin(Serial1) == false) { configuration.hasSensorPMS1 = false; - Serial.println("PMS1 sensor not found"); + Serial.println("No PM sensor detected on Serial1"); } else { serial1Available = false; - Serial.println("Found PMS 1 on Serial1"); + Serial.println("Detected PM 1 on Serial1"); } } } @@ -811,15 +810,15 @@ static void openAirInit(void) { } else { if (ag->pms5003t_1.begin(Serial0) == false) { configuration.hasSensorPMS1 = false; - Serial.println("PMS1 sensor not found"); + Serial.println("No PM sensor detected on Serial0"); } else { - Serial.println("Found PMS 1 on Serial0"); + Serial.println("Detected PM 1 on Serial0"); } if (ag->pms5003t_2.begin(Serial1) == false) { configuration.hasSensorPMS2 = false; - Serial.println("PMS2 sensor not found"); + Serial.println("No PM sensor detected on Serial1"); } else { - Serial.println("Found PMS 2 on Serial1"); + Serial.println("Detected PM 2 on Serial1"); } if (fwMode == FW_MODE_O_1PP) { @@ -947,57 +946,41 @@ static void configUpdateHandle() { stateMachine.executeLedBarTest(); } - appDispHandler(); - appLedHandler(); + // Update display and led bar notification based on updated configuration + updateDisplayAndLedBar(); } -static void appLedHandler(void) { +static void updateDisplayAndLedBar(void) { + if (factoryBtnPressTime != 0) { + // Do not distrub factory reset sequence countdown + return; + } + + if (configuration.isOfflineMode()) { + // Ignore network related status when in offline mode + stateMachine.displayHandle(AgStateMachineNormal); + stateMachine.handleLeds(AgStateMachineNormal); + return; + } + AgStateMachineState state = AgStateMachineNormal; - if (configuration.isOfflineMode() == false) { - if (wifiConnector.isConnected() == false) { - state = AgStateMachineWiFiLost; - } else if (apiClient.isFetchConfigureFailed()) { - state = AgStateMachineSensorConfigFailed; - } else if (apiClient.isPostToServerFailed()) { - state = AgStateMachineServerLost; + if (wifiConnector.isConnected() == false) { + state = AgStateMachineWiFiLost; + } else if (apiClient.isFetchConfigureFailed()) { + state = AgStateMachineSensorConfigFailed; + if (apiClient.isNotAvailableOnDashboard()) { + stateMachine.displaySetAddToDashBoard(); + } else { + stateMachine.displayClearAddToDashBoard(); } + } else if (apiClient.isPostToServerFailed() && configuration.isPostDataToAirGradient()) { + state = AgStateMachineServerLost; } + stateMachine.displayHandle(state); stateMachine.handleLeds(state); } -static void appDispHandler(void) { - if (ag->isOne()) { - AgStateMachineState state = AgStateMachineNormal; - - /** Only show display status on online mode. */ - if (configuration.isOfflineMode() == false) { - if (wifiConnector.isConnected() == false) { - state = AgStateMachineWiFiLost; - } else if (apiClient.isFetchConfigureFailed()) { - state = AgStateMachineSensorConfigFailed; - if (apiClient.isNotAvailableOnDashboard()) { - stateMachine.displaySetAddToDashBoard(); - } else { - stateMachine.displayClearAddToDashBoard(); - } - } else if (apiClient.isPostToServerFailed()) { - state = AgStateMachineServerLost; - } - } - stateMachine.displayHandle(state); - } -} - -static void oledDisplayLedBarSchedule(void) { - if (ag->isOne()) { - if (factoryBtnPressTime == 0) { - appDispHandler(); - } - } - appLedHandler(); -} - static void updateTvoc(void) { measurements.TVOC = ag->sgp41.getTvocIndex(); measurements.TVOCRaw = ag->sgp41.getTvocRaw(); @@ -1025,10 +1008,11 @@ static void updatePm(void) { Serial.printf("PM2.5 ug/m3: %d\r\n", measurements.pm25_1); Serial.printf("PM10 ug/m3: %d\r\n", measurements.pm10_1); Serial.printf("PM0.3 Count: %d\r\n", measurements.pm03PCount_1); + Serial.printf("PM firmware version: %d\r\n", ag->pms5003.getFirmwareVersion()); ag->pms5003.resetFailCount(); } else { ag->pms5003.updateFailCount(); - Serial.printf("PMS read faile %d times\r\n", ag->pms5003.getFailCount()); + Serial.printf("PMS read failed %d times\r\n", ag->pms5003.getFailCount()); if (ag->pms5003.getFailCount() >= PMS_FAIL_COUNT_SET_INVALID) { measurements.pm01_1 = utils::getInvalidPmValue(); measurements.pm25_1 = utils::getInvalidPmValue(); @@ -1064,6 +1048,7 @@ static void updatePm(void) { ag->pms5003t_1.compensateTemp(measurements.temp_1)); Serial.printf("[1] Relative Humidity compensated: %0.2f\r\n", ag->pms5003t_1.compensateHum(measurements.hum_1)); + Serial.printf("[1] PM firmware version: %d\r\n", ag->pms5003t_1.getFirmwareVersion()); ag->pms5003t_1.resetFailCount(); } else { @@ -1107,6 +1092,7 @@ static void updatePm(void) { ag->pms5003t_1.compensateTemp(measurements.temp_2)); Serial.printf("[2] Relative Humidity compensated: %0.2f\r\n", ag->pms5003t_1.compensateHum(measurements.hum_2)); + Serial.printf("[2] PM firmware version: %d\r\n", ag->pms5003t_2.getFirmwareVersion()); ag->pms5003t_2.resetFailCount(); } else { @@ -1242,13 +1228,11 @@ static void sendDataToServer(void) { String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), ag, &configuration); if (apiClient.postToServer(syncData)) { - ag->watchdog.reset(); Serial.println(); Serial.println( "Online mode and isPostToAirGradient = true: watchdog reset"); Serial.println(); } - measurements.bootCount++; } @@ -1275,4 +1259,4 @@ static void tempHumUpdate(void) { measurements.Humidity = utils::getInvalidHumidity(); Serial.println("SHT read failed"); } -} +} \ No newline at end of file diff --git a/library.properties b/library.properties index f6af924..51de43b 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AirGradient Air Quality Sensor -version=3.1.7 +version=3.1.9 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/AgApiClient.cpp b/src/AgApiClient.cpp index fe582a4..5933c30 100644 --- a/src/AgApiClient.cpp +++ b/src/AgApiClient.cpp @@ -58,6 +58,7 @@ bool AgApiClient::fetchServerConfiguration(void) { } #else HTTPClient client; + client.setTimeout(timeoutMs); if (client.begin(uri) == false) { getConfigFailed = true; return false; @@ -113,14 +114,13 @@ bool AgApiClient::postToServer(String data) { return false; } - String uri = - "http://hw.airgradient.com/sensors/airgradient:" + ag->deviceId() + - "/measures"; + String uri = apiRoot + "/sensors/airgradient:" + ag->deviceId() + "/measures"; // logInfo("Post uri: " + uri); // logInfo("Post data: " + data); WiFiClient wifiClient; HTTPClient client; + client.setTimeout(timeoutMs); if (client.begin(wifiClient, uri.c_str()) == false) { logError("Init client failed"); return false; @@ -190,3 +190,12 @@ bool AgApiClient::sendPing(int rssi, int bootCount) { String AgApiClient::getApiRoot() const { return apiRoot; } void AgApiClient::setApiRoot(const String &apiRoot) { this->apiRoot = apiRoot; } + +/** + * @brief Set http request timeout. (Default: 10s) + * + * @param timeoutMs + */ +void AgApiClient::setTimeout(uint16_t timeoutMs) { + this->timeoutMs = timeoutMs; +} \ No newline at end of file diff --git a/src/AgApiClient.h b/src/AgApiClient.h index 7e6037d..7035323 100644 --- a/src/AgApiClient.h +++ b/src/AgApiClient.h @@ -25,6 +25,7 @@ private: bool getConfigFailed; bool postToServerFailed; bool notAvailableOnDashboard = false; // Device not setup on Airgradient cloud dashboard. + uint16_t timeoutMs = 10000; // Default set to 10s public: AgApiClient(Stream &stream, Configuration &config); @@ -40,6 +41,7 @@ public: bool sendPing(int rssi, int bootCount); String getApiRoot() const; void setApiRoot(const String &apiRoot); + void setTimeout(uint16_t timeoutMs); }; #endif /** _AG_API_CLIENT_H_ */ diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp index 99e00c1..3f3005f 100644 --- a/src/AgConfigure.cpp +++ b/src/AgConfigure.cpp @@ -41,21 +41,23 @@ JSON_PROP_DEF(displayBrightness); JSON_PROP_DEF(co2CalibrationRequested); JSON_PROP_DEF(ledBarTestRequested); JSON_PROP_DEF(offlineMode); +JSON_PROP_DEF(monitorDisplayCompensatedValues); -#define jprop_model_default "" -#define jprop_country_default "TH" -#define jprop_pmStandard_default getPMStandardString(false) -#define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2) -#define jprop_abcDays_default 8 -#define jprop_tvocLearningOffset_default 12 -#define jprop_noxLearningOffset_default 12 -#define jprop_mqttBrokerUrl_default "" -#define jprop_temperatureUnit_default "c" -#define jprop_configurationControl_default String(CONFIGURATION_CONTROL_NAME[ConfigurationControl::ConfigurationControlBoth]) -#define jprop_postDataToAirGradient_default true -#define jprop_ledBarBrightness_default 100 -#define jprop_displayBrightness_default 100 -#define jprop_offlineMode_default false +#define jprop_model_default "" +#define jprop_country_default "TH" +#define jprop_pmStandard_default getPMStandardString(false) +#define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2) +#define jprop_abcDays_default 8 +#define jprop_tvocLearningOffset_default 12 +#define jprop_noxLearningOffset_default 12 +#define jprop_mqttBrokerUrl_default "" +#define jprop_temperatureUnit_default "c" +#define jprop_configurationControl_default String(CONFIGURATION_CONTROL_NAME[ConfigurationControl::ConfigurationControlBoth]) +#define jprop_postDataToAirGradient_default true +#define jprop_ledBarBrightness_default 100 +#define jprop_displayBrightness_default 100 +#define jprop_offlineMode_default false +#define jprop_monitorDisplayCompensatedValues_default false JSONVar jconfig; @@ -167,6 +169,7 @@ void Configuration::defaultConfig(void) { jconfig[jprop_abcDays] = jprop_abcDays_default; jconfig[jprop_model] = jprop_model_default; jconfig[jprop_offlineMode] = jprop_offlineMode_default; + jconfig[jprop_monitorDisplayCompensatedValues] = jprop_monitorDisplayCompensatedValues_default; saveConfig(); } @@ -628,6 +631,27 @@ bool Configuration::parse(String data, bool isLocal) { } } + if (JSON.typeof_(root[jprop_monitorDisplayCompensatedValues]) == "boolean") { + bool value = root[jprop_monitorDisplayCompensatedValues]; + bool oldValue = jconfig[jprop_monitorDisplayCompensatedValues]; + if (value != oldValue) { + changed = true; + jconfig[jprop_monitorDisplayCompensatedValues] = value; + + configLogInfo(String(jprop_monitorDisplayCompensatedValues), + String(oldValue ? "true" : "false"), + String(value ? "true" : "false")); + } + } else { + if (jsonTypeInvalid(root[jprop_monitorDisplayCompensatedValues], + "boolean")) { + failedMessage = jsonTypeInvalidMessage( + String(jprop_monitorDisplayCompensatedValues), "boolean"); + jsonInvalid(); + return false; + } + } + if (ag->getBoardType() == ONE_INDOOR || ag->getBoardType() == OPEN_AIR_OUTDOOR) { if (JSON.typeof_(root["targetFirmware"]) == "string") { @@ -1082,12 +1106,16 @@ void Configuration::toConfig(const char *buf) { } if (JSON.typeof_(jconfig[jprop_offlineMode]) != "boolean") { - isInvalid = true; - } else { - isInvalid = false; + changed = true; + jconfig[jprop_offlineMode] = jprop_offlineMode_default; } - if (isInvalid) { - jconfig[jprop_offlineMode] = false; + + /** Validate monitorDisplayCompensatedValues */ + if (JSON.typeof_(jconfig[jprop_monitorDisplayCompensatedValues]) != + "boolean") { + changed = true; + jconfig[jprop_monitorDisplayCompensatedValues] = + jprop_monitorDisplayCompensatedValues_default; } if (changed) { @@ -1173,6 +1201,10 @@ bool Configuration::isLedBarModeChanged(void) { return changed; } +bool Configuration::isMonitorDisplayCompensatedValues(void) { + return jconfig[jprop_monitorDisplayCompensatedValues]; +} + bool Configuration::isDisplayBrightnessChanged(void) { bool changed = displayBrightnessChanged; displayBrightnessChanged = false; diff --git a/src/AgConfigure.h b/src/AgConfigure.h index 24473ec..a899b64 100644 --- a/src/AgConfigure.h +++ b/src/AgConfigure.h @@ -82,6 +82,7 @@ public: void setOfflineMode(bool offline); void setOfflineModeWithoutSave(bool offline); bool isLedBarModeChanged(void); + bool isMonitorDisplayCompensatedValues(void); }; #endif /** _AG_CONFIG_H_ */ diff --git a/src/AgOledDisplay.cpp b/src/AgOledDisplay.cpp index 109be27..050782a 100644 --- a/src/AgOledDisplay.cpp +++ b/src/AgOledDisplay.cpp @@ -10,37 +10,43 @@ * * @param hasStatus */ -void OledDisplay::showTempHum(bool hasStatus) { - char buf[16]; +void OledDisplay::showTempHum(bool hasStatus, char *buf, int buf_size) { + /** Temperature */ if (utils::isValidTemperature(value.Temperature)) { + float t = 0.0f; + if (config.isTemperatureUnitInF()) { + t = utils::degreeC_To_F(value.Temperature); + } else { + t = value.Temperature; + } + if (config.isTemperatureUnitInF()) { - float tempF = (value.Temperature * 9) / 5 + 32; if (hasStatus) { - snprintf(buf, sizeof(buf), "%0.1f", tempF); + snprintf(buf, buf_size, "%0.1f", t); } else { - snprintf(buf, sizeof(buf), "%0.1f°F", tempF); + snprintf(buf, buf_size, "%0.1f°F", t); } } else { if (hasStatus) { - snprintf(buf, sizeof(buf), "%.1f", value.Temperature); + snprintf(buf, buf_size, "%.1f", t); } else { - snprintf(buf, sizeof(buf), "%.1f°C", value.Temperature); + snprintf(buf, buf_size, "%.1f°C", t); } } - } else { + } else { /** Show invalid value */ if (config.isTemperatureUnitInF()) { - snprintf(buf, sizeof(buf), "-°F"); + snprintf(buf, buf_size, "-°F"); } else { - snprintf(buf, sizeof(buf), "-°C"); + snprintf(buf, buf_size, "-°C"); } } DISP()->drawUTF8(1, 10, buf); - /** Show humidty */ + /** Show humidity */ if (utils::isValidHumidity(value.Humidity)) { - snprintf(buf, sizeof(buf), "%d%%", value.Humidity); + snprintf(buf, buf_size, "%d%%", value.Humidity); } else { - snprintf(buf, sizeof(buf), "-%%"); + snprintf(buf, buf_size, "-%%"); } if (value.Humidity > 99) { @@ -261,7 +267,7 @@ void OledDisplay::showDashboard(const char *status) { do { DISP()->setFont(u8g2_font_t0_16_tf); if ((status == NULL) || (strlen(status) == 0)) { - showTempHum(false); + showTempHum(false, strBuf, sizeof(strBuf)); } else { String strStatus = "Show status: " + String(status); logInfo(strStatus); @@ -272,7 +278,7 @@ void OledDisplay::showDashboard(const char *status) { /** Show WiFi NA*/ if (strcmp(status, "WiFi N/A") == 0) { DISP()->setFont(u8g2_font_t0_12_tf); - showTempHum(true); + showTempHum(true, strBuf, sizeof(strBuf)); } } @@ -304,29 +310,31 @@ void OledDisplay::showDashboard(const char *status) { DISP()->drawStr(55, 27, "PM2.5"); /** Draw PM2.5 value */ - int pm25 = value.pm25_1; - if (config.hasSensorSHT) { - pm25 = ag->pms5003.compensate(pm25, value.Humidity); - logInfo("PM2.5:" + String(value.pm25_1) + String("Compensated:") + String(pm25)); - } - DISP()->setFont(u8g2_font_t0_22b_tf); - if (config.isPmStandardInUSAQI()) { - if (utils::isValidPm(pm25)) { + if (utils::isValidPm(value.pm25_1)) { + int pm25 = value.pm25_1; + + /** Compensate PM2.5 value. */ + if (config.hasSensorSHT && config.isMonitorDisplayCompensatedValues()) { + pm25 = ag->pms5003.compensate(pm25, value.Humidity); + logInfo("PM2.5 compensate: " + String(pm25)); + } + + if (config.isPmStandardInUSAQI()) { sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(pm25)); } else { - sprintf(strBuf, "%s", "-"); + sprintf(strBuf, "%d", pm25); } - DISP()->drawStr(55, 48, strBuf); - DISP()->setFont(u8g2_font_t0_12_tf); + } else { /** Show invalid value. */ + sprintf(strBuf, "%s", "-"); + } + DISP()->setFont(u8g2_font_t0_22b_tf); + DISP()->drawStr(55, 48, strBuf); + + /** Draw PM2.5 unit */ + DISP()->setFont(u8g2_font_t0_12_tf); + if (config.isPmStandardInUSAQI()) { DISP()->drawUTF8(55, 61, "AQI"); } else { - if (utils::isValidPm(pm25)) { - sprintf(strBuf, "%d", pm25); - } else { - sprintf(strBuf, "%s", "-"); - } - DISP()->drawStr(55, 48, strBuf); - DISP()->setFont(u8g2_font_t0_12_tf); DISP()->drawUTF8(55, 61, "ug/m³"); } @@ -355,20 +363,21 @@ void OledDisplay::showDashboard(const char *status) { ag->display.clear(); /** Set CO2 */ - if(utils::isValidCO2(value.CO2)) { + if (utils::isValidCO2(value.CO2)) { snprintf(strBuf, sizeof(strBuf), "CO2:%d", value.CO2); } else { snprintf(strBuf, sizeof(strBuf), "CO2:-"); } - + ag->display.setCursor(0, 0); ag->display.setText(strBuf); /** Set PM */ int pm25 = value.pm25_1; - if(config.hasSensorSHT) { + if (config.hasSensorSHT && config.isMonitorDisplayCompensatedValues()) { pm25 = (int)ag->pms5003.compensate(pm25, value.Humidity); } + ag->display.setCursor(0, 12); if (utils::isValidPm(pm25)) { snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", pm25); @@ -380,8 +389,8 @@ void OledDisplay::showDashboard(const char *status) { /** Set temperature and humidity */ if (utils::isValidTemperature(value.Temperature)) { if (config.isTemperatureUnitInF()) { - float tempF = (value.Temperature * 9) / 5 + 32; - snprintf(strBuf, sizeof(strBuf), "T:%0.1f F", tempF); + snprintf(strBuf, sizeof(strBuf), "T:%0.1f F", + utils::degreeC_To_F(value.Temperature)); } else { snprintf(strBuf, sizeof(strBuf), "T:%0.f1 C", value.Temperature); } @@ -424,7 +433,17 @@ void OledDisplay::setBrightness(int percent) { DISP()->setContrast((127 * percent) / 100); } } else if (ag->isBasic()) { - ag->display.setContrast((255 * percent) / 100); + if (percent == 0) { + isDisplayOff = true; + + // Clear display. + ag->display.clear(); + ag->display.show(); + } + else { + isDisplayOff = false; + ag->display.setContrast((255 * percent) / 100); + } } } @@ -519,7 +538,7 @@ void OledDisplay::showRebooting(void) { do { DISP()->setFont(u8g2_font_t0_16_tf); // setCentralText(20, "Firmware Update"); - setCentralText(40, "Reboot..."); + setCentralText(40, "Rebooting..."); // setCentralText(60, String("Retry after 24h")); } while (DISP()->nextPage()); } else if (ag->isBasic()) { diff --git a/src/AgOledDisplay.h b/src/AgOledDisplay.h index 28a0cba..435ff4c 100644 --- a/src/AgOledDisplay.h +++ b/src/AgOledDisplay.h @@ -16,7 +16,7 @@ private: Measurements &value; bool isDisplayOff = false; - void showTempHum(bool hasStatus); + void showTempHum(bool hasStatus, char* buf, int buf_size); void setCentralText(int y, String text); void setCentralText(int y, const char *text); diff --git a/src/AgStateMachine.cpp b/src/AgStateMachine.cpp index e5566e2..85f87d5 100644 --- a/src/AgStateMachine.cpp +++ b/src/AgStateMachine.cpp @@ -142,6 +142,10 @@ void StateMachine::co2handleLeds(void) { */ void StateMachine::pm25handleLeds(void) { int pm25Value = value.pm25_1; + if (config.isMonitorDisplayCompensatedValues() && config.hasSensorSHT) { + pm25Value = ag->pms5003.compensate(value.pm25_1, value.Humidity); + } + if (pm25Value < 5) { /** G; 1 */ ag->ledBar.setColor(RGB_COLOR_G, ag->ledBar.getNumberOfLeds() - 1); @@ -495,7 +499,7 @@ void StateMachine::displayHandle(AgStateMachineState state) { break; } case AgStateMachineServerLost: { - disp.showDashboard("Server N/A"); + disp.showDashboard("AG Server N/A"); break; } case AgStateMachineSensorConfigFailed: { @@ -504,7 +508,7 @@ void StateMachine::displayHandle(AgStateMachineState state) { if (ms >= 5000) { addToDashboardTime = millis(); if (addToDashBoardToggle) { - disp.showDashboard("Add to Dashboard"); + disp.showDashboard("Add to AG Dashb."); } else { disp.showDashboard(ag->deviceId().c_str()); } diff --git a/src/AgValue.cpp b/src/AgValue.cpp index c7ec1a2..867ee42 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -130,8 +130,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } - int pm25 = (ag->pms5003t_1.compensate(this->pm25_1, this->temp_1) + - ag->pms5003t_2.compensate(this->pm25_2, this->temp_2)) / + int pm25 = (ag->pms5003t_1.compensate(this->pm25_1, this->hum_1) + + ag->pms5003t_2.compensate(this->pm25_2, this->hum_2)) / 2; root["pm02Compensated"] = pm25; } @@ -171,7 +171,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1); if (!localServer) { root[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion()); @@ -212,7 +212,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->temp_2); + root["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->hum_2); if(!localServer) { root[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion()); @@ -253,7 +253,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1); if(!localServer) { root[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion()); @@ -291,7 +291,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->temp_1); + root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1); if(!localServer) { root[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion()); @@ -332,7 +332,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->temp_1); + root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1); // PMS5003T version if(!localServer) { @@ -374,7 +374,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } } - root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->temp_2); + root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->hum_2); // PMS5003T version if(!localServer) { root["channels"]["2"][json_prop_pmFirmware] = diff --git a/src/AgWiFiConnector.cpp b/src/AgWiFiConnector.cpp index ddf4736..66fa34d 100644 --- a/src/AgWiFiConnector.cpp +++ b/src/AgWiFiConnector.cpp @@ -72,7 +72,7 @@ bool WifiConnector::connect(void) { WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); }); WIFI()->setConfigPortalTimeoutCallback([this]() {_wifiTimeoutCallback();}); if (ag->isOne() || (ag->isPro4_2()) || ag->isPro3_3() || ag->isBasic()) { - disp.setText("Connect to", "WiFi", "..."); + disp.setText("Connecting to", "WiFi", "..."); } else { logInfo("Connecting to WiFi..."); } diff --git a/src/AirGradient.h b/src/AirGradient.h index 1a7a0fc..cc187f7 100644 --- a/src/AirGradient.h +++ b/src/AirGradient.h @@ -15,7 +15,7 @@ #include "Main/utils.h" #ifndef GIT_VERSION -#define GIT_VERSION "3.1.7-snap" +#define GIT_VERSION "3.1.9-snap" #endif /** diff --git a/src/Main/utils.cpp b/src/Main/utils.cpp index 42b06a5..33f8618 100644 --- a/src/Main/utils.cpp +++ b/src/Main/utils.cpp @@ -87,3 +87,8 @@ int utils::getInvalidPmValue(void) { return INVALID_PMS; } int utils::getInvalidNOx(void) { return INVALID_NOX; } int utils::getInvalidVOC(void) { return INVALID_VOC; } + +float utils::degreeC_To_F(float t) { + /** (t * 9)/5 + 32 */ + return t * 1.8f + 32.0f; +} diff --git a/src/Main/utils.h b/src/Main/utils.h index b51ac98..6b8452b 100644 --- a/src/Main/utils.h +++ b/src/Main/utils.h @@ -24,6 +24,7 @@ public: static int getInvalidPmValue(void); static int getInvalidNOx(void); static int getInvalidVOC(void); + static float degreeC_To_F(float t); }; diff --git a/src/PMS/PMS.cpp b/src/PMS/PMS.cpp index 3faf919..f77cea1 100644 --- a/src/PMS/PMS.cpp +++ b/src/PMS/PMS.cpp @@ -2,7 +2,7 @@ #include "../Main/BoardDef.h" /** - * @brief Init and check that sensor has connected + * @brief Initializes the sensor and attempts to read data. * * @param stream UART stream * @return true Sucecss diff --git a/src/PMS/PMS.h b/src/PMS/PMS.h index 20872bc..617cdf3 100644 --- a/src/PMS/PMS.h +++ b/src/PMS/PMS.h @@ -5,6 +5,9 @@ #define PMS_FAIL_COUNT_SET_INVALID 3 +/** + * Known to work with these sensors: Plantower PMS5003, Plantower PMS5003, Cubic PM2009X + */ class PMSBase { public: bool begin(HardwareSerial& serial); diff --git a/src/PMS/PMS5003.cpp b/src/PMS/PMS5003.cpp index 3e52896..bf57689 100644 --- a/src/PMS/PMS5003.cpp +++ b/src/PMS/PMS5003.cpp @@ -38,14 +38,11 @@ bool PMS5003::begin(HardwareSerial &serial) { PMS5003::PMS5003(BoardType def) : _boardDef(def) {} /** - * @brief Init sensor - * - * @return true Success - * @return false Failure + * Initializes the sensor. */ bool PMS5003::begin(void) { if (this->_isBegin) { - AgLog("Initialized, call end() then try again"); + AgLog("Already initialized, call end() then try again"); return true; }