Compare commits

..

52 Commits
3.1.6 ... 3.1.9

Author SHA1 Message Date
c841476ca4 Merge pull request #247 from airgradienthq/fix/pms-read-data
Fix: PMS sensor read failed in case PM value is low
2024-09-24 20:45:04 +07:00
359394af53 fix: compile failed for esp32-c3 2024-09-24 20:13:01 +07:00
b8e10f473e update API change on example 2024-09-24 20:07:31 +07:00
cb511903ef Update the API use Stream instead of Hardware/Software serial 2024-09-24 20:07:14 +07:00
ebb3f01dcd set active mode on init 2024-09-24 10:39:17 +07:00
2e0ba26c97 Merge commit '0370a8aa15ffaf776f9055f84b5d7c221046b9be' into fix/pms-read-data 2024-09-24 10:39:04 +07:00
c1a4758c6c update timeout handle 2024-09-24 10:28:41 +07:00
0370a8aa15 Update AirGradient.h to 3.1.9 2024-09-24 10:05:04 +07:00
863a37132a Update library.properties to 3.1.9 2024-09-24 10:04:28 +07:00
612317d976 Update local-server config example 2024-09-24 09:46:18 +07:00
8873bacf55 Merge pull request #243 from airgradienthq/feature/add-pm-configuratin-for-display
Add configuration: monitorDisplayCompensatedValues
2024-09-24 09:42:50 +07:00
bf2388b121 Merge pull request #241 from DmitryPustovit/support-display-disable-for-diy-board
Added support clearing display at 0 brightness for DIY Boards
2024-09-24 09:41:01 +07:00
b3918bd1fb Merge pull request #242 from airgradienthq/hw-watchdog-feed
Update hardware watchdog reset
2024-09-24 09:40:11 +07:00
2a6fce674e add variable comment 2024-09-23 06:51:01 +07:00
2f0663ced0 Merge pull request #246 from airgradienthq/fix/display-msg
Fix showing "Server N/A" when postDataToAirGradient is false
2024-09-22 14:26:17 +07:00
3adf58537a Changed error message 2024-09-22 14:13:24 +07:00
e10c9ff854 Update status notification in 1 function call 2024-09-22 13:18:15 +07:00
12c6ec9910 format code 2024-09-21 17:48:18 +07:00
d108b63a57 Update read proccess 2024-09-21 17:47:59 +07:00
6e212714fc Fix/mqtt-log (#235)
Ignore init mqtt when it's not configured
2024-09-21 14:57:05 +07:00
866684eb30 fix load configuration value changed 2024-09-21 14:26:06 +07:00
9d01479406 Update show PM compensate value on display and documents 2024-09-21 14:08:42 +07:00
20245f2110 Saving work 2024-09-21 13:06:01 +07:00
3890919f54 Update log message 2024-09-21 08:46:05 +07:00
76e40fea8c let hw watchdog run independently of POST success 2024-09-21 08:09:58 +07:00
c4024f49fb Added support clearing display at 0 brightness for DIY Boards to AgOledDisplay.
Currently, the only affect the brightness setting has with the DIY boards is an attempt to set the contrast. 

Setting the contrast to 0 does not have any effect. 
This appears to be a know limitation for these display boards.
2024-09-20 00:36:34 -07:00
ca5fc8d65b fix WiFi reset 2024-09-18 12:10:23 +07:00
fd2cef153e Merge pull request #239 from airgradienthq/hotfix/led-bar-show-pm-status
Fix: Correct LED bar show PM status
2024-09-17 10:25:42 +07:00
507b958fdf Correct LED bar show PM value use compensate 2024-09-17 10:15:47 +07:00
335c29ebb1 Merge remote-tracking branch 'origin/develop' into hotfix/led-bar-show-pm-status 2024-09-17 10:01:58 +07:00
2907d6f14e Merge pull request #238 from airgradienthq/hotfix/PM-compensation-receiving-temperature-instead-of-RH
Fix pm compensation: receiving temperature instead of humidity
2024-09-17 09:44:50 +07:00
c8d5b546ed correct PM compensate the input argument value humidity instead of temperature, fix #234 2024-09-16 14:52:04 +07:00
b7cfdc4c4d Update AirGradient.h to v 3.1.8 2024-09-16 12:47:50 +07:00
994d281e02 Update Version to 3.1.8 2024-09-16 12:47:08 +07:00
39470384e4 Merge pull request #233 from airgradienthq/cubic-PM2009X
Changed PM initialization to also support the Cubic PM2009X
2024-09-16 12:08:18 +07:00
c25ba764bf Merge pull request #236 from airgradienthq/add-log-pms-version-code
Add log: PMS5003x sensor print log firmware version
2024-09-16 11:02:32 +07:00
826ff00f42 add log message PM sensor firmware version 2024-09-16 10:36:45 +07:00
520550037d Explicitly set active mode for PM sensor upon initialization 2024-09-15 08:26:38 +07:00
90f336dee7 Revert "Explicitly set active mode for PM sensor upon initialization"
This reverts commit 0d39643e76.
2024-09-15 08:23:32 +07:00
0d39643e76 Explicitly set active mode for PM sensor upon initialization 2024-09-15 08:22:50 +07:00
21232ec49d Optimize PMS sensor read data on active mode send each second 2024-09-14 14:05:35 +07:00
b7339de31f Merge pull request #232 from samuelbles07/feat/ag-client-timeout
Feat/ag-client-timeout
2024-09-12 15:06:23 +07:00
013fb94307 Only for tcp timeout
Ignoring connect to server timeout
2024-09-11 16:37:50 +07:00
e16373a64d Add new public member to set http client timeout by caller 2024-09-11 16:02:13 +07:00
f929623443 Fix uri formatting postToServer to use apiRoot 2024-09-11 16:01:16 +07:00
59587ce2b7 Add http request timeout number for ApiClient 2024-09-11 15:48:44 +07:00
9ec74450a5 Merge branch 'master' into develop 2024-09-02 19:56:46 +07:00
28096e9faf Update version to 3.1.7 2024-09-02 19:55:16 +07:00
682378a47c Merge pull request #231 from airgradienthq/develop
Add WiFi feature
2024-09-02 19:53:33 +07:00
a1861be7b7 Merge pull request #230 from airgradienthq/feature/wifi-connect-to-default
Add default WiFi connect
2024-09-02 19:50:47 +07:00
99ddd24432 Merge branch 'develop' into feature/wifi-connect-to-default 2024-09-02 19:44:53 +07:00
03e2afbf54 WiFi Connect to default airgradient if WiFi connected is empty 2024-08-26 15:47:49 +07:00
26 changed files with 587 additions and 426 deletions

View File

@ -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 <br> `us-aqi`: USAQI | {"pmStandard": "ugm3"} |
| `ledBarMode` | Mode in which the led bar can be set. | String | `co2`: LED bar displays CO2 <br>`pm`: LED bar displays PM <br>`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 <br>`f` or `F`: Degree Fahrenheit °F | {"temperatureUnit": "c"} |
| `configurationControl` | The configuration source of the device. | String | `both`: Accept local and cloud configuration <br>`local`: Accept only local configuration <br>`cloud`: Accept only cloud configuration | {"configurationControl": "both"} |
| `postDataToAirGradient` | Send data to AirGradient cloud. | Boolean | `true`: Enabled <br>`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) <br> `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 <br> `us-aqi`: USAQI | `{"pmStandard": "ugm3"}` |
| `ledBarMode` | Mode in which the led bar can be set. | String | `co2`: LED bar displays CO2 <br>`pm`: LED bar displays PM <br>`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 <br>`f` or `F`: Degree Fahrenheit °F | `{"temperatureUnit": "c"}` |
| `configurationControl` | The configuration source of the device. | String | `both`: Accept local and cloud configuration <br>`local`: Accept only local configuration <br>`cloud`: Accept only cloud configuration | `{"configurationControl": "both"}` |
| `postDataToAirGradient` | Send data to AirGradient cloud. | Boolean | `true`: Enabled <br>`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) <br> `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) <br> `true`: with compensate | `{"monitorDisplayCompensatedValues": false }` |

