Compare commits

..

45 Commits
3.1.4 ... 3.1.5

Author SHA1 Message Date
b1aaa04421 update GIT_BUILD version 2024-08-23 09:12:43 +07:00
186f0d27ab Update version 2024-08-23 08:59:28 +07:00
e25aa87ecc Merge pull request #215 from airgradienthq/develop
Develop
2024-08-23 08:50:04 +07:00
1cc8941a5c csv alignment format 2024-08-22 11:27:25 +07:00
9bf1495be7 Merge branch 'hotfix/firmware-version' into develop 2024-08-22 11:24:26 +07:00
73089b51f5 add firmware version for arduino build 2024-08-22 11:23:53 +07:00
625e60a5bf Merge branch 'hotfix/local-configuration-return-result' into develop 2024-08-21 12:54:47 +07:00
88e3d0bd3f Ignore and return failed if configurationControl is cloud 2024-08-21 12:54:06 +07:00
171821cfcf Merge pull request #214 from airgradienthq/hotfix/api-client-log
API client log post data
2024-08-21 12:28:50 +07:00
900a2da2ac Log POST data 2024-08-21 12:27:56 +07:00
fb57a112c9 Merge pull request #201 from McJoppy/feature/root-api
Reintroduce 'ROOTAPI' so domain and protocol can be configured
2024-08-20 09:25:48 +07:00
ab69b686ec Merge branch 'develop' into feature/root-api 2024-08-20 09:22:36 +07:00
6746d25dc2 Add comment to all example scripts showing how to change APIROOT 2024-08-18 16:46:56 +12:00
be150e105a Merge pull request #204 from airgradienthq/feature/add-http-request-to-ag-log
Add log message HTTP request and response to AG server
2024-08-18 11:37:42 +07:00
ecadeeb156 Merge pull request #209 from airgradienthq/hotfix/json-round-2-decimal-place-support-negative-value
`round2` support negative value
2024-08-18 11:33:39 +07:00
219ff73132 Merge pull request #212 from airgradienthq/feature/correct-pm2.5-formula
correct pm2.5 formula to show value on display
2024-08-18 11:32:50 +07:00
0a9142204d Merge pull request #213 from airgradienthq/hotfix/sensor-value-out-of-range
sensor value out of range
2024-08-18 11:30:27 +07:00
f3a9c722b2 Change pm25Compensated to compensated 2024-08-16 06:39:52 +07:00
3be3218115 Update invalid value and optimize code operator. 2024-08-15 09:11:38 +07:00
5edb21cfe9 Fix: PMS5003T only return positive temperature value 2024-08-15 09:10:48 +07:00
6cd587b008 Merge remote-tracking branch 'origin/develop' into feature/correct-pm2.5-formula 2024-08-15 08:19:10 +07:00
1a347e9cfe Merge pull request #206 from airgradienthq/hotfix/display-show-nox-incorrect-position
`NOx` show incorrect position on display
2024-08-12 09:20:21 +07:00
6432e4451e Merge pull request #210 from airgradienthq/hotfix/set-connect-to-default-wifi-on-factory-reset
Set WiFi connect to default WiFi on factory reset
2024-08-10 07:45:06 +07:00
97f0696002 set default wifi on factory reset. 2024-08-09 13:19:28 +07:00
e46e11c030 round2 support negative value 2024-08-08 05:53:24 +07:00
dc261f668d Update local-server.md II 2024-08-07 11:08:48 +07:00
b5cced40d2 Update local-server.md 2024-08-07 11:05:39 +07:00
b0ae851427 Fix nox position 2024-07-30 20:26:19 +07:00
ed7b8df6fe log URLs of all HTTP requests to AG backend / log status codes of responses 2024-07-29 06:00:54 +07:00
6c1c914716 Merge pull request #196 from airgradienthq/hotfix/led-bar-show-sensor-data-incorrect
Correct LED bar show sensor value level color
2024-07-26 06:16:33 +07:00
6a0d88ff10 Merge pull request #197 from airgradienthq/hotfix/ignore-parameter-out-of-range
Ignore parameter values out of range
2024-07-26 06:12:04 +07:00
9097eed137 [fix] typo comment 2024-07-24 20:31:43 +07:00
c9b5e5f0d7 Merge branch 'develop' into hotfix/ignore-parameter-out-of-range 2024-07-24 20:24:27 +07:00
c12bac4ce3 Update invalid temperature value 2024-07-24 20:19:06 +07:00
9ae9b2ac9c display float value on display with 1 digit 2024-07-24 20:18:48 +07:00
7fb3e68b6d Merge pull request #195 from airgradienthq/hotfix/change-tvoc-to-VOC
Change `tvoc` to `VOC` on display
2024-07-24 09:19:03 +02:00
cf65a1f901 Merge pull request #200 from airgradienthq/feature/doc-quote-properties-name
Update local-server.md
2024-07-24 09:16:09 +02:00
5fb27b6d1e Check value sensor value 2024-07-24 09:05:57 +07:00
7b9dac756b Reintroduce 'ROOTAPI' so domain and protocol can be configured
eg. setter for api root added as comment in examples/BASIC/BASIC.ino
2024-07-21 19:38:50 +12:00
4b2a5f5540 Add PM2.5 correction formula, #182 2024-07-21 07:13:34 +07:00
4af77d532e Update local-server.md
Quote properties name
2024-07-20 09:39:29 +07:00
0ece16f434 Update screen layout, #139 2024-07-18 11:28:12 +07:00
df6cca3714 Ignore parameter values out of range #190 2024-07-11 06:25:31 +07:00
c8aa07ae20 Correct LED bar show sensor value level color, #161 2024-07-09 06:44:04 +07:00
a1d216ac77 Change tvoc to VOC, #139 2024-07-09 06:10:07 +07:00
31 changed files with 807 additions and 347 deletions

View File