View File

@ -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) {
@ -502,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();
@ -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++;
}

View File

@ -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) {
@ -554,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();
@ -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++;
}

View File

@ -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,8 +330,6 @@ static void factoryConfigReset(void) {
// }
/** Reset WIFI */
// WiFi.enableSTA(true); // Incase offline mode
// WiFi.disconnect(true, true);
wifiConnector.reset();
/** Reset local config */
@ -357,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) {
@ -597,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();
@ -608,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();
@ -636,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++;
}

View File

@ -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() {
@ -288,6 +286,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) {
@ -298,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();
@ -382,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");
}
}
@ -423,8 +429,7 @@ static void factoryConfigReset(void) {
}
/** Reset WIFI */
Serial.println("Set wifi connect to 'airgradient' as default");
WiFi.begin("airgradient", "cleanair");
WiFi.disconnect(true, true);
/** Reset local config */
configuration.reset();
@ -443,7 +448,7 @@ static void factoryConfigReset(void) {
/** Show current content cause reset ignore */
factoryBtnPressTime = 0;
if (ag->isOne()) {
appDispHandler();
updateDisplayAndLedBar();
}
}
}
@ -451,7 +456,7 @@ static void factoryConfigReset(void) {
if (factoryBtnPressTime != 0) {
if (ag->isOne()) {
/** Restore last display content */
appDispHandler();
updateDisplayAndLedBar();
}
}
factoryBtnPressTime = 0;
@ -460,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) {
@ -698,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) {
@ -779,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");
}
}
}
@ -807,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) {
@ -943,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();
@ -1010,7 +997,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();
@ -1021,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();
@ -1039,7 +1027,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();
@ -1060,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 {
@ -1082,7 +1071,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();
@ -1103,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 {
@ -1238,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++;
}
@ -1271,4 +1259,4 @@ static void tempHumUpdate(void) {
measurements.Humidity = utils::getInvalidHumidity();
Serial.println("SHT read failed");
}
}
}