@ -47,27 +47,27 @@ You get the following response:
| 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 |
| `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 |
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.
@ -101,6 +101,10 @@ Example to set monitor to Celsius
```curl -X PUT -H "Content-Type: application/json" -d '{"temperatureUnit":"c"}' http://airgradient_84fce612eff4.local/config ```
If you use command prompt on Windows, you need to escape the quotes:
``` -d "{\"param\":\"value\"}" ```
#### Avoiding Conflicts with Configuration on AirGradient Server
If the monitor is set up on the AirGradient dashboard, it will also receive configurations from there. In case you do not want this, please set `configurationControl` to `local`. In case you set it to `cloud` and want to change it to `local`, you need to make a factory reset.
@ -108,19 +112,19 @@ If the monitor is set up on the AirGradient dashboard, it will also receive conf
| 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} |
| `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} |

View File

@ -126,6 +126,9 @@ void setup() {
openMetrics.setAirGradient(&ag);
localServer.setAirGraident(&ag);
/** Example set custom API root URL */
// apiClient.setApiRoot("https://example.custom.api");
/** Init sensor */
boardInit();
@ -233,7 +236,7 @@ void loop() {
static void co2Update(void) {
int value = ag.s8.getCo2();
if (value >= 0) {
if (utils::isValidCO2(value)) {
measurements.CO2 = value;
getCO2FailCount = 0;
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
@ -241,7 +244,7 @@ static void co2Update(void) {
getCO2FailCount++;
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
if (getCO2FailCount >= 3) {
measurements.CO2 = -1;
measurements.CO2 = utils::getInvalidCO2();
}
}
}
@ -516,10 +519,10 @@ static void updatePm(void) {
pmFailCount++;
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
if (pmFailCount >= 3) {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
measurements.pm01_1 = utils::getInvalidPMS();
measurements.pm25_1 = utils::getInvalidPMS();
measurements.pm10_1 = utils::getInvalidPMS();
measurements.pm03PCount_1 = utils::getInvalidPMS();
}
}
}
@ -564,5 +567,7 @@ static void tempHumUpdate(void) {
}
} else {
Serial.println("SHT read failed");
measurements.Temperature = utils::getInvalidTemperature();
measurements.Humidity = utils::getInvalidHumidity();
}
}

View File

@ -65,14 +65,14 @@ String OpenMetrics::getPayload(void) {
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
int atmpCompensated = -1;
int ahumCompensated = -1;
float _temp = utils::getInvalidTemperature();
float _hum = utils::getInvalidHumidity();
int pm01 = utils::getInvalidPMS();
int pm25 = utils::getInvalidPMS();
int pm10 = utils::getInvalidPMS();
int pm03PCount = utils::getInvalidPMS();
int atmpCompensated = utils::getInvalidTemperature();
int ahumCompensated = utils::getInvalidHumidity();
if (config.hasSensorSHT) {
_temp = measure.Temperature;
@ -89,28 +89,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorPMS1) {
if (pm01 >= 0) {
if (utils::isValidPMS(pm01)) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
if (utils::isValidPMS(pm25)) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
if (utils::isValidPMS(pm10)) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
if (utils::isValidPMS03Count(pm03PCount)) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
@ -120,28 +120,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
if (utils::isValidVOC(measure.TVOC)) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
if (utils::isValidVOC(measure.TVOCRaw)) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
if (utils::isValidNOx(measure.NOx)) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
if (utils::isValidNOx(measure.NOxRaw)) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
@ -150,7 +150,7 @@ String OpenMetrics::getPayload(void) {
}
}
if (_temp > -1001) {
if (utils::isValidTemperature(_temp)) {
add_metric(
"temperature",
"The ambient temperature as measured by the AirGradient SHT / PMS "
@ -158,7 +158,7 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (atmpCompensated > -1001) {
if (utils::isValidTemperature(atmpCompensated)) {
add_metric("temperature_compensated",
"The compensated ambient temperature as measured by the "
"AirGradient SHT / PMS "
@ -166,14 +166,14 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(atmpCompensated));
}
if (_hum >= 0) {
if (utils::isValidHumidity(_hum)) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
if (ahumCompensated >= 0) {
if (utils::isValidHumidity(ahumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",

View File

@ -126,6 +126,9 @@ void setup() {
openMetrics.setAirGradient(&ag);
localServer.setAirGraident(&ag);
/** Example set custom API root URL */
// apiClient.setApiRoot("https://example.custom.api");
/** Init sensor */
boardInit();
@ -231,7 +234,7 @@ void loop() {
static void co2Update(void) {
int value = ag.s8.getCo2();
if (value >= 0) {
if (utils::isValidCO2(value)) {
measurements.CO2 = value;
getCO2FailCount = 0;
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
@ -239,7 +242,7 @@ static void co2Update(void) {
getCO2FailCount++;
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
if (getCO2FailCount >= 3) {
measurements.CO2 = -1;
measurements.CO2 = utils::getInvalidCO2();
}
}
}
@ -568,10 +571,10 @@ static void updatePm(void) {
pmFailCount++;
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
if (pmFailCount >= 3) {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
measurements.pm01_1 = utils::getInvalidPMS();
measurements.pm25_1 = utils::getInvalidPMS();
measurements.pm10_1 = utils::getInvalidPMS();
measurements.pm03PCount_1 = utils::getInvalidPMS();
}
}
}
@ -616,5 +619,7 @@ static void tempHumUpdate(void) {
}
} else {
Serial.println("SHT read failed");
measurements.Temperature = utils::getInvalidTemperature();
measurements.Humidity = utils::getInvalidHumidity();
}
}

View File

@ -65,14 +65,14 @@ String OpenMetrics::getPayload(void) {
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
int atmpCompensated = -1;
int ahumCompensated = -1;
float _temp = utils::getInvalidTemperature();
float _hum = utils::getInvalidHumidity();
int pm01 = utils::getInvalidPMS();
int pm25 = utils::getInvalidPMS();
int pm10 = utils::getInvalidPMS();
int pm03PCount = utils::getInvalidPMS();
int atmpCompensated = utils::getInvalidTemperature();
int ahumCompensated = utils::getInvalidHumidity();
if (config.hasSensorSHT) {
_temp = measure.Temperature;
@ -89,28 +89,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorPMS1) {
if (pm01 >= 0) {
if (utils::isValidPMS(pm01)) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
if (utils::isValidPMS(pm25)) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
if (utils::isValidPMS(pm10)) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
if (utils::isValidPMS03Count(pm03PCount)) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
@ -120,28 +120,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
if (utils::isValidVOC(measure.TVOC)) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
if (utils::isValidVOC(measure.TVOCRaw)) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
if (utils::isValidNOx(measure.NOx)) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
if (utils::isValidNOx(measure.NOxRaw)) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
@ -150,7 +150,7 @@ String OpenMetrics::getPayload(void) {
}
}
if (_temp > -1001) {
if (utils::isValidTemperature(_temp)) {
add_metric(
"temperature",
"The ambient temperature as measured by the AirGradient SHT / PMS "
@ -158,7 +158,7 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (atmpCompensated > -1001) {
if (utils::isValidTemperature(atmpCompensated)) {
add_metric("temperature_compensated",
"The compensated ambient temperature as measured by the "
"AirGradient SHT / PMS "
@ -166,14 +166,14 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(atmpCompensated));
}
if (_hum >= 0) {
if (utils::isValidHumidity(_hum)) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
if (ahumCompensated >= 0) {
if (utils::isValidHumidity(ahumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",

View File

@ -127,6 +127,9 @@ void setup() {
openMetrics.setAirGradient(&ag);
localServer.setAirGraident(&ag);
/** Example set custom API root URL */
// apiClient.setApiRoot("https://example.custom.api");
/** Init sensor */
boardInit();
@ -258,7 +261,7 @@ void loop() {
static void co2Update(void) {
int value = ag.s8.getCo2();
if (value >= 0) {
if (utils::isValidCO2(value)) {
measurements.CO2 = value;
getCO2FailCount = 0;
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
@ -266,7 +269,7 @@ static void co2Update(void) {
getCO2FailCount++;
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
if (getCO2FailCount >= 3) {
measurements.CO2 = -1;
measurements.CO2 = utils::getInvalidCO2();
}
}
}
@ -611,10 +614,10 @@ static void updatePm(void) {
pmFailCount++;
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
if (pmFailCount >= 3) {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
measurements.pm01_1 = utils::getInvalidPMS();
measurements.pm25_1 = utils::getInvalidPMS();
measurements.pm10_1 = utils::getInvalidPMS();
measurements.pm03PCount_1 = utils::getInvalidPMS();
}
}
}
@ -659,5 +662,7 @@ static void tempHumUpdate(void) {
}
} else {
Serial.println("SHT read failed");
measurements.Temperature = utils::getInvalidTemperature();
measurements.Humidity = utils::getInvalidHumidity();
}
}

View File

@ -65,14 +65,14 @@ String OpenMetrics::getPayload(void) {
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
int atmpCompensated = -1;
int ahumCompensated = -1;
float _temp = utils::getInvalidTemperature();
float _hum = utils::getInvalidHumidity();
int pm01 = utils::getInvalidPMS();
int pm25 = utils::getInvalidPMS();
int pm10 = utils::getInvalidPMS();
int pm03PCount = utils::getInvalidPMS();
int atmpCompensated = utils::getInvalidTemperature();
int ahumCompensated = utils::getInvalidHumidity();
if (config.hasSensorSHT) {
_temp = measure.Temperature;
@ -89,28 +89,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorPMS1) {
if (pm01 >= 0) {
if (utils::isValidPMS(pm01)) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
if (utils::isValidPMS(pm25)) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
if (utils::isValidPMS(pm10)) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
if (utils::isValidPMS03Count(pm03PCount)) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
@ -120,28 +120,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
if (utils::isValidVOC(measure.TVOC)) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
if (utils::isValidVOC(measure.TVOCRaw)) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
if (utils::isValidNOx(measure.NOx)) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
if (utils::isValidNOx(measure.NOxRaw)) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
@ -150,7 +150,7 @@ String OpenMetrics::getPayload(void) {
}
}
if (_temp > -1001) {
if (utils::isValidTemperature(_temp)) {
add_metric(
"temperature",
"The ambient temperature as measured by the AirGradient SHT / PMS "
@ -158,7 +158,7 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (atmpCompensated > -1001) {
if (utils::isValidTemperature(atmpCompensated)) {
add_metric("temperature_compensated",
"The compensated ambient temperature as measured by the "
"AirGradient SHT / PMS "
@ -166,14 +166,14 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(atmpCompensated));
}
if (_hum >= 0) {
if (utils::isValidHumidity(_hum)) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
if (ahumCompensated >= 0) {
if (utils::isValidHumidity(ahumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",

View File

@ -163,6 +163,9 @@ void setup() {
openMetrics.setAirGradient(ag);
localServer.setAirGraident(ag);
/** Example set custom API root URL */
// apiClient.setApiRoot("https://example.custom.api");
/** Init sensor */
boardInit();
@ -317,7 +320,7 @@ void loop() {
static void co2Update(void) {
int value = ag->s8.getCo2();
if (value >= 0) {
if (utils::isValidCO2(value)) {
measurements.CO2 = value;
getCO2FailCount = 0;
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
@ -325,7 +328,7 @@ static void co2Update(void) {
getCO2FailCount++;
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
if (getCO2FailCount >= 3) {
measurements.CO2 = -1;
measurements.CO2 = utils::getInvalidCO2();
}
}
}
@ -421,12 +424,8 @@ static void factoryConfigReset(void) {
}
/** Reset WIFI */
WiFi.enableSTA(true); // Incase offline mode
WiFi.disconnect(true, true);
if (ag->isOne() == false) {
WiFi.begin("airgradient", "cleanair");
Serial.println("Set WiFi connect to \"airgradient\"");
}
Serial.println("Set wifi connect to 'airgradient' as default");
WiFi.begin("airgradient", "cleanair");
/** Reset local config */
configuration.reset();
@ -1024,10 +1023,10 @@ static void updatePm(void) {
pmFailCount++;
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
if (pmFailCount >= 3) {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
measurements.pm01_1 = utils::getInvalidPMS();
measurements.pm25_1 = utils::getInvalidPMS();
measurements.pm10_1 = utils::getInvalidPMS();
measurements.pm03PCount_1 = utils::getInvalidPMS();
}
}
} else {
@ -1055,12 +1054,12 @@ static void updatePm(void) {
Serial.printf("[1] Relative Humidity compensated: %f\r\n",
ag->pms5003t_1.humidityCompensated(measurements.hum_1));
} else {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
measurements.temp_1 = -1001;
measurements.hum_1 = -1;
measurements.pm01_1 = utils::getInvalidPMS();
measurements.pm25_1 = utils::getInvalidPMS();
measurements.pm10_1 = utils::getInvalidPMS();
measurements.pm03PCount_1 = utils::getInvalidPMS();
measurements.temp_1 = utils::getInvalidTemperature();
measurements.hum_1 = utils::getInvalidHumidity();
}
if (configuration.hasSensorPMS2 && (ag->pms5003t_2.isFailed() == false)) {
@ -1085,12 +1084,12 @@ static void updatePm(void) {
Serial.printf("[2] Relative Humidity compensated: %d\r\n",
ag->pms5003t_1.humidityCompensated(measurements.hum_2));
} else {
measurements.pm01_2 = -1;
measurements.pm25_2 = -1;
measurements.pm10_2 = -1;
measurements.pm03PCount_2 = -1;
measurements.temp_2 = -1001;
measurements.hum_2 = -1;
measurements.pm01_2 = utils::getInvalidPMS();
measurements.pm25_2 = utils::getInvalidPMS();
measurements.pm10_2 = utils::getInvalidPMS();
measurements.pm03PCount_2 = utils::getInvalidPMS();
measurements.temp_2 = utils::getInvalidTemperature();
measurements.hum_2 = utils::getInvalidHumidity();
}
if (configuration.hasSensorPMS1 && configuration.hasSensorPMS2 &&
@ -1230,6 +1229,8 @@ static void tempHumUpdate(void) {
measurements.Humidity);
}
} else {
measurements.Temperature = utils::getInvalidTemperature();
measurements.Humidity = utils::getInvalidHumidity();
Serial.println("SHT read failed");
}
}

View File

@ -65,14 +65,14 @@ String OpenMetrics::getPayload(void) {
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
int atmpCompensated = -1;
int ahumCompensated = -1;
float _temp = utils::getInvalidTemperature();
float _hum = utils::getInvalidHumidity();
int pm01 = utils::getInvalidPMS();
int pm25 = utils::getInvalidPMS();
int pm10 = utils::getInvalidPMS();
int pm03PCount = utils::getInvalidPMS();
int atmpCompensated = utils::getInvalidTemperature();
int ahumCompensated = utils::getInvalidHumidity();
if (config.hasSensorPMS1 && config.hasSensorPMS2) {
_temp = (measure.temp_1 + measure.temp_2) / 2.0f;
_hum = (measure.hum_1 + measure.hum_2) / 2.0f;
@ -123,28 +123,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorPMS1 || config.hasSensorPMS2) {
if (pm01 >= 0) {
if (utils::isValidPMS(pm01)) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
if (utils::isValidPMS(pm25)) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
if (utils::isValidPMS(pm10)) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
if (utils::isValidPMS03Count(pm03PCount)) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
@ -154,28 +154,28 @@ String OpenMetrics::getPayload(void) {
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
if (utils::isValidVOC(measure.TVOC)) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
if (utils::isValidVOC(measure.TVOCRaw)) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
if (utils::isValidNOx(measure.NOx)) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
if (utils::isValidNOx(measure.NOxRaw)) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
@ -184,14 +184,14 @@ String OpenMetrics::getPayload(void) {
}
}
if (_temp > -1001) {
if (utils::isValidTemperature(_temp)) {
add_metric("temperature",
"The ambient temperature as measured by the AirGradient SHT / PMS "
"sensor, in degrees Celsius",
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (atmpCompensated > -1001) {
if (utils::isValidTemperature(atmpCompensated)) {
add_metric(
"temperature_compensated",
"The compensated ambient temperature as measured by the AirGradient SHT / PMS "
@ -199,14 +199,14 @@ String OpenMetrics::getPayload(void) {
"gauge", "celsius");
add_metric_point("", String(atmpCompensated));
}
if (_hum >= 0) {
if (utils::isValidHumidity(_hum)) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
if (ahumCompensated >= 0) {
if (utils::isValidHumidity(ahumCompensated)) {
add_metric(
"humidity_compensated",
"The compensated relative humidity as measured by the AirGradient SHT / PMS sensor",

View File

@ -1,5 +1,5 @@
name=AirGradient Air Quality Sensor
version=3.1.4
version=3.1.5
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

@ -1,7 +1,7 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1E0000,
app1, app, ota_1, 0x1F0000,0x1E0000,
spiffs, data, spiffs, 0x3D0000,0x20000,
coredump, data, coredump,0x3F0000,0x10000,
# Name ,Type ,SubType ,Offset ,Size ,Flags
nvs ,data ,nvs ,0x9000 ,0x5000 ,
otadata ,data ,ota ,0xe000 ,0x2000 ,
app0 ,app ,ota_0 ,0x10000 ,0x1E0000 ,
app1 ,app ,ota_1 ,0x1F0000 ,0x1E0000 ,
spiffs ,data ,spiffs ,0x3D0000 ,0x20000 ,
coredump ,data ,coredump ,0x3F0000 ,0x10000 ,

1 # Name # Name Type Type SubType SubType Offset Offset Size Size Flags
2 nvs nvs data data nvs nvs 0x9000 0x9000 0x5000 0x5000
3 otadata otadata data data ota ota 0xe000 0xe000 0x2000 0x2000
4 app0 app0 app app ota_0 ota_0 0x10000 0x10000 0x1E0000 0x1E0000
5 app1 app1 app app ota_1 ota_1 0x1F0000 0x1F0000 0x1E0000 0x1E0000
6 spiffs spiffs data data spiffs spiffs 0x3D0000 0x3D0000 0x20000 0x20000
7 coredump coredump data data coredump coredump 0x3F0000 0x3F0000 0x10000 0x10000

View File

@ -22,6 +22,7 @@ AgApiClient::~AgApiClient() {}
void AgApiClient::begin(void) {
getConfigFailed = false;
postToServerFailed = false;
logInfo("Init apiRoot: " + apiRoot);
logInfo("begin");
}
@ -44,9 +45,8 @@ bool AgApiClient::fetchServerConfiguration(void) {
return false;
}
String uri =
"http://hw.airgradient.com/sensors/airgradient:" + ag->deviceId() +
"/one/config";
String uri = apiRoot + "/sensors/airgradient:" +
ag->deviceId() + "/one/config";
/** Init http client */
#ifdef ESP8266
@ -66,6 +66,10 @@ bool AgApiClient::fetchServerConfiguration(void) {
/** Get data */
int retCode = client.GET();
logInfo(String("GET: ") + uri);
logInfo(String("Return code: ") + String(retCode));
if (retCode != 200) {
client.end();
getConfigFailed = true;
@ -112,18 +116,23 @@ bool AgApiClient::postToServer(String data) {
String uri =
"http://hw.airgradient.com/sensors/airgradient:" + ag->deviceId() +
"/measures";
logInfo("Post uri: " + uri);
logInfo("Post data: " + data);
// logInfo("Post uri: " + uri);
// logInfo("Post data: " + data);
WiFiClient wifiClient;
HTTPClient client;
if (client.begin(wifiClient, uri.c_str()) == false) {
logError("Init client failed");
return false;
}
client.addHeader("content-type", "application/json");
int retCode = client.POST(data);
client.end();
logInfo(String("POST: ") + uri);
logInfo(String("DATA: ") + data);
logInfo(String("Return code: ") + String(retCode));
if ((retCode == 200) || (retCode == 429)) {
postToServerFailed = false;
return true;
@ -177,3 +186,7 @@ bool AgApiClient::sendPing(int rssi, int bootCount) {
root["boot"] = bootCount;
return postToServer(JSON.stringify(root));
}
String AgApiClient::getApiRoot() const { return apiRoot; }
void AgApiClient::setApiRoot(const String &apiRoot) { this->apiRoot = apiRoot; }

View File

@ -20,6 +20,7 @@ class AgApiClient : public PrintLog {
private:
Configuration &config;
AirGradient *ag;
String apiRoot = "http://hw.airgradient.com";
bool getConfigFailed;
bool postToServerFailed;
@ -37,6 +38,8 @@ public:
bool isNotAvailableOnDashboard(void);
void setAirGradient(AirGradient *ag);
bool sendPing(int rssi, int bootCount);
String getApiRoot() const;
void setApiRoot(const String &apiRoot);
};
#endif /** _AG_API_CLIENT_H_ */

View File

@ -264,12 +264,14 @@ bool Configuration::parse(String data, bool isLocal) {
jconfig[jprop_configurationControl]);
}
/** Check to return result if configurationControl is 'cloud' */
if (ctrl ==
String(CONFIGURATION_CONTROL_NAME
[ConfigurationControl::ConfigurationControlCloud])) {
failedMessage = String(msg);
return true;
/** Return failed if new "configurationControl" new and old is "cloud" */
if (ctrl == String(CONFIGURATION_CONTROL_NAME [ConfigurationControl::ConfigurationControlCloud])) {
if(ctrl != lastCtrl) {
return true;
} else {
failedMessage = String(msg);
return false;
}
}
} else {
failedMessage =

View File

@ -1,5 +1,6 @@
#include "AgOledDisplay.h"
#include "Libraries/U8g2/src/U8g2lib.h"
#include "Main/utils.h"
/** Cast U8G2 */
#define DISP() ((U8G2_SH1106_128X64_NONAME_F_HW_I2C *)(this->u8g2))
@ -10,8 +11,8 @@
* @param hasStatus
*/
void OledDisplay::showTempHum(bool hasStatus) {
char buf[10];
if (value.Temperature > -1001) {
char buf[16];
if (utils::isValidTemperature(value.Temperature)) {
if (config.isTemperatureUnitInF()) {
float tempF = (value.Temperature * 9) / 5 + 32;
if (hasStatus) {
@ -36,10 +37,10 @@ void OledDisplay::showTempHum(bool hasStatus) {
DISP()->drawUTF8(1, 10, buf);
/** Show humidty */
if (value.Humidity >= 0) {
if (utils::isValidHumidity(value.Humidity)) {
snprintf(buf, sizeof(buf), "%d%%", value.Humidity);
} else {
snprintf(buf, sizeof(buf), "%-%%");
snprintf(buf, sizeof(buf), "-%%");
}
if (value.Humidity > 99) {
@ -283,12 +284,8 @@ void OledDisplay::showDashboard(const char *status) {
DISP()->drawUTF8(1, 27, "CO2");
DISP()->setFont(u8g2_font_t0_22b_tf);
if (value.CO2 > 0) {
int val = 9999;
if (value.CO2 < 10000) {
val = value.CO2;
}
sprintf(strBuf, "%d", val);
if (utils::isValidCO2(value.CO2)) {
sprintf(strBuf, "%d", value.CO2);
} else {
sprintf(strBuf, "%s", "-");
}
@ -299,88 +296,111 @@ void OledDisplay::showDashboard(const char *status) {
DISP()->drawStr(1, 61, "ppm");
/** Draw vertical line */
DISP()->drawLine(45, 14, 45, 64);
DISP()->drawLine(82, 14, 82, 64);
DISP()->drawLine(52, 14, 52, 64);
DISP()->drawLine(97, 14, 97, 64);
/** Draw PM2.5 label */
DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawStr(48, 27, "PM2.5");
DISP()->drawStr(55, 27, "PM2.5");
/** Draw PM2.5 value */
int pm25 = value.pm25_1;
if (config.hasSensorSHT) {
pm25 = ag->pms5003.compensated(pm25, value.Humidity);
}
DISP()->setFont(u8g2_font_t0_22b_tf);
if (config.isPmStandardInUSAQI()) {
if (value.pm25_1 >= 0) {
if (utils::isValidPMS(value.pm25_1)) {
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.pm25_1));
} else {
sprintf(strBuf, "%s", "-");
}
DISP()->drawStr(48, 48, strBuf);
DISP()->drawStr(55, 48, strBuf);
DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawUTF8(48, 61, "AQI");
DISP()->drawUTF8(55, 61, "AQI");
} else {
if (value.pm25_1 >= 0) {
if (utils::isValidPMS(value.pm25_1)) {
sprintf(strBuf, "%d", value.pm25_1);
} else {
sprintf(strBuf, "%s", "-");
}
DISP()->drawStr(48, 48, strBuf);
DISP()->drawStr(55, 48, strBuf);
DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawUTF8(48, 61, "ug/m³");
DISP()->drawUTF8(55, 61, "ug/m³");
}
/** Draw tvocIndexlabel */
DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawStr(85, 27, "tvoc:");
DISP()->drawStr(100, 27, "VOC:");
/** Draw tvocIndexvalue */
if (value.TVOC >= 0) {
if (utils::isValidVOC(value.TVOC)) {
sprintf(strBuf, "%d", value.TVOC);
} else {
sprintf(strBuf, "%s", "-");
}
DISP()->drawStr(85, 39, strBuf);
DISP()->drawStr(100, 39, strBuf);
/** Draw NOx label */
DISP()->drawStr(85, 53, "NOx:");
if (value.NOx >= 0) {
DISP()->drawStr(100, 53, "NOx:");
if (utils::isValidNOx(value.NOx)) {
sprintf(strBuf, "%d", value.NOx);
} else {
sprintf(strBuf, "%s", "-");
}
DISP()->drawStr(85, 63, strBuf);
DISP()->drawStr(100, 63, strBuf);
} while (DISP()->nextPage());
} else if (ag->isBasic()) {
ag->display.clear();
/** Set CO2 */
snprintf(strBuf, sizeof(strBuf), "CO2:%d", 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) {
pm25 = (int)ag->pms5003.compensated(pm25, value.Humidity);
}
ag->display.setCursor(0, 12);
snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", value.pm25_1);
if (utils::isValidPMS(value.pm25_1)) {
snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", value.pm25_1);
} else {
snprintf(strBuf, sizeof(strBuf), "PM2.5:-");
}
ag->display.setText(strBuf);
/** Set temperature and humidity */
if (value.Temperature <= -1001.0f) {
if (utils::isValidTemperature(value.Temperature)) {
if (config.isTemperatureUnitInF()) {
float tempF = (value.Temperature * 9) / 5 + 32;
snprintf(strBuf, sizeof(strBuf), "T:%0.1f F", tempF);
} else {
snprintf(strBuf, sizeof(strBuf), "T:%0.f1 C", value.Temperature);
}
} else {
if (config.isTemperatureUnitInF()) {
snprintf(strBuf, sizeof(strBuf), "T:-F");
} else {
snprintf(strBuf, sizeof(strBuf), "T:-C");
}
} else {
if (config.isTemperatureUnitInF()) {
float tempF = (value.Temperature * 9) / 5 + 32;
snprintf(strBuf, sizeof(strBuf), "T:%d F", (int)tempF);
} else {
snprintf(strBuf, sizeof(strBuf), "T:%d C", (int)value.Temperature);
}
}
ag->display.setCursor(0, 24);
ag->display.setText(strBuf);
snprintf(strBuf, sizeof(strBuf), "H:%d %%", (int)value.Humidity);
if (utils::isValidHumidity(value.Humidity)) {
snprintf(strBuf, sizeof(strBuf), "H:%d %%", (int)value.Humidity);
} else {
snprintf(strBuf, sizeof(strBuf), "H:- %%");
}
ag->display.setCursor(0, 36);
ag->display.setText(strBuf);

View File

@ -9,9 +9,9 @@
#define RGB_COLOR_R 255, 0, 0 /** Red */
#define RGB_COLOR_G 0, 255, 0 /** Green */
#define RGB_COLOR_Y 255, 255, 0 /** Yellow */
#define RGB_COLOR_O 255, 165, 0 /** Organge */
#define RGB_COLOR_P 160, 32, 240 /** Purple */
#define RGB_COLOR_Y 255, 150, 0 /** Yellow */
#define RGB_COLOR_O 255, 40, 0 /** Orange */
#define RGB_COLOR_P 180, 0, 255 /** Purple */
/**
* @brief Animation LED bar with color
@ -573,7 +573,7 @@ void StateMachine::handleLeds(AgStateMachineState state) {
case AgStateMachineWiFiManagerMode: {
/** In WiFi Manager Mode */
/** Turn LED OFF */
/** Turn midle LED Color */
/** Turn middle LED Color */
if (ag->isOne()) {
ag->ledBar.setColor(0, 0, 255, ag->ledBar.getNumberOfLeds() / 2);
} else {
@ -713,7 +713,7 @@ void StateMachine::handleLeds(AgStateMachineState state) {
break;
}
case AgStateMachineSensorConfigFailed: {
/** Server is reachable but there is some conguration issue to be fixed on
/** Server is reachable but there is some configuration issue to be fixed on
* the server side */
if (ag->isOne()) {
ag->ledBar.setColor(139, 24, 248, 0);

View File

@ -1,6 +1,7 @@
#include "AgValue.h"
#include "AgConfigure.h"
#include "AirGradient.h"
#include "Main/utils.h"
#include "Libraries/Arduino_JSON/src/Arduino_JSON.h"
String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
@ -13,36 +14,35 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
if (localServer) {
root["serialno"] = ag->deviceId();
}
if (config->hasSensorS8) {
if (this->CO2 >= 0) {
root["rco2"] = this->CO2;
}
if (config->hasSensorS8 && utils::isValidCO2(this->CO2)) {
root["rco2"] = this->CO2;
}
if (ag->isOne() || (ag->isPro4_2()) || ag->isPro3_3() || ag->isBasic()) {
if (config->hasSensorPMS1) {
if (this->pm01_1 >= 0) {
if (utils::isValidPMS(this->pm01_1)) {
root["pm01"] = this->pm01_1;
}
if (this->pm25_1 >= 0) {
if (utils::isValidPMS(this->pm25_1)) {
root["pm02"] = this->pm25_1;
}
if (this->pm10_1 >= 0) {
if (utils::isValidPMS(this->pm10_1)) {
root["pm10"] = this->pm10_1;
}
if (this->pm03PCount_1 >= 0) {
if (utils::isValidPMS03Count(this->pm03PCount_1)) {
root["pm003Count"] = this->pm03PCount_1;
}
}
if (config->hasSensorSHT) {
if (this->Temperature > -1001) {
if (utils::isValidTemperature(this->Temperature)) {
root["atmp"] = ag->round2(this->Temperature);
if (localServer) {
root["atmpCompensated"] = ag->round2(this->Temperature);
}
}
if (this->Humidity >= 0) {
if (utils::isValidHumidity(this->Humidity)) {
root["rhum"] = this->Humidity;
if (localServer) {
root["rhumCompensated"] = this->Humidity;
@ -50,126 +50,287 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
}
}
} else {
if (config->hasSensorPMS1 && config->hasSensorPMS2) {
root["pm01"] = ag->round2((this->pm01_1 + this->pm01_2) / 2.0);
root["pm02"] = ag->round2((this->pm25_1 + this->pm25_2) / 2.0);
root["pm10"] = ag->round2((this->pm10_1 + this->pm10_2) / 2.0);
root["pm003Count"] =
ag->round2((this->pm03PCount_1 + this->pm03PCount_2) / 2.0);
root["atmp"] = ag->round2((this->temp_1 + this->temp_2) / 2.0f);
root["rhum"] = ag->round2((this->hum_1 + this->hum_2) / 2.0f);
if (localServer) {
root["atmpCompensated"] =
ag->round2(ag->pms5003t_2.temperatureCompensated(
(this->temp_1 + this->temp_2) / 2.0f));
root["rhumCompensated"] = (int)ag->pms5003t_2.humidityCompensated(
(this->hum_1 + this->hum_2) / 2.0f);
if (config->hasSensorSHT && config->hasSensorPMS1) {
int pm25 = ag->pms5003.compensated(this->pm25_1, this->Humidity);
if (pm25 >= 0) {
root["pm02Compensated"] = pm25;
}
}
if (fwMode == FW_MODE_O_1PS || fwMode == FW_MODE_O_1PST) {
if (config->hasSensorPMS1) {
root["pm01"] = this->pm01_1;
root["pm02"] = this->pm25_1;
root["pm10"] = this->pm10_1;
root["pm003Count"] = this->pm03PCount_1;
root["atmp"] = ag->round2(this->temp_1);
root["rhum"] = this->hum_1;
} else {
if (config->hasSensorPMS1 && config->hasSensorPMS2) {
if (utils::isValidPMS(this->pm01_1) && utils::isValidPMS(this->pm01_2)) {
root["pm01"] = ag->round2((this->pm01_1 + this->pm01_2) / 2.0f);
}
if (utils::isValidPMS(this->pm25_1) && utils::isValidPMS(this->pm25_2)) {
root["pm02"] = ag->round2((this->pm25_1 + this->pm25_2) / 2.0f);
}
if (utils::isValidPMS(this->pm10_1) && utils::isValidPMS(this->pm10_2)) {
root["pm10"] = ag->round2((this->pm10_1 + this->pm10_2) / 2.0f);
}
if (utils::isValidPMS(this->pm03PCount_1) && utils::isValidPMS(this->pm03PCount_2)) {
root["pm003Count"] = ag->round2((this->pm03PCount_1 + this->pm03PCount_2) / 2.0f);
}
float val;
if (utils::isValidTemperature(this->temp_1) && utils::isValidTemperature(this->temp_1)) {
root["atmp"] = ag->round2((this->temp_1 + this->temp_2) / 2.0f);
if (localServer) {
root["atmpCompensated"] =
ag->round2(ag->pms5003t_1.temperatureCompensated(this->temp_1));
root["rhumCompensated"] =
(int)ag->pms5003t_1.humidityCompensated(this->hum_1);
val = ag->pms5003t_2.temperatureCompensated((this->temp_1 + this->temp_2) / 2.0f);
if (utils::isValidTemperature(val)) {
root["atmpCompensated"] = ag->round2(val);
}
}
}
if (config->hasSensorPMS2) {
root["pm01"] = this->pm01_2;
root["pm02"] = this->pm25_2;
root["pm10"] = this->pm10_2;
root["pm003Count"] = this->pm03PCount_2;
root["atmp"] = ag->round2(this->temp_2);
root["rhum"] = this->hum_2;
if (utils::isValidHumidity(this->hum_1) && utils::isValidHumidity(this->hum_1)) {
root["rhum"] = ag->round2((this->hum_1 + this->hum_2) / 2.0f);
if (localServer) {
root["atmpCompensated"] =
ag->round2(ag->pms5003t_2.temperatureCompensated(this->temp_2));
root["rhumCompensated"] =
(int)ag->pms5003t_2.humidityCompensated(this->hum_2);
val = ag->pms5003t_2.humidityCompensated((this->hum_1 + this->hum_2) / 2.0f);
if (utils::isValidHumidity(val)) {
root["rhumCompensated"] = (int)val;
}
}
}
int pm25 = (ag->pms5003t_1.compensated(this->pm25_1, this->temp_1) +
ag->pms5003t_2.compensated(this->pm25_2, this->temp_2)) /
2;
root["pm02Compensated"] = pm25;
}
if (fwMode == FW_MODE_O_1PS || fwMode == FW_MODE_O_1PST) {
float val;
if (config->hasSensorPMS1) {
if (utils::isValidPMS(this->pm01_1)) {
root["pm01"] = this->pm01_1;
}
if (utils::isValidPMS(this->pm25_1)) {
root["pm02"] = this->pm25_1;
}
if (utils::isValidPMS(this->pm10_1)) {
root["pm10"] = this->pm10_1;
}
if (utils::isValidPMS03Count(this->pm03PCount_1)) {
root["pm003Count"] = this->pm03PCount_1;
}
if (utils::isValidTemperature(this->temp_1)) {
root["atmp"] = ag->round2(this->temp_1);
if (localServer) {
val = ag->pms5003t_1.temperatureCompensated(this->temp_1);
if (utils::isValidTemperature(val)) {
root["atmpCompensated"] = ag->round2(val);
}
}
}
if (utils::isValidHumidity(this->hum_1)) {
root["rhum"] = this->hum_1;
if (localServer) {
val = ag->pms5003t_1.humidityCompensated(this->hum_1);
if (utils::isValidHumidity(val)) {
root["rhumCompensated"] = (int)val;
}
}
}
root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1);
}
if (config->hasSensorPMS2) {
if(utils::isValidPMS(this->pm01_2)) {
root["pm01"] = this->pm01_2;
}
if(utils::isValidPMS(this->pm25_2)) {
root["pm02"] = this->pm25_2;
}
if(utils::isValidPMS(this->pm10_2)) {
root["pm10"] = this->pm10_2;
}
if(utils::isValidPMS03Count(this->pm03PCount_2)) {
root["pm003Count"] = this->pm03PCount_2;
}
float val;
if (utils::isValidTemperature(this->temp_2)) {
root["atmp"] = ag->round2(this->temp_2);
if (localServer) {
val = ag->pms5003t_2.temperatureCompensated(this->temp_2);
if (utils::isValidTemperature(val)) {
root["atmpCompensated"] = ag->round2(val);
}
}
}
if(utils::isValidHumidity(this->hum_2)) {
root["rhum"] = this->hum_2;
if (localServer) {
val = ag->pms5003t_2.humidityCompensated(this->hum_2);
if (utils::isValidHumidity(val)) {
root["rhumCompensated"] = (int)val;
}
}
}
root["pm02Compensated"] = ag->pms5003t_2.compensated(this->pm25_2, this->temp_2);
}
} else {
if (fwMode == FW_MODE_O_1P) {
float val;
if (config->hasSensorPMS1) {
root["pm01"] = this->pm01_1;
root["pm02"] = this->pm25_1;
root["pm10"] = this->pm10_1;
root["pm003Count"] = this->pm03PCount_1;
root["atmp"] = ag->round2(this->temp_1);
root["rhum"] = this->hum_1;
if (localServer) {
root["atmpCompensated"] =
ag->round2(ag->pms5003t_1.temperatureCompensated(this->temp_1));
root["rhumCompensated"] =
(int)ag->pms5003t_1.humidityCompensated(this->hum_1);
if (utils::isValidPMS(this->pm01_1)) {
root["pm01"] = this->pm01_1;
}
if (utils::isValidPMS(this->pm25_1)) {
root["pm02"] = this->pm25_1;
}
if (utils::isValidPMS(this->pm10_1)) {
root["pm10"] = this->pm10_1;
}
if (utils::isValidPMS03Count(this->pm03PCount_1)) {
root["pm003Count"] = this->pm03PCount_1;
}
if (utils::isValidTemperature(this->temp_1)) {
root["atmp"] = ag->round2(this->temp_1);
if (localServer) {
val = ag->pms5003t_1.temperatureCompensated(this->temp_1);
if (utils::isValidTemperature(val)) {
root["atmpCompensated"] = ag->round2(val);
}
}
}
if (utils::isValidHumidity(this->hum_1)) {
root["rhum"] = this->hum_1;
if(localServer) {
val = ag->pms5003t_1.humidityCompensated(this->hum_1);
if(utils::isValidHumidity(val)) {
root["rhumCompensated"] = (int)val;
}
}
}
root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1);
} else if (config->hasSensorPMS2) {
root["pm01"] = this->pm01_2;
root["pm02"] = this->pm25_2;
root["pm10"] = this->pm10_2;
root["pm003Count"] = this->pm03PCount_2;
root["atmp"] = ag->round2(this->temp_2);
root["rhum"] = this->hum_2;
if (localServer) {
root["atmpCompensated"] =
ag->round2(ag->pms5003t_1.temperatureCompensated(this->temp_2));
root["rhumCompensated"] =
(int)ag->pms5003t_1.humidityCompensated(this->hum_2);
if(utils::isValidPMS(this->pm01_2)) {
root["pm01"] = this->pm01_2;
}
if(utils::isValidPMS(this->pm25_2)) {
root["pm02"] = this->pm25_2;
}
if(utils::isValidPMS(this->pm10_2)) {
root["pm10"] = this->pm10_2;
}
if(utils::isValidPMS03Count(this->pm03PCount_2)) {
root["pm003Count"] = this->pm03PCount_2;
}
if (utils::isValidTemperature(this->temp_2)) {
root["atmp"] = ag->round2(this->temp_2);
if (localServer) {
val = ag->pms5003t_1.temperatureCompensated(this->temp_2);
if (utils::isValidTemperature(val)) {
root["atmpCompensated"] = ag->round2(val);
}
}
}
if (utils::isValidHumidity(this->hum_2)) {
root["rhum"] = this->hum_2;
if(localServer) {
val = ag->pms5003t_1.humidityCompensated(this->hum_2);
if(utils::isValidHumidity(val)) {
root["rhumCompensated"] = (int)val;
}
}
}
root["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1);
}
} else {
float val;
if (config->hasSensorPMS1) {
root["channels"]["1"]["pm01"] = this->pm01_1;
root["channels"]["1"]["pm02"] = this->pm25_1;
root["channels"]["1"]["pm10"] = this->pm10_1;
root["channels"]["1"]["pm003Count"] = this->pm03PCount_1;
root["channels"]["1"]["atmp"] = ag->round2(this->temp_1);
root["channels"]["1"]["rhum"] = this->hum_1;
if (localServer) {
root["channels"]["1"]["atmpCompensated"] =
ag->round2(ag->pms5003t_1.temperatureCompensated(this->temp_1));
root["channels"]["1"]["rhumCompensated"] =
(int)ag->pms5003t_1.humidityCompensated(this->hum_1);
if(utils::isValidPMS(this->pm01_1)) {
root["channels"]["1"]["pm01"] = this->pm01_1;
}
if(utils::isValidPMS(this->pm25_1)) {
root["channels"]["1"]["pm02"] = this->pm25_1;
}
if(utils::isValidPMS(this->pm10_1)) {
root["channels"]["1"]["pm10"] = this->pm10_1;
}
if (utils::isValidPMS03Count(this->pm03PCount_1)) {
root["channels"]["1"]["pm003Count"] = this->pm03PCount_1;
}
if(utils::isValidTemperature(this->temp_1)) {
root["channels"]["1"]["atmp"] = ag->round2(this->temp_1);
if (localServer) {
val = ag->pms5003t_1.temperatureCompensated(this->temp_1);
if (utils::isValidTemperature(val)) {
root["channels"]["1"]["atmpCompensated"] = ag->round2(val);
}
}
}
if (utils::isValidHumidity(this->hum_1)) {
root["channels"]["1"]["rhum"] = this->hum_1;
if (localServer) {
val = ag->pms5003t_1.humidityCompensated(this->hum_1);
if (utils::isValidHumidity(val)) {
root["channels"]["1"]["rhumCompensated"] = (int)val;
}
}
}
root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.compensated(this->pm25_1, this->temp_1);
}
if (config->hasSensorPMS2) {
root["channels"]["2"]["pm01"] = this->pm01_2;
root["channels"]["2"]["pm02"] = this->pm25_2;
root["channels"]["2"]["pm10"] = this->pm10_2;
root["channels"]["2"]["pm003Count"] = this->pm03PCount_2;
root["channels"]["2"]["atmp"] = ag->round2(this->temp_2);
root["channels"]["2"]["rhum"] = this->hum_2;
if (localServer) {
root["channels"]["2"]["atmpCompensated"] =
ag->round2(ag->pms5003t_1.temperatureCompensated(this->temp_2));
root["channels"]["2"]["rhumCompensated"] =
(int)ag->pms5003t_1.humidityCompensated(this->hum_2);
float val;
if (utils::isValidPMS(this->pm01_2)) {
root["channels"]["2"]["pm01"] = this->pm01_2;
}
if (utils::isValidPMS(this->pm25_2)) {
root["channels"]["2"]["pm02"] = this->pm25_2;
}
if (utils::isValidPMS(this->pm10_2)) {
root["channels"]["2"]["pm10"] = this->pm10_2;
}
if (utils::isValidPMS03Count(this->pm03PCount_2)) {
root["channels"]["2"]["pm003Count"] = this->pm03PCount_2;
}
if (utils::isValidTemperature(this->temp_2)) {
root["channels"]["2"]["atmp"] = ag->round2(this->temp_2);
if (localServer) {
val = ag->pms5003t_1.temperatureCompensated(this->temp_2);
if (utils::isValidTemperature(val)) {
root["channels"]["2"]["atmpCompensated"] = ag->round2(val);
}
}
}
if (utils::isValidHumidity(this->hum_2)) {
root["channels"]["2"]["rhum"] = this->hum_2;
if (localServer) {
val = ag->pms5003t_1.humidityCompensated(this->hum_2);
if (utils::isValidHumidity(val)) {
root["channels"]["2"]["rhumCompensated"] = (int)val;
}
}
}
root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.compensated(this->pm25_2, this->temp_2);
}
}
}
}
if (config->hasSensorSGP) {
if (this->TVOC >= 0) {
if (utils::isValidVOC(this->TVOC)) {
root["tvocIndex"] = this->TVOC;
}
if (this->TVOCRaw >= 0) {
if (utils::isValidVOC(this->TVOCRaw)) {
root["tvocRaw"] = this->TVOCRaw;
}
if (this->NOx >= 0) {
if (utils::isValidNOx(this->NOx)) {
root["noxIndex"] = this->NOx;
}
if (this->NOxRaw >= 0) {
if (utils::isValidNOx(this->NOxRaw)) {
root["noxRaw"] = this->NOxRaw;
}
}

View File

@ -41,7 +41,14 @@ String AirGradient::getVersion(void) { return GIT_VERSION; }
BoardType AirGradient::getBoardType(void) { return boardType; }
double AirGradient::round2(double value) {
return (int)(value * 100 + 0.5) / 100.0;
double ret;
if (value >= 0) {
ret = (int)(value * 100 + 0.5f);
} else {
ret = (int)(value * 100 - 0.5f);
}
return ret / 100;
}
String AirGradient::getBoardName(void) {

View File

@ -12,9 +12,10 @@
#include "S8/S8.h"
#include "Sgp41/Sgp41.h"
#include "Sht/Sht.h"
#include "Main/utils.h"
#ifndef GIT_VERSION
#define GIT_VERSION "snapshot"
#define GIT_VERSION "3.1.5-snap"
#endif
/**

89
src/Main/utils.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "utils.h"
#define VALID_TEMPERATURE_MAX (125)
#define VALID_TEMPERATURE_MIN (-40)
#define INVALID_TEMPERATURE (-1000)
#define VALID_HUMIDITY_MAX (100)
#define VALID_HUMIDITY_MIN (0)
#define INVALID_HUMIDITY (-1)
#define VALID_PMS_MAX (1000)
#define VALID_PMS_MIN (0)
#define INVALID_PMS (-1)
#define VALID_PMS03COUNT_MIN (0)
#define VALID_CO2_MAX (10000)
#define VALID_CO2_MIN (0)
#define INVALID_CO2 (-1)
#define VALID_NOX_MIN (0)
#define VALID_VOC_MIN (0)
#define INVALID_NOX (-1)
#define INVALID_VOC (-1)
utils::utils(/* args */) {}
utils::~utils() {}
bool utils::isValidTemperature(float value) {
if ((value >= VALID_TEMPERATURE_MIN) && (value <= VALID_TEMPERATURE_MAX)) {
return true;
}
return false;
}
bool utils::isValidHumidity(float value) {
if ((value >= VALID_HUMIDITY_MIN) && (value <= VALID_HUMIDITY_MAX)) {
return true;
}
return false;
}
bool utils::isValidCO2(int16_t value) {
if ((value >= VALID_CO2_MIN) && (value <= VALID_CO2_MAX)) {
return true;
}
return false;
}
bool utils::isValidPMS(int value) {
if ((value >= VALID_PMS_MIN) && (value <= VALID_PMS_MAX)) {
return true;
}
return false;
}
bool utils::isValidPMS03Count(int value) {
if (value >= VALID_PMS03COUNT_MIN) {
return true;
}
return false;
}
bool utils::isValidNOx(int value) {
if (value >= VALID_NOX_MIN) {
return true;
}
return false;
}
bool utils::isValidVOC(int value) {
if (value >= VALID_VOC_MIN) {
return true;
}
return false;
}
float utils::getInvalidTemperature(void) { return INVALID_TEMPERATURE; }
float utils::getInvalidHumidity(void) { return INVALID_HUMIDITY; }
int utils::getInvalidCO2(void) { return INVALID_CO2; }
int utils::getInvalidPMS(void) { return INVALID_PMS; }
int utils::getInvalidNOx(void) { return INVALID_NOX; }
int utils::getInvalidVOC(void) { return INVALID_VOC; }

30
src/Main/utils.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <Arduino.h>
class utils
{
private:
/* data */
public:
utils(/* args */);
~utils();
static bool isValidTemperature(float value);
static bool isValidHumidity(float value);
static bool isValidCO2(int16_t value);
static bool isValidPMS(int value);
static bool isValidPMS03Count(int value);
static bool isValidNOx(int value);
static bool isValidVOC(int value);
static float getInvalidTemperature(void);
static float getInvalidHumidity(void);
static int getInvalidCO2(void);
static int getInvalidPMS(void);
static int getInvalidNOx(void);
static int getInvalidVOC(void);
};
#endif /** _UTILS_H_ */

View File

@ -86,7 +86,7 @@ void PMSBase::handle() {
case 2: {
buf[bufIndex++] = value;
if (bufIndex >= 4) {
len = toValue(&buf[2]);
len = toI16(&buf[2]);
if (len != 28) {
// Serial.printf("Got good bad len %d\r\n", len);
len += 4;
@ -152,98 +152,98 @@ bool PMSBase::isFailed(void) { return failed; }
*
* @return uint16_t
*/
uint16_t PMSBase::getRaw0_1(void) { return toValue(&package[4]); }
uint16_t PMSBase::getRaw0_1(void) { return toU16(&package[4]); }
/**
* @brief Read PMS 2.5 ug/m3 with CF = 1 PM estimates
*
* @return uint16_t
*/
uint16_t PMSBase::getRaw2_5(void) { return toValue(&package[6]); }
uint16_t PMSBase::getRaw2_5(void) { return toU16(&package[6]); }
/**
* @brief Read PMS 10 ug/m3 with CF = 1 PM estimates
*
* @return uint16_t
*/
uint16_t PMSBase::getRaw10(void) { return toValue(&package[8]); }
uint16_t PMSBase::getRaw10(void) { return toU16(&package[8]); }
/**
* @brief Read PMS 0.1 ug/m3
*
* @return uint16_t
*/
uint16_t PMSBase::getPM0_1(void) { return toValue(&package[10]); }
uint16_t PMSBase::getPM0_1(void) { return toU16(&package[10]); }
/**
* @brief Read PMS 2.5 ug/m3
*
* @return uint16_t
*/
uint16_t PMSBase::getPM2_5(void) { return toValue(&package[12]); }
uint16_t PMSBase::getPM2_5(void) { return toU16(&package[12]); }
/**
* @brief Read PMS 10 ug/m3
*
* @return uint16_t
*/
uint16_t PMSBase::getPM10(void) { return toValue(&package[14]); }
uint16_t PMSBase::getPM10(void) { return toU16(&package[14]); }
/**
* @brief Get numnber concentrations over 0.3 um/0.1L
*
* @return uint16_t
*/
uint16_t PMSBase::getCount0_3(void) { return toValue(&package[16]); }
uint16_t PMSBase::getCount0_3(void) { return toU16(&package[16]); }
/**
* @brief Get numnber concentrations over 0.5 um/0.1L
*
* @return uint16_t
*/
uint16_t PMSBase::getCount0_5(void) { return toValue(&package[18]); }
uint16_t PMSBase::getCount0_5(void) { return toU16(&package[18]); }
/**
* @brief Get numnber concentrations over 1.0 um/0.1L
*
* @return uint16_t
*/
uint16_t PMSBase::getCount1_0(void) { return toValue(&package[20]); }
uint16_t PMSBase::getCount1_0(void) { return toU16(&package[20]); }
/**
* @brief Get numnber concentrations over 2.5 um/0.1L
*
* @return uint16_t
*/
uint16_t PMSBase::getCount2_5(void) { return toValue(&package[22]); }
uint16_t PMSBase::getCount2_5(void) { return toU16(&package[22]); }
/**
* @brief Get numnber concentrations over 5.0 um/0.1L (only PMS5003)
*
* @return uint16_t
*/
uint16_t PMSBase::getCount5_0(void) { return toValue(&package[24]); }
uint16_t PMSBase::getCount5_0(void) { return toU16(&package[24]); }
/**
* @brief Get numnber concentrations over 10.0 um/0.1L (only PMS5003)
*
* @return uint16_t
*/
uint16_t PMSBase::getCount10(void) { return toValue(&package[26]); }
uint16_t PMSBase::getCount10(void) { return toU16(&package[26]); }
/**
* @brief Get temperature (only PMS5003T)
*
* @return uint16_t
*/
uint16_t PMSBase::getTemp(void) { return toValue(&package[24]); }
int16_t PMSBase::getTemp(void) { return toI16(&package[24]); }
/**
* @brief Get humidity (only PMS5003T)
*
* @return uint16_t
*/
uint16_t PMSBase::getHum(void) { return toValue(&package[26]); }
uint16_t PMSBase::getHum(void) { return toU16(&package[26]); }
/**
* @brief Convert PMS2.5 to US AQI unit
@ -270,13 +270,58 @@ int PMSBase::pm25ToAQI(int pm02) {
return 500;
}
/**
* @brief Correction PM2.5
*
* @param pm25 Raw PM2.5 value
* @param humidity Humidity value (%)
* @return int
*/
int PMSBase::compensated(int pm25, float humidity) {
float value;
if (humidity < 0) {
humidity = 0;
}
if (humidity > 100) {
humidity = 100;
}
if(pm25 < 30) {
value = (pm25 * 0.524f) - (humidity * 0.0862f) + 5.75f;
} else if(pm25 < 50) {
value = (0.786f * (pm25 / 20 - 3 / 2) + 0.524f * (1 - (pm25 / 20 - 3 / 2))) * pm25 - (0.0862f * humidity) + 5.75f;
} else if(pm25 < 210) {
value = (0.786f * pm25) - (0.0862f * humidity) + 5.75f;
} else if(pm25 < 260) {
value = (0.69f * (pm25/50 - 21/5) + 0.786f * (1 - (pm25/50 - 21/5))) * pm25 - (0.0862f * humidity * (1 - (pm25/50 - 21/5))) + (2.966f * (pm25/50 -21/5)) + (5.75f * (1 - (pm25/50 - 21/5))) + (8.84f * (1.e-4) * pm25* (pm25/50 - 21/5));
} else {
value = 2.966f + (0.69f * pm25) + (8.84f * (1.e-4) * pm25);
}
if(value < 0) {
value = 0;
}
return (int)value;
}
/**
* @brief Convert two byte value to uint16_t value
*
* @param buf bytes array (must be >= 2)
* @return uint16_t
* @return int16_t
*/
uint16_t PMSBase::toValue(char *buf) { return (buf[0] << 8) | buf[1]; }
int16_t PMSBase::toI16(char *buf) {
int16_t value = buf[0];
value = (value << 8) | buf[1];
return value;
}
uint16_t PMSBase::toU16(char *buf) {
uint16_t value = buf[0];
value = (value << 8) | buf[1];
return value;
}
/**
* @brief Validate package data
@ -290,7 +335,7 @@ bool PMSBase::validate(char *buf) {
for (int i = 0; i < 30; i++) {
sum += buf[i];
}
if (sum == toValue(&buf[30])) {
if (sum == toU16(&buf[30])) {
for (int i = 0; i < 32; i++) {
package[i] = buf[i];
}

View File

@ -24,10 +24,11 @@ public:
uint16_t getCount10(void);
/** For PMS5003T*/
uint16_t getTemp(void);
int16_t getTemp(void);
uint16_t getHum(void);
int pm25ToAQI(int pm02);
int compensated(int pm25, float humidity);
private:
Stream *stream;
@ -36,7 +37,8 @@ private:
bool failed = false;
uint32_t lastRead;
uint16_t toValue(char *buf);
int16_t toI16(char *buf);
uint16_t toU16(char* buf);
bool validate(char *buf);
};

View File

@ -1,5 +1,6 @@
#include "PMS5003.h"
#include "Arduino.h"
#include "../Main/utils.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
@ -108,7 +109,9 @@ int PMS5003::getPm10Ae(void) { return pms.getPM10(); }
*
* @return int PM0.3 index
*/
int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); }
int PMS5003::getPm03ParticleCount(void) {
return pms.getCount0_3();
}
/**
* @brief Convert PM2.5 to US AQI
@ -118,6 +121,17 @@ int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); }
*/
int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); }
/**
* @brief Correct PM2.5
*
* @param pm25 PM2.5 raw value
* @param humidity Humidity value
* @return float
*/
int PMS5003::compensated(int pm25, float humidity) {
return pms.compensated(pm25, humidity);
}
/**
* @brief Check device initialized or not
*

View File

@ -24,6 +24,7 @@ public:
int getPm10Ae(void);
int getPm03ParticleCount(void);
int convertPm25ToUsAqi(int pm25);
int compensated(int pm25, float humidity);
private:
bool _isBegin = false;

View File

@ -1,5 +1,6 @@
#include "PMS5003T.h"
#include "Arduino.h"
#include "../Main/utils.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
@ -133,7 +134,9 @@ int PMS5003T::getPm10Ae(void) { return pms.getPM10(); }
*
* @return int PM 0.3 Count index
*/
int PMS5003T::getPm03ParticleCount(void) { return pms.getCount0_3(); }
int PMS5003T::getPm03ParticleCount(void) {
return pms.getCount0_3();
}
/**
* @brief Convert PM2.5 to US AQI
@ -149,7 +152,7 @@ int PMS5003T::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); }
* @return float Degree Celcius
*/
float PMS5003T::getTemperature(void) {
return pms.getTemp()/10.0f;
return pms.getTemp() / 10.0f;
}
/**
@ -158,7 +161,18 @@ float PMS5003T::getTemperature(void) {
* @return float Percent (%)
*/
float PMS5003T::getRelativeHumidity(void) {
return pms.getHum()/10.0f;
return pms.getHum() / 10.0f;
}
/**
* @brief Correct PM2.5
*
* @param pm25 PM2.5 raw value
* @param humidity Humidity value
* @return float
*/
float PMS5003T::compensated(int pm25, float humidity) {
return pms.compensated(pm25, humidity);
}
/**

View File

@ -29,6 +29,7 @@ public:
int convertPm25ToUsAqi(int pm25);
float getTemperature(void);
float getRelativeHumidity(void);
float compensated(int pm25, float humidity);
private:
bool _isBegin = false;

View File

@ -1,5 +1,6 @@
#include "S8.h"
#include "mb_crc.h"
#include "../Main/utils.h"
#if defined(ESP8266)
#include <SoftwareSerial.h>
#else
@ -103,7 +104,7 @@ void S8::getFirmwareVersion(char firmver[]) {
*/
int32_t S8::getSensorTypeId(void) {
if (this->isBegin() == false) {
return -1;
return utils::getInvalidCO2();
}
int32_t sensorType = 0;

View File

@ -2,6 +2,7 @@
#include "../Libraries/SensirionSGP41/src/SensirionI2CSgp41.h"
#include "../Libraries/Sensirion_Gas_Index_Algorithm/src/NOxGasIndexAlgorithm.h"
#include "../Libraries/Sensirion_Gas_Index_Algorithm/src/VOCGasIndexAlgorithm.h"
#include "../Main/utils.h"
#define sgpSensor() ((SensirionI2CSgp41 *)(this->_sensor))
#define vocAlgorithm() ((VOCGasIndexAlgorithm *)(this->_vocAlgorithm))
@ -66,6 +67,7 @@ bool Sgp41::begin(TwoWire &wire) {
}
onConditioning = true;
_handleFailCount = 0;
#ifdef ESP32
/** Create task */
xTaskCreate(
@ -108,7 +110,21 @@ void Sgp41::handle(void) {
noxRaw = srawNox;
nox = noxAlgorithm()->process(srawNox);
tvoc = vocAlgorithm()->process(srawVoc);
_handleFailCount = 0;
// AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
} else {
if(_handleFailCount < 5) {
_handleFailCount++;
AgLog("Polling SGP41 failed: %d", _handleFailCount);
}
if (_handleFailCount >= 5) {
tvocRaw = utils::getInvalidVOC();
tvoc = utils::getInvalidVOC();
noxRaw = utils::getInvalidNOx();
nox = utils::getInvalidNOx();
}
}
}
}
@ -141,7 +157,21 @@ void Sgp41::_handle(void) {
noxRaw = srawNox;
nox = noxAlgorithm()->process(srawNox);
tvoc = vocAlgorithm()->process(srawVoc);
_handleFailCount = 0;
// AgLog("Polling SGP41 success: tvoc: %d, nox: %d", tvoc, nox);
} else {
if(_handleFailCount < 5) {
_handleFailCount++;
AgLog("Polling SGP41 failed: %d", _handleFailCount);
}
if (_handleFailCount >= 5) {
tvocRaw = utils::getInvalidVOC();
tvoc = utils::getInvalidVOC();
noxRaw = utils::getInvalidNOx();
nox = utils::getInvalidNOx();
}
}
}
}
@ -176,7 +206,7 @@ void Sgp41::end(void) {
*/
int Sgp41::getTvocIndex(void) {
if (onConditioning) {
return -1;
return utils::getInvalidVOC();
}
return tvoc;
}
@ -188,7 +218,7 @@ int Sgp41::getTvocIndex(void) {
*/
int Sgp41::getNoxIndex(void) {
if (onConditioning) {
return -1;
return utils::getInvalidNOx();
}
return nox;
}

View File

@ -35,6 +35,7 @@ private:
bool onConditioning = true;
bool ready = false;
bool _isBegin = false;
uint8_t _handleFailCount = 0;
void *_sensor;
void *_vocAlgorithm;
void *_noxAlgorithm;

View File

@ -1,6 +1,7 @@
#include "Sht.h"
#include "../Libraries/arduino-sht/SHTSensor.h"
#include "../Main/utils.h"
/** Cast _sensor to SHTSensor */
#define shtSensor() ((SHTSensor *)(this->_sensor))
@ -131,14 +132,18 @@ void Sht::end(void) {
*
* @return float
*/
float Sht::getTemperature(void) { return shtSensor()->getTemperature(); }
float Sht::getTemperature(void) {
return shtSensor()->getTemperature();
}
/**
* @brief Get humidity
*
* @return float
*/
float Sht::getRelativeHumidity(void) { return shtSensor()->getHumidity(); }
float Sht::getRelativeHumidity(void) {
return shtSensor()->getHumidity();
}
/**
* @brief Measure temperature and humidity