View File

@ -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",
@ -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;
}

View File

@ -1,5 +1,5 @@
name=AirGradient Air Quality Sensor
version=3.1.6
version=3.1.9
author=AirGradient <support@airgradient.com>
maintainer=AirGradient <support@airgradient.com>
sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display.

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;

View File

@ -82,6 +82,7 @@ public:
void setOfflineMode(bool offline);
void setOfflineModeWithoutSave(bool offline);
bool isLedBarModeChanged(void);
bool isMonitorDisplayCompensatedValues(void);
};
#endif /** _AG_CONFIG_H_ */

View File

@ -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()) {

View File

@ -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);

View File

@ -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());
}

View File

@ -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] =

View File

@ -41,6 +41,28 @@ bool WifiConnector::connect(void) {
}
}
WiFi.begin();
String wifiSSID = WIFI()->getWiFiSSID(true);
if (wifiSSID.isEmpty()) {
logInfo("Connected WiFi is empty, connect to default wifi \"" +
String(this->defaultSsid) + String("\""));
/** Set wifi connect */
WiFi.begin(this->defaultSsid, this->defaultPassword);
/** Wait for wifi connect to AP */
int count = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
count++;
if (count >= 15) {
logError("Try connect to default wifi \"" + String(this->defaultSsid) +
String("\" failed"));
break;
}
}
}
WIFI()->setConfigPortalBlocking(false);
WIFI()->setConnectTimeout(15);
WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
@ -50,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...");
}
@ -383,3 +405,11 @@ bool WifiConnector::hasConfigurated(void) {
* @return false
*/
bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; }
/**
* @brief Set wifi connect to default WiFi
*
*/
void WifiConnector::setDefault(void) {
WiFi.begin("airgradient", "cleanair");
}

View File

@ -46,6 +46,10 @@ public:
String localIpStr(void);
bool hasConfigurated(void);
bool isConfigurePorttalTimeout(void);
const char* defaultSsid = "airgradient";
const char* defaultPassword = "cleanair";
void setDefault(void);
};
#endif /** _AG_WIFI_CONNECTOR_H_ */

View File

@ -15,7 +15,7 @@
#include "Main/utils.h"
#ifndef GIT_VERSION
#define GIT_VERSION "3.1.6-snap"
#define GIT_VERSION "3.1.9-snap"
#endif
/**

View File

@ -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;
}

View File

@ -24,6 +24,7 @@ public:
static int getInvalidPmValue(void);
static int getInvalidNOx(void);
static int getInvalidVOC(void);
static float degreeC_To_F(float t);
};

View File

@ -2,155 +2,162 @@
#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
* @return false Failure
*/
bool PMSBase::begin(Stream *stream) {
this->stream = stream;
Serial.printf("initializing PM sensor\n");
failed = true;
failCount = 0;
lastRead = 0; // To read buffer on handle without wait after 1.5sec
_connected = false;
this->stream->flush();
// 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 = stream->write(activeModeCommand, sizeof(activeModeCommand));
Serial.printf("%d byte(s) written\n", bytesWritten);
// Run and check sensor data for 4sec
while (1) {
handle();
if (failed == false) {
return true;
unsigned long lastInit = millis();
while (true) {
readPackage(stream);
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;
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) {
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 {
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;
lastReadPackage = millis();
if (!lastReadPackage) {
lastReadPackage = 1;
}
}
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: {
/** 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 */
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: /** Frame length */
if (value == 0x1C) {
readBuffer[readBufferIndex++] = value;
} else {
readBufferIndex = 0;
}
break;
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;
}
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;
}
// Reduce core panic: delay 1 ms each 32bytes data
bcount++;
if ((bcount % 32) == 0) {
/** Avoid task watchdog timer reset... */
delayCount++;
if (delayCount >= 32) {
delayCount = 0;
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 >= READ_PACKGE_TIMEOUT) {
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
*
*
*/
void PMSBase::updateFailCount(void) {
if (failCount < failCountMax) {
@ -162,8 +169,8 @@ void PMSBase::resetFailCount(void) { failCount = 0; }
/**
* @brief Get number of fail
*
* @return int
*
* @return int
*/
int PMSBase::getFailCount(void) { return failCount; }
@ -174,112 +181,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
*
* @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
*
* @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
@ -308,12 +317,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;
@ -337,7 +346,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;
}
@ -350,13 +359,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 +378,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];
}

View File

@ -5,11 +5,13 @@
#define PMS_FAIL_COUNT_SET_INVALID 3
/**
* Known to work with these sensors: Plantower PMS5003, Plantower PMS5003, Cubic PM2009X
*/
class PMSBase {
public:
bool begin(Stream *stream);
void handle();
bool isFailed(void);
void readPackage(Stream *stream);
void updateFailCount(void);
void resetFailCount(void);
int getFailCount(void);
@ -24,6 +26,7 @@ public:
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 +42,48 @@ public:
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;
/** 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;
int16_t toI16(char *buf);
uint16_t toU16(char* buf);
bool validate(char *buf);
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;
unsigned long lastReadPackage = 0;
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_ */

View File

@ -3,7 +3,6 @@
#include "../Main/utils.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
/**
* @brief Init sensor
*
@ -38,14 +37,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;
}
@ -63,11 +59,10 @@ 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;
}
@ -148,6 +143,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 +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.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();

View File

@ -4,6 +4,9 @@
#include "../Main/BoardDef.h"
#include "PMS.h"
#include "Stream.h"
#ifdef ESP8266
#include <SoftwareSerial.h>
#endif
/**
* @brief The class define how to handle PMS5003 sensor bas on @ref PMS class
@ -18,7 +21,6 @@ public:
#endif
void end(void);
void handle(void);
bool isFailed(void);
void updateFailCount(void);
void resetFailCount(void);
int getFailCount(void);
@ -31,6 +33,7 @@ public:
int compensate(int pm25, float humidity);
int getFirmwareVersion(void);
uint8_t getErrorCode(void);
bool connected(void);
private:
bool _isBegin = false;
@ -41,6 +44,7 @@ private:
#if defined(ESP8266)
Stream *_debugStream;
const char *TAG = "PMS5003";
SoftwareSerial *_serial;
#else
HardwareSerial *_serial;
#endif

View File

@ -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;
}
@ -191,6 +190,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 +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.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();

View File

@ -6,6 +6,9 @@
#include "PMS5003TBase.h"
#include "Stream.h"
#include <HardwareSerial.h>
#ifdef ESP8266
#include <SoftwareSerial.h>
#endif
/**
* @brief The class define how to handle PMS5003T sensor bas on @ref PMS class
@ -21,7 +24,6 @@ public:
void end(void);
void handle(void);
bool isFailed(void);
void updateFailCount(void);
void resetFailCount(void);
int getFailCount(void);
@ -36,6 +38,7 @@ public:
int compensate(int pm25, float humidity);
int getFirmwareVersion(void);
uint8_t getErrorCode(void);
bool connected(void);
private:
bool _isBegin = false;
@ -47,6 +50,7 @@ private:
#if defined(ESP8266)
Stream *_debugStream;
const char *TAG = "PMS5003T";
SoftwareSerial *_serial;
#else
HardwareSerial *_serial;
#endif