mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-29 09:40:58 +02:00
Compare commits
135 Commits
Author | SHA1 | Date | |
---|---|---|---|
c841476ca4 | |||
359394af53 | |||
b8e10f473e | |||
cb511903ef | |||
ebb3f01dcd | |||
2e0ba26c97 | |||
c1a4758c6c | |||
0370a8aa15 | |||
863a37132a | |||
612317d976 | |||
8873bacf55 | |||
bf2388b121 | |||
b3918bd1fb | |||
2a6fce674e | |||
2f0663ced0 | |||
3adf58537a | |||
e10c9ff854 | |||
12c6ec9910 | |||
d108b63a57 | |||
6e212714fc | |||
866684eb30 | |||
9d01479406 | |||
20245f2110 | |||
3890919f54 | |||
76e40fea8c | |||
c4024f49fb | |||
ca5fc8d65b | |||
fd2cef153e | |||
507b958fdf | |||
335c29ebb1 | |||
2907d6f14e | |||
c8d5b546ed | |||
b7cfdc4c4d | |||
994d281e02 | |||
39470384e4 | |||
c25ba764bf | |||
826ff00f42 | |||
520550037d | |||
90f336dee7 | |||
0d39643e76 | |||
21232ec49d | |||
b7339de31f | |||
013fb94307 | |||
e16373a64d | |||
f929623443 | |||
59587ce2b7 | |||
9ec74450a5 | |||
28096e9faf | |||
682378a47c | |||
a1861be7b7 | |||
99ddd24432 | |||
29491e4cbe | |||
87cc3fc45f | |||
7471d8079a | |||
8b0fe967f1 | |||
6f1cef4e67 | |||
02b63ff816 | |||
228bf83e92 | |||
d3534cda52 | |||
aafaa42a68 | |||
2e9ff0d7dd | |||
244b7814a6 | |||
28d27ee8fd | |||
753f22923c | |||
c45901706f | |||
663836e277 | |||
d39e10908d | |||
c52962d628 | |||
6b65efd3d6 | |||
8bb87a75ef | |||
1afcca25a1 | |||
17238cff86 | |||
03e2afbf54 | |||
104d58a8c0 | |||
7a988ea6c1 | |||
54ed83cb89 | |||
e461b92c9f | |||
db21648e91 | |||
a9654506f5 | |||
63f653d5cd | |||
b049a23657 | |||
d6766ef68b | |||
6c3259b94b | |||
b1aaa04421 | |||
2df78e9066 | |||
186f0d27ab | |||
e25aa87ecc | |||
1cc8941a5c | |||
9bf1495be7 | |||
73089b51f5 | |||
625e60a5bf | |||
88e3d0bd3f | |||
171821cfcf | |||
900a2da2ac | |||
fb57a112c9 | |||
ab69b686ec | |||
6746d25dc2 | |||
be150e105a | |||
ecadeeb156 | |||
219ff73132 | |||
0a9142204d | |||
81b13134d2 | |||
f3a9c722b2 | |||
3be3218115 | |||
5edb21cfe9 | |||
6cd587b008 | |||
6d01366887 | |||
1a347e9cfe | |||
6432e4451e | |||
97f0696002 | |||
e46e11c030 | |||
dc261f668d | |||
b5cced40d2 | |||
040bd28038 | |||
b0ae851427 | |||
01943f594d | |||
01a69668cc | |||
ed7b8df6fe | |||
6c1c914716 | |||
6a0d88ff10 | |||
9097eed137 | |||
c9b5e5f0d7 | |||
c12bac4ce3 | |||
9ae9b2ac9c | |||
7fb3e68b6d | |||
cf65a1f901 | |||
5fb27b6d1e | |||
7b9dac756b | |||
4b2a5f5540 | |||
4af77d532e | |||
812c2ab803 | |||
0ece16f434 | |||
df6cca3714 | |||
c8aa07ae20 | |||
a1d216ac77 |
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@ -101,26 +107,31 @@ 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.
|
||||
|
||||
#### 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 }` |
|
||||
|
@ -68,7 +68,6 @@ static LocalServer localServer(Serial, openMetrics, measurements, configuration,
|
||||
wifiConnector);
|
||||
static MqttClient mqttClient(Serial);
|
||||
|
||||
static int pmFailCount = 0;
|
||||
static int getCO2FailCount = 0;
|
||||
static AgFirmwareMode fwMode = FW_MODE_I_BASIC_40PS;
|
||||
|
||||
@ -126,6 +125,9 @@ void setup() {
|
||||
openMetrics.setAirGradient(&ag);
|
||||
localServer.setAirGraident(&ag);
|
||||
|
||||
/** Example set custom API root URL */
|
||||
// apiClient.setApiRoot("https://example.custom.api");
|
||||
|
||||
/** Init sensor */
|
||||
boardInit();
|
||||
|
||||
@ -204,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();
|
||||
@ -233,7 +231,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 +239,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -264,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) {
|
||||
@ -500,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();
|
||||
@ -511,15 +514,21 @@ 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);
|
||||
pmFailCount = 0;
|
||||
Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion());
|
||||
ag.pms5003.resetFailCount();
|
||||
} else {
|
||||
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;
|
||||
ag.pms5003.updateFailCount();
|
||||
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();
|
||||
measurements.pm10_1 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_1 = utils::getInvalidPmValue();
|
||||
}
|
||||
|
||||
if(ag.pms5003.getFailCount() >= ag.pms5003.getFailCountMax()) {
|
||||
Serial.printf("PMS failure count reach to max set %d, restarting...", ag.pms5003.getFailCountMax());
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -534,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++;
|
||||
}
|
||||
|
||||
@ -564,5 +571,7 @@ static void tempHumUpdate(void) {
|
||||
}
|
||||
} else {
|
||||
Serial.println("SHT read failed");
|
||||
measurements.Temperature = utils::getInvalidTemperature();
|
||||
measurements.Humidity = utils::getInvalidHumidity();
|
||||
}
|
||||
}
|
||||
|
@ -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::getInvalidPmValue();
|
||||
int pm25 = utils::getInvalidPmValue();
|
||||
int pm10 = utils::getInvalidPmValue();
|
||||
int pm03PCount = utils::getInvalidPmValue();
|
||||
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::isValidPm(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::isValidPm(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::isValidPm(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::isValidPm03Count(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",
|
||||
|
@ -68,7 +68,6 @@ static LocalServer localServer(Serial, openMetrics, measurements, configuration,
|
||||
wifiConnector);
|
||||
static MqttClient mqttClient(Serial);
|
||||
|
||||
static int pmFailCount = 0;
|
||||
static int getCO2FailCount = 0;
|
||||
static AgFirmwareMode fwMode = FW_MODE_I_33PS;
|
||||
|
||||
@ -126,6 +125,9 @@ void setup() {
|
||||
openMetrics.setAirGradient(&ag);
|
||||
localServer.setAirGraident(&ag);
|
||||
|
||||
/** Example set custom API root URL */
|
||||
// apiClient.setApiRoot("https://example.custom.api");
|
||||
|
||||
/** Init sensor */
|
||||
boardInit();
|
||||
|
||||
@ -202,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();
|
||||
@ -231,7 +229,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 +237,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -262,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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,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) {
|
||||
@ -552,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();
|
||||
@ -563,15 +566,21 @@ 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);
|
||||
pmFailCount = 0;
|
||||
Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion());
|
||||
ag.pms5003.resetFailCount();
|
||||
} else {
|
||||
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;
|
||||
ag.pms5003.updateFailCount();
|
||||
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();
|
||||
measurements.pm10_1 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_1 = utils::getInvalidPmValue();
|
||||
}
|
||||
|
||||
if(ag.pms5003.getFailCount() >= ag.pms5003.getFailCountMax()) {
|
||||
Serial.printf("PMS failure count reach to max set %d, restarting...", ag.pms5003.getFailCountMax());
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -586,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++;
|
||||
}
|
||||
|
||||
@ -616,5 +623,7 @@ static void tempHumUpdate(void) {
|
||||
}
|
||||
} else {
|
||||
Serial.println("SHT read failed");
|
||||
measurements.Temperature = utils::getInvalidTemperature();
|
||||
measurements.Humidity = utils::getInvalidHumidity();
|
||||
}
|
||||
}
|
||||
|
@ -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::getInvalidPmValue();
|
||||
int pm25 = utils::getInvalidPmValue();
|
||||
int pm10 = utils::getInvalidPmValue();
|
||||
int pm03PCount = utils::getInvalidPmValue();
|
||||
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::isValidPm(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::isValidPm(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::isValidPm(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::isValidPm03Count(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",
|
||||
|
@ -68,7 +68,6 @@ static LocalServer localServer(Serial, openMetrics, measurements, configuration,
|
||||
wifiConnector);
|
||||
static MqttClient mqttClient(Serial);
|
||||
|
||||
static int pmFailCount = 0;
|
||||
static uint32_t factoryBtnPressTime = 0;
|
||||
static int getCO2FailCount = 0;
|
||||
static AgFirmwareMode fwMode = FW_MODE_I_42PS;
|
||||
@ -127,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();
|
||||
|
||||
@ -229,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();
|
||||
@ -258,7 +256,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 +264,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,8 +330,6 @@ static void factoryConfigReset(void) {
|
||||
// }
|
||||
|
||||
/** Reset WIFI */
|
||||
// WiFi.enableSTA(true); // Incase offline mode
|
||||
// WiFi.disconnect(true, true);
|
||||
wifiConnector.reset();
|
||||
|
||||
/** Reset local config */
|
||||
@ -355,9 +358,7 @@ static void factoryConfigReset(void) {
|
||||
|
||||
static void wdgFeedUpdate(void) {
|
||||
ag.watchdog.reset();
|
||||
Serial.println();
|
||||
Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset");
|
||||
Serial.println();
|
||||
Serial.println("External watchdog feed!");
|
||||
}
|
||||
|
||||
static bool sgp41Init(void) {
|
||||
@ -595,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();
|
||||
@ -606,15 +607,21 @@ 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);
|
||||
pmFailCount = 0;
|
||||
Serial.printf("PM firmware version: %d\r\n", ag.pms5003.getFirmwareVersion());
|
||||
ag.pms5003.resetFailCount();
|
||||
} else {
|
||||
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;
|
||||
ag.pms5003.updateFailCount();
|
||||
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();
|
||||
measurements.pm10_1 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_1 = utils::getInvalidPmValue();
|
||||
}
|
||||
|
||||
if(ag.pms5003.getFailCount() >= ag.pms5003.getFailCountMax()) {
|
||||
Serial.printf("PMS failure count reach to max set %d, restarting...", ag.pms5003.getFailCountMax());
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -629,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++;
|
||||
}
|
||||
|
||||
@ -659,5 +664,7 @@ static void tempHumUpdate(void) {
|
||||
}
|
||||
} else {
|
||||
Serial.println("SHT read failed");
|
||||
measurements.Temperature = utils::getInvalidTemperature();
|
||||
measurements.Humidity = utils::getInvalidHumidity();
|
||||
}
|
||||
}
|
||||
|
@ -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::getInvalidPmValue();
|
||||
int pm25 = utils::getInvalidPmValue();
|
||||
int pm10 = utils::getInvalidPmValue();
|
||||
int pm03PCount = utils::getInvalidPmValue();
|
||||
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::isValidPm(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::isValidPm(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::isValidPm(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::isValidPm03Count(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",
|
||||
|
@ -88,7 +88,6 @@ static OtaHandler otaHandler;
|
||||
static LocalServer localServer(Serial, openMetrics, measurements, configuration,
|
||||
wifiConnector);
|
||||
|
||||
static int pmFailCount = 0;
|
||||
static uint32_t factoryBtnPressTime = 0;
|
||||
static int getCO2FailCount = 0;
|
||||
static AgFirmwareMode fwMode = FW_MODE_I_9PSL;
|
||||
@ -99,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);
|
||||
@ -119,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);
|
||||
@ -163,6 +160,9 @@ void setup() {
|
||||
openMetrics.setAirGradient(ag);
|
||||
localServer.setAirGraident(ag);
|
||||
|
||||
/** Example set custom API root URL */
|
||||
// apiClient.setApiRoot("https://example.custom.api");
|
||||
|
||||
/** Init sensor */
|
||||
boardInit();
|
||||
|
||||
@ -259,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() {
|
||||
@ -286,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) {
|
||||
@ -296,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();
|
||||
@ -317,7 +318,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 +326,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,12 +429,7 @@ 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\"");
|
||||
}
|
||||
|
||||
/** Reset local config */
|
||||
configuration.reset();
|
||||
@ -445,7 +448,7 @@ static void factoryConfigReset(void) {
|
||||
/** Show current content cause reset ignore */
|
||||
factoryBtnPressTime = 0;
|
||||
if (ag->isOne()) {
|
||||
appDispHandler();
|
||||
updateDisplayAndLedBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -453,7 +456,7 @@ static void factoryConfigReset(void) {
|
||||
if (factoryBtnPressTime != 0) {
|
||||
if (ag->isOne()) {
|
||||
/** Restore last display content */
|
||||
appDispHandler();
|
||||
updateDisplayAndLedBar();
|
||||
}
|
||||
}
|
||||
factoryBtnPressTime = 0;
|
||||
@ -462,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) {
|
||||
@ -700,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) {
|
||||
@ -781,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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -809,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) {
|
||||
@ -941,58 +942,45 @@ static void configUpdateHandle() {
|
||||
|
||||
stateMachine.executeLedBarTest();
|
||||
}
|
||||
else if(ag->isOpenAir()) {
|
||||
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();
|
||||
@ -1007,8 +995,9 @@ 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();
|
||||
@ -1019,21 +1008,26 @@ 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);
|
||||
pmFailCount = 0;
|
||||
Serial.printf("PM firmware version: %d\r\n", ag->pms5003.getFirmwareVersion());
|
||||
ag->pms5003.resetFailCount();
|
||||
} else {
|
||||
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;
|
||||
ag->pms5003.updateFailCount();
|
||||
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();
|
||||
measurements.pm10_1 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_1 = utils::getInvalidPmValue();
|
||||
}
|
||||
|
||||
if (ag->pms5003.getFailCount() >= ag->pms5003.getFailCountMax()) {
|
||||
restart = true;
|
||||
}
|
||||
}
|
||||
} 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();
|
||||
@ -1051,19 +1045,33 @@ static void updatePm(void) {
|
||||
Serial.printf("[1] Temperature in C: %0.2f\r\n", measurements.temp_1);
|
||||
Serial.printf("[1] Relative Humidity: %d\r\n", measurements.hum_1);
|
||||
Serial.printf("[1] Temperature compensated in C: %0.2f\r\n",
|
||||
ag->pms5003t_1.temperatureCompensated(measurements.temp_1));
|
||||
Serial.printf("[1] Relative Humidity compensated: %f\r\n",
|
||||
ag->pms5003t_1.humidityCompensated(measurements.hum_1));
|
||||
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 {
|
||||
measurements.pm01_1 = -1;
|
||||
measurements.pm25_1 = -1;
|
||||
measurements.pm10_1 = -1;
|
||||
measurements.pm03PCount_1 = -1;
|
||||
measurements.temp_1 = -1001;
|
||||
measurements.hum_1 = -1;
|
||||
if (configuration.hasSensorPMS1) {
|
||||
ag->pms5003t_1.updateFailCount();
|
||||
Serial.printf("[1] PMS read failed %d times\r\n", ag->pms5003t_1.getFailCount());
|
||||
|
||||
if (ag->pms5003t_1.getFailCount() >= PMS_FAIL_COUNT_SET_INVALID) {
|
||||
measurements.pm01_1 = utils::getInvalidPmValue();
|
||||
measurements.pm25_1 = utils::getInvalidPmValue();
|
||||
measurements.pm10_1 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_1 = utils::getInvalidPmValue();
|
||||
measurements.temp_1 = utils::getInvalidTemperature();
|
||||
measurements.hum_1 = utils::getInvalidHumidity();
|
||||
}
|
||||
|
||||
if (ag->pms5003t_1.getFailCount() >= ag->pms5003t_1.getFailCountMax()) {
|
||||
restart = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@ -1081,16 +1089,30 @@ static void updatePm(void) {
|
||||
Serial.printf("[2] Temperature in C: %0.2f\r\n", measurements.temp_2);
|
||||
Serial.printf("[2] Relative Humidity: %d\r\n", measurements.hum_2);
|
||||
Serial.printf("[2] Temperature compensated in C: %0.2f\r\n",
|
||||
ag->pms5003t_1.temperatureCompensated(measurements.temp_2));
|
||||
Serial.printf("[2] Relative Humidity compensated: %d\r\n",
|
||||
ag->pms5003t_1.humidityCompensated(measurements.hum_2));
|
||||
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 {
|
||||
measurements.pm01_2 = -1;
|
||||
measurements.pm25_2 = -1;
|
||||
measurements.pm10_2 = -1;
|
||||
measurements.pm03PCount_2 = -1;
|
||||
measurements.temp_2 = -1001;
|
||||
measurements.hum_2 = -1;
|
||||
if (configuration.hasSensorPMS2) {
|
||||
ag->pms5003t_2.updateFailCount();
|
||||
Serial.printf("[2] PMS read failed %d times\r\n", ag->pms5003t_2.getFailCount());
|
||||
|
||||
if (ag->pms5003t_2.getFailCount() >= PMS_FAIL_COUNT_SET_INVALID) {
|
||||
measurements.pm01_2 = utils::getInvalidPmValue();
|
||||
measurements.pm25_2 = utils::getInvalidPmValue();
|
||||
measurements.pm10_2 = utils::getInvalidPmValue();
|
||||
measurements.pm03PCount_2 = utils::getInvalidPmValue();
|
||||
measurements.temp_2 = utils::getInvalidTemperature();
|
||||
measurements.hum_2 = utils::getInvalidHumidity();
|
||||
}
|
||||
|
||||
if (ag->pms5003t_2.getFailCount() >= ag->pms5003t_2.getFailCountMax()) {
|
||||
restart = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configuration.hasSensorPMS1 && configuration.hasSensorPMS2 &&
|
||||
@ -1190,6 +1212,11 @@ static void updatePm(void) {
|
||||
ag->sgp41.setCompensationTemperatureHumidity(temp, hum);
|
||||
}
|
||||
}
|
||||
|
||||
if (restart) {
|
||||
Serial.printf("PMS failure count reach to max set %d, restarting...", ag->pms5003.getFailCountMax());
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
static void sendDataToServer(void) {
|
||||
@ -1201,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++;
|
||||
}
|
||||
|
||||
@ -1230,6 +1255,8 @@ static void tempHumUpdate(void) {
|
||||
measurements.Humidity);
|
||||
}
|
||||
} else {
|
||||
measurements.Temperature = utils::getInvalidTemperature();
|
||||
measurements.Humidity = utils::getInvalidHumidity();
|
||||
Serial.println("SHT read failed");
|
||||
}
|
||||
}
|
@ -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::getInvalidPmValue();
|
||||
int pm25 = utils::getInvalidPmValue();
|
||||
int pm10 = utils::getInvalidPmValue();
|
||||
int pm03PCount = utils::getInvalidPmValue();
|
||||
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;
|
||||
@ -118,33 +118,33 @@ String OpenMetrics::getPayload(void) {
|
||||
atmpCompensated = _temp;
|
||||
ahumCompensated = _hum;
|
||||
} else {
|
||||
atmpCompensated = ag->pms5003t_1.temperatureCompensated(_temp);
|
||||
ahumCompensated = ag->pms5003t_1.humidityCompensated(_hum);
|
||||
atmpCompensated = ag->pms5003t_1.compensateTemp(_temp);
|
||||
ahumCompensated = ag->pms5003t_1.compensateHum(_hum);
|
||||
}
|
||||
|
||||
if (config.hasSensorPMS1 || config.hasSensorPMS2) {
|
||||
if (pm01 >= 0) {
|
||||
if (utils::isValidPm(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::isValidPm(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::isValidPm(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::isValidPm03Count(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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AirGradient Air Quality Sensor
|
||||
version=3.1.4
|
||||
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.
|
||||
|
@ -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 ,
|
||||
|
|
@ -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
|
||||
@ -58,6 +58,7 @@ bool AgApiClient::fetchServerConfiguration(void) {
|
||||
}
|
||||
#else
|
||||
HTTPClient client;
|
||||
client.setTimeout(timeoutMs);
|
||||
if (client.begin(uri) == false) {
|
||||
getConfigFailed = true;
|
||||
return false;
|
||||
@ -66,6 +67,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;
|
||||
@ -109,21 +114,25 @@ bool AgApiClient::postToServer(String data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String uri =
|
||||
"http://hw.airgradient.com/sensors/airgradient:" + ag->deviceId() +
|
||||
"/measures";
|
||||
logInfo("Post uri: " + uri);
|
||||
logInfo("Post data: " + data);
|
||||
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;
|
||||
}
|
||||
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,16 @@ 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; }
|
||||
|
||||
/**
|
||||
* @brief Set http request timeout. (Default: 10s)
|
||||
*
|
||||
* @param timeoutMs
|
||||
*/
|
||||
void AgApiClient::setTimeout(uint16_t timeoutMs) {
|
||||
this->timeoutMs = timeoutMs;
|
||||
}
|
@ -20,10 +20,12 @@ class AgApiClient : public PrintLog {
|
||||
private:
|
||||
Configuration &config;
|
||||
AirGradient *ag;
|
||||
String apiRoot = "http://hw.airgradient.com";
|
||||
|
||||
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);
|
||||
@ -37,6 +39,9 @@ public:
|
||||
bool isNotAvailableOnDashboard(void);
|
||||
void setAirGradient(AirGradient *ag);
|
||||
bool sendPing(int rssi, int bootCount);
|
||||
String getApiRoot() const;
|
||||
void setApiRoot(const String &apiRoot);
|
||||
void setTimeout(uint16_t timeoutMs);
|
||||
};
|
||||
|
||||
#endif /** _AG_API_CLIENT_H_ */
|
||||
|
@ -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();
|
||||
}
|
||||
@ -264,12 +267,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 =
|
||||
@ -626,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") {
|
||||
@ -1080,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) {
|
||||
@ -1171,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;
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
void setOfflineMode(bool offline);
|
||||
void setOfflineModeWithoutSave(bool offline);
|
||||
bool isLedBarModeChanged(void);
|
||||
bool isMonitorDisplayCompensatedValues(void);
|
||||
};
|
||||
|
||||
#endif /** _AG_CONFIG_H_ */
|
||||
|
@ -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))
|
||||
@ -9,37 +10,43 @@
|
||||
*
|
||||
* @param hasStatus
|
||||
*/
|
||||
void OledDisplay::showTempHum(bool hasStatus) {
|
||||
char buf[10];
|
||||
if (value.Temperature > -1001) {
|
||||
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 */
|
||||
if (value.Humidity >= 0) {
|
||||
snprintf(buf, sizeof(buf), "%d%%", value.Humidity);
|
||||
/** Show humidity */
|
||||
if (utils::isValidHumidity(value.Humidity)) {
|
||||
snprintf(buf, buf_size, "%d%%", value.Humidity);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%-%%");
|
||||
snprintf(buf, buf_size, "-%%");
|
||||
}
|
||||
|
||||
if (value.Humidity > 99) {
|
||||
@ -260,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);
|
||||
@ -271,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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,12 +290,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 +302,115 @@ 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 */
|
||||
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, "%d", pm25);
|
||||
}
|
||||
} 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()) {
|
||||
if (value.pm25_1 >= 0) {
|
||||
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(value.pm25_1));
|
||||
} else {
|
||||
sprintf(strBuf, "%s", "-");
|
||||
}
|
||||
DISP()->drawStr(48, 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) {
|
||||
sprintf(strBuf, "%d", value.pm25_1);
|
||||
} else {
|
||||
sprintf(strBuf, "%s", "-");
|
||||
}
|
||||
DISP()->drawStr(48, 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 && config.isMonitorDisplayCompensatedValues()) {
|
||||
pm25 = (int)ag->pms5003.compensate(pm25, value.Humidity);
|
||||
}
|
||||
|
||||
ag->display.setCursor(0, 12);
|
||||
snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", value.pm25_1);
|
||||
if (utils::isValidPm(pm25)) {
|
||||
snprintf(strBuf, sizeof(strBuf), "PM2.5:%d", pm25);
|
||||
} 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()) {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
|
||||
@ -403,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,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()) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "AgStateMachine.h"
|
||||
|
||||
#define LED_TEST_BLINK_DELAY 50 /** ms */
|
||||
#define LED_FAST_BLINK_DELAY 250 /** ms */
|
||||
#define LED_SLOW_BLINK_DELAY 1000 /** ms */
|
||||
#define LED_SHORT_BLINK_DELAY 500 /** ms */
|
||||
@ -9,9 +10,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
|
||||
@ -141,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);
|
||||
@ -305,18 +310,23 @@ void StateMachine::co2Calibration(void) {
|
||||
|
||||
void StateMachine::ledBarTest(void) {
|
||||
if (config.isLedBarTestRequested()) {
|
||||
if (config.getCountry() == "TH") {
|
||||
uint32_t tstart = millis();
|
||||
logInfo("Start run LED test for 2 min");
|
||||
while (1) {
|
||||
ledBarRunTest();
|
||||
uint32_t ms = (uint32_t)(millis() - tstart);
|
||||
if (ms >= (60 * 1000 * 2)) {
|
||||
logInfo("LED test after 2 min finish");
|
||||
break;
|
||||
if (ag->isOne()) {
|
||||
if (config.getCountry() == "TH") {
|
||||
uint32_t tstart = millis();
|
||||
logInfo("Start run LED test for 2 min");
|
||||
while (1) {
|
||||
ledBarRunTest();
|
||||
uint32_t ms = (uint32_t)(millis() - tstart);
|
||||
if (ms >= (60 * 1000 * 2)) {
|
||||
logInfo("LED test after 2 min finish");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ledBarRunTest();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if(ag->isOpenAir()) {
|
||||
ledBarRunTest();
|
||||
}
|
||||
}
|
||||
@ -325,22 +335,31 @@ void StateMachine::ledBarTest(void) {
|
||||
void StateMachine::ledBarPowerUpTest(void) { ledBarRunTest(); }
|
||||
|
||||
void StateMachine::ledBarRunTest(void) {
|
||||
disp.setText("LED Test", "running", ".....");
|
||||
runLedTest('r');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('g');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('b');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('w');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('n');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
if (ag->isOne()) {
|
||||
disp.setText("LED Test", "running", ".....");
|
||||
runLedTest('r');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('g');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('b');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('w');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
runLedTest('n');
|
||||
ag->ledBar.show();
|
||||
delay(1000);
|
||||
} else if (ag->isOpenAir()) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ag->statusLed.setOn();
|
||||
delay(LED_TEST_BLINK_DELAY);
|
||||
ag->statusLed.setOff();
|
||||
delay(LED_TEST_BLINK_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::runLedTest(char color) {
|
||||
@ -480,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: {
|
||||
@ -489,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());
|
||||
}
|
||||
@ -573,7 +592,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 +732,7 @@ void StateMachine::handleLeds(AgStateMachineState state) {
|
||||
break;
|
||||
}
|
||||
case AgStateMachineSensorConfigFailed: {
|
||||
/** Server is reachable but there is some configuration 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);
|
||||
|
418
src/AgValue.cpp
418
src/AgValue.cpp
@ -1,8 +1,42 @@
|
||||
#include "AgValue.h"
|
||||
#include "AgConfigure.h"
|
||||
#include "AirGradient.h"
|
||||
#include "Main/utils.h"
|
||||
#include "Libraries/Arduino_JSON/src/Arduino_JSON.h"
|
||||
|
||||
#define json_prop_pmFirmware "firmware"
|
||||
|
||||
/**
|
||||
* @brief Get PMS5003 firmware version string
|
||||
*
|
||||
* @param fwCode
|
||||
* @return String
|
||||
*/
|
||||
String Measurements::pms5003FirmwareVersion(int fwCode) {
|
||||
return pms5003FirmwareVersionBase("PMS5003x", fwCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PMS5003T firmware version string
|
||||
*
|
||||
* @param fwCode
|
||||
* @return String
|
||||
*/
|
||||
String Measurements::pms5003TFirmwareVersion(int fwCode) {
|
||||
return pms5003FirmwareVersionBase("PMS5003x", fwCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware version string
|
||||
*
|
||||
* @param prefix Prefix firmware string
|
||||
* @param fwCode Version code
|
||||
* @return string
|
||||
*/
|
||||
String Measurements::pms5003FirmwareVersionBase(String prefix, int fwCode) {
|
||||
return prefix + String("-") + String(fwCode);
|
||||
}
|
||||
|
||||
String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
|
||||
void *_ag, void *_config) {
|
||||
AirGradient *ag = (AirGradient *)_ag;
|
||||
@ -13,36 +47,40 @@ 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::isValidPm(this->pm01_1)) {
|
||||
root["pm01"] = this->pm01_1;
|
||||
}
|
||||
if (this->pm25_1 >= 0) {
|
||||
if (utils::isValidPm(this->pm25_1)) {
|
||||
root["pm02"] = this->pm25_1;
|
||||
}
|
||||
if (this->pm10_1 >= 0) {
|
||||
if (utils::isValidPm(this->pm10_1)) {
|
||||
root["pm10"] = this->pm10_1;
|
||||
}
|
||||
if (this->pm03PCount_1 >= 0) {
|
||||
if (utils::isValidPm03Count(this->pm03PCount_1)) {
|
||||
root["pm003Count"] = this->pm03PCount_1;
|
||||
}
|
||||
if (!localServer) {
|
||||
|
||||
root[json_prop_pmFirmware] =
|
||||
this->pms5003FirmwareVersion(ag->pms5003.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
|
||||
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,109 +88,297 @@ 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.compensate(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::isValidPm(this->pm01_1) && utils::isValidPm(this->pm01_2)) {
|
||||
root["pm01"] = ag->round2((this->pm01_1 + this->pm01_2) / 2.0f);
|
||||
}
|
||||
if (utils::isValidPm(this->pm25_1) && utils::isValidPm(this->pm25_2)) {
|
||||
root["pm02"] = ag->round2((this->pm25_1 + this->pm25_2) / 2.0f);
|
||||
}
|
||||
if (utils::isValidPm(this->pm10_1) && utils::isValidPm(this->pm10_2)) {
|
||||
root["pm10"] = ag->round2((this->pm10_1 + this->pm10_2) / 2.0f);
|
||||
}
|
||||
if (utils::isValidPm(this->pm03PCount_1) && utils::isValidPm(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.compensateTemp((this->temp_1 + this->temp_2) / 2.0f);
|
||||
if (utils::isValidTemperature(val)) {
|
||||
root["atmpCompensated"] = ag->round2(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
val = ag->pms5003t_2.compensateHum((this->hum_1 + this->hum_2) / 2.0f);
|
||||
if (utils::isValidHumidity(val)) {
|
||||
root["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (fwMode == FW_MODE_O_1PS || fwMode == FW_MODE_O_1PST) {
|
||||
float val;
|
||||
if (config->hasSensorPMS1) {
|
||||
if (utils::isValidPm(this->pm01_1)) {
|
||||
root["pm01"] = this->pm01_1;
|
||||
}
|
||||
if (utils::isValidPm(this->pm25_1)) {
|
||||
root["pm02"] = this->pm25_1;
|
||||
}
|
||||
if (utils::isValidPm(this->pm10_1)) {
|
||||
root["pm10"] = this->pm10_1;
|
||||
}
|
||||
if (utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_1);
|
||||
if (utils::isValidHumidity(val)) {
|
||||
root["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1);
|
||||
if (!localServer) {
|
||||
root[json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
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_2.temperatureCompensated(this->temp_2));
|
||||
root["rhumCompensated"] =
|
||||
(int)ag->pms5003t_2.humidityCompensated(this->hum_2);
|
||||
if(utils::isValidPm(this->pm01_2)) {
|
||||
root["pm01"] = this->pm01_2;
|
||||
}
|
||||
if(utils::isValidPm(this->pm25_2)) {
|
||||
root["pm02"] = this->pm25_2;
|
||||
}
|
||||
if(utils::isValidPm(this->pm10_2)) {
|
||||
root["pm10"] = this->pm10_2;
|
||||
}
|
||||
if(utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_2);
|
||||
if (utils::isValidHumidity(val)) {
|
||||
root["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->hum_2);
|
||||
if(!localServer) {
|
||||
root[json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
} 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::isValidPm(this->pm01_1)) {
|
||||
root["pm01"] = this->pm01_1;
|
||||
}
|
||||
if (utils::isValidPm(this->pm25_1)) {
|
||||
root["pm02"] = this->pm25_1;
|
||||
}
|
||||
if (utils::isValidPm(this->pm10_1)) {
|
||||
root["pm10"] = this->pm10_1;
|
||||
}
|
||||
if (utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_1);
|
||||
if(utils::isValidHumidity(val)) {
|
||||
root["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1);
|
||||
if(!localServer) {
|
||||
root[json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
||||
}
|
||||
} 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::isValidPm(this->pm01_2)) {
|
||||
root["pm01"] = this->pm01_2;
|
||||
}
|
||||
if(utils::isValidPm(this->pm25_2)) {
|
||||
root["pm02"] = this->pm25_2;
|
||||
}
|
||||
if(utils::isValidPm(this->pm10_2)) {
|
||||
root["pm10"] = this->pm10_2;
|
||||
}
|
||||
if(utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_2);
|
||||
if(utils::isValidHumidity(val)) {
|
||||
root["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1);
|
||||
if(!localServer) {
|
||||
root[json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
} 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::isValidPm(this->pm01_1)) {
|
||||
root["channels"]["1"]["pm01"] = this->pm01_1;
|
||||
}
|
||||
if(utils::isValidPm(this->pm25_1)) {
|
||||
root["channels"]["1"]["pm02"] = this->pm25_1;
|
||||
}
|
||||
if(utils::isValidPm(this->pm10_1)) {
|
||||
root["channels"]["1"]["pm10"] = this->pm10_1;
|
||||
}
|
||||
if (utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_1);
|
||||
if (utils::isValidHumidity(val)) {
|
||||
root["channels"]["1"]["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["channels"]["1"]["pm02Compensated"] = ag->pms5003t_1.compensate(this->pm25_1, this->hum_1);
|
||||
|
||||
// PMS5003T version
|
||||
if(!localServer) {
|
||||
root["channels"]["1"][json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
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::isValidPm(this->pm01_2)) {
|
||||
root["channels"]["2"]["pm01"] = this->pm01_2;
|
||||
}
|
||||
if (utils::isValidPm(this->pm25_2)) {
|
||||
root["channels"]["2"]["pm02"] = this->pm25_2;
|
||||
}
|
||||
if (utils::isValidPm(this->pm10_2)) {
|
||||
root["channels"]["2"]["pm10"] = this->pm10_2;
|
||||
}
|
||||
if (utils::isValidPm03Count(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.compensateTemp(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.compensateHum(this->hum_2);
|
||||
if (utils::isValidHumidity(val)) {
|
||||
root["channels"]["2"]["rhumCompensated"] = (int)val;
|
||||
}
|
||||
}
|
||||
}
|
||||
root["channels"]["2"]["pm02Compensated"] = ag->pms5003t_2.compensate(this->pm25_2, this->hum_2);
|
||||
// PMS5003T version
|
||||
if(!localServer) {
|
||||
root["channels"]["2"][json_prop_pmFirmware] =
|
||||
pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,16 +386,16 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
class Measurements {
|
||||
private:
|
||||
String pms5003FirmwareVersion(int fwCode);
|
||||
String pms5003TFirmwareVersion(int fwCode);
|
||||
String pms5003FirmwareVersionBase(String prefix, int fwCode);
|
||||
public:
|
||||
Measurements() {
|
||||
pm25_1 = -1;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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) {
|
||||
@ -58,6 +65,10 @@ bool AirGradient::isOne(void) {
|
||||
return boardType == BoardType::ONE_INDOOR;
|
||||
}
|
||||
|
||||
bool AirGradient::isOpenAir(void) {
|
||||
return boardType == BoardType::OPEN_AIR_OUTDOOR;
|
||||
}
|
||||
|
||||
bool AirGradient::isPro4_2(void) {
|
||||
return boardType == BoardType::DIY_PRO_INDOOR_V4_2;
|
||||
}
|
||||
|
@ -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.9-snap"
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -134,6 +135,14 @@ public:
|
||||
*/
|
||||
bool isOne(void);
|
||||
|
||||
/**
|
||||
* @brief Check that Airgradient object is OPEN_AIR
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool isOpenAir(void);
|
||||
|
||||
/**
|
||||
* @brief Check that Airgradient object is DIY_PRO 4.2 indoor
|
||||
*
|
||||
|
94
src/Main/utils.cpp
Normal file
94
src/Main/utils.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#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::isValidPm(int value) {
|
||||
if ((value >= VALID_PMS_MIN) && (value <= VALID_PMS_MAX)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool utils::isValidPm03Count(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::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;
|
||||
}
|
31
src/Main/utils.h
Normal file
31
src/Main/utils.h
Normal file
@ -0,0 +1,31 @@
|
||||
#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 isValidPm(int value);
|
||||
static bool isValidPm03Count(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 getInvalidPmValue(void);
|
||||
static int getInvalidNOx(void);
|
||||
static int getInvalidVOC(void);
|
||||
static float degreeC_To_F(float t);
|
||||
};
|
||||
|
||||
|
||||
#endif /** _UTILS_H_ */
|
339
src/PMS/PMS.cpp
339
src/PMS/PMS.cpp
@ -2,248 +2,293 @@
|
||||
#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;
|
||||
lastRead = 0; // To read buffer on handle without wait after 1.5sec
|
||||
failCount = 0;
|
||||
_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 = toValue(&buf[2]);
|
||||
if (len != 28) {
|
||||
// Serial.printf("Got good bad len %d\r\n", len);
|
||||
len += 4;
|
||||
step = 3;
|
||||
} else {
|
||||
// Serial.println("Got good len");
|
||||
step = 4;
|
||||
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
|
||||
* @brief Increate number of fail
|
||||
*
|
||||
* @return true Failed
|
||||
* @return false No problem
|
||||
*/
|
||||
bool PMSBase::isFailed(void) { return failed; }
|
||||
void PMSBase::updateFailCount(void) {
|
||||
if (failCount < failCountMax) {
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void PMSBase::resetFailCount(void) { failCount = 0; }
|
||||
|
||||
/**
|
||||
* @brief Get number of fail
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int PMSBase::getFailCount(void) { return failCount; }
|
||||
|
||||
int PMSBase::getFailCountMax(void) { return failCountMax; }
|
||||
|
||||
/**
|
||||
* @brief Read PMS 0.1 ug/m3 with CF = 1 PM estimates
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t PMSBase::getRaw0_1(void) { return toValue(&package[4]); }
|
||||
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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&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 toValue(&package[26]); }
|
||||
uint16_t PMSBase::getCount10(void) { return pms_count10; }
|
||||
|
||||
/**
|
||||
* @brief Get temperature (only PMS5003T)
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t PMSBase::getTemp(void) { return toValue(&package[24]); }
|
||||
int16_t PMSBase::getTemp(void) { return pms_temp; }
|
||||
|
||||
/**
|
||||
* @brief Get humidity (only PMS5003T)
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t PMSBase::getHum(void) { return toValue(&package[26]); }
|
||||
uint16_t PMSBase::getHum(void) { return pms_hum; }
|
||||
|
||||
/**
|
||||
* @brief Get firmware version code
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t PMSBase::getFirmwareVersion(void) { return pms_firmwareVersion; }
|
||||
|
||||
/**
|
||||
* @brief Ge PMS5003 error code
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
uint8_t PMSBase::getErrorCode(void) { return pms_errorCode; }
|
||||
|
||||
/**
|
||||
* @brief Convert PMS2.5 to US AQI unit
|
||||
@ -270,13 +315,61 @@ int PMSBase::pm25ToAQI(int pm02) {
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Correction PM2.5
|
||||
*
|
||||
* Formula: https://www.airgradient.com/documentation/correction-algorithms/
|
||||
*
|
||||
* @param pm25 Raw PM2.5 value
|
||||
* @param humidity Humidity value (%)
|
||||
* @return int
|
||||
*/
|
||||
int PMSBase::compensate(int pm25, float humidity) {
|
||||
float value;
|
||||
float fpm25 = pm25;
|
||||
if (humidity < 0) {
|
||||
humidity = 0;
|
||||
}
|
||||
if (humidity > 100) {
|
||||
humidity = 100.0f;
|
||||
}
|
||||
|
||||
if(pm25 < 30) { /** pm2.5 < 30 */
|
||||
value = (fpm25 * 0.524f) - (humidity * 0.0862f) + 5.75f;
|
||||
} else if(pm25 < 50) { /** 30 <= pm2.5 < 50 */
|
||||
value = (0.786f * (fpm25 * 0.05f - 1.5f) + 0.524f * (1.0f - (fpm25 * 0.05f - 1.5f))) * fpm25 - (0.0862f * humidity) + 5.75f;
|
||||
} else if(pm25 < 210) { /** 50 <= pm2.5 < 210 */
|
||||
value = (0.786f * fpm25) - (0.0862f * humidity) + 5.75f;
|
||||
} else if(pm25 < 260) { /** 210 <= pm2.5 < 260 */
|
||||
value = (0.69f * (fpm25 * 0.02f - 4.2f) + 0.786f * (1.0f - (fpm25 * 0.02f - 4.2f))) * fpm25 - (0.0862f * humidity * (1.0f - (fpm25 * 0.02f - 4.2f))) + (2.966f * (fpm25 * 0.02f - 4.2f)) + (5.75f * (1.0f - (fpm25 * 0.02f - 4.2f))) + (8.84f * (1.e-4) * fpm25 * fpm25 * (fpm25 * 0.02f - 4.2f));
|
||||
} else { /** 260 <= pm2.5 */
|
||||
value = 2.966f + (0.69f * fpm25) + (8.84f * (1.e-4) * fpm25 * fpm25);
|
||||
}
|
||||
|
||||
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(const uint8_t *buf) {
|
||||
int16_t value = buf[0];
|
||||
value = (value << 8) | buf[1];
|
||||
return value;
|
||||
}
|
||||
|
||||
uint16_t PMSBase::toU16(const uint8_t *buf) {
|
||||
uint16_t value = buf[0];
|
||||
value = (value << 8) | buf[1];
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate package data
|
||||
@ -285,16 +378,32 @@ uint16_t PMSBase::toValue(char *buf) { return (buf[0] << 8) | buf[1]; }
|
||||
* @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 == toValue(&buf[30])) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
package[i] = buf[i];
|
||||
}
|
||||
if (sum == toU16(&buf[30])) {
|
||||
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];
|
||||
}
|
||||
|
@ -3,11 +3,19 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#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);
|
||||
int getFailCountMax(void);
|
||||
uint16_t getRaw0_1(void);
|
||||
uint16_t getRaw2_5(void);
|
||||
uint16_t getRaw10(void);
|
||||
@ -18,26 +26,64 @@ 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);
|
||||
uint16_t getCount10(void);
|
||||
|
||||
/** For PMS5003T*/
|
||||
uint16_t getTemp(void);
|
||||
int16_t getTemp(void);
|
||||
uint16_t getHum(void);
|
||||
uint8_t getFirmwareVersion(void);
|
||||
uint8_t getErrorCode(void);
|
||||
|
||||
int pm25ToAQI(int pm02);
|
||||
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;
|
||||
|
||||
uint16_t toValue(char *buf);
|
||||
bool validate(char *buf);
|
||||
/** 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;
|
||||
|
||||
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_ */
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "PMS5003.h"
|
||||
#include "Arduino.h"
|
||||
#include "../Main/utils.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <SoftwareSerial.h>
|
||||
/**
|
||||
* @brief Init sensor
|
||||
*
|
||||
@ -37,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;
|
||||
}
|
||||
|
||||
@ -62,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;
|
||||
}
|
||||
@ -77,7 +73,7 @@ bool PMS5003::begin(void) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
_ver = pms.getFirmwareVersion();
|
||||
this->_isBegin = true;
|
||||
return true;
|
||||
}
|
||||
@ -108,7 +104,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 +116,41 @@ int PMS5003::getPm03ParticleCount(void) { return pms.getCount0_3(); }
|
||||
*/
|
||||
int PMS5003::convertPm25ToUsAqi(int pm25) { return pms.pm25ToAQI(pm25); }
|
||||
|
||||
/**
|
||||
* @brief Correct PM2.5
|
||||
*
|
||||
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
|
||||
*
|
||||
* @param pm25 PM2.5 raw value
|
||||
* @param humidity Humidity value
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003::compensate(int pm25, float humidity) {
|
||||
return pms.compensate(pm25, humidity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sensor firmware version
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003::getFirmwareVersion(void) { return _ver; }
|
||||
|
||||
/**
|
||||
* @brief Get sensor error code
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
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
|
||||
*
|
||||
@ -152,12 +185,26 @@ 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(); }
|
||||
void PMS5003::handle(void) { pms.readPackage(this->_serial); }
|
||||
|
||||
void PMS5003::updateFailCount(void) {
|
||||
pms.updateFailCount();
|
||||
}
|
||||
|
||||
void PMS5003::resetFailCount(void) {
|
||||
pms.resetFailCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sensor status
|
||||
* @brief Get number of fail count
|
||||
*
|
||||
* @return true No problem
|
||||
* @return false Communication timeout or sensor has removed
|
||||
* @return int
|
||||
*/
|
||||
bool PMS5003::isFailed(void) { return pms.isFailed(); }
|
||||
int PMS5003::getFailCount(void) { return pms.getFailCount(); }
|
||||
|
||||
/**
|
||||
* @brief Get number of fail count max
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003::getFailCountMax(void) { return pms.getFailCountMax(); }
|
||||
|
@ -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,21 +21,30 @@ public:
|
||||
#endif
|
||||
void end(void);
|
||||
void handle(void);
|
||||
bool isFailed(void);
|
||||
void updateFailCount(void);
|
||||
void resetFailCount(void);
|
||||
int getFailCount(void);
|
||||
int getFailCountMax(void);
|
||||
int getPm01Ae(void);
|
||||
int getPm25Ae(void);
|
||||
int getPm10Ae(void);
|
||||
int getPm03ParticleCount(void);
|
||||
int convertPm25ToUsAqi(int pm25);
|
||||
int compensate(int pm25, float humidity);
|
||||
int getFirmwareVersion(void);
|
||||
uint8_t getErrorCode(void);
|
||||
bool connected(void);
|
||||
|
||||
private:
|
||||
bool _isBegin = false;
|
||||
int _ver;
|
||||
BoardType _boardDef;
|
||||
PMSBase pms;
|
||||
const BoardDef *bsp;
|
||||
#if defined(ESP8266)
|
||||
Stream *_debugStream;
|
||||
const char *TAG = "PMS5003";
|
||||
SoftwareSerial *_serial;
|
||||
#else
|
||||
HardwareSerial *_serial;
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "PMS5003T.h"
|
||||
#include "Arduino.h"
|
||||
#include "../Main/utils.h"
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <SoftwareSerial.h>
|
||||
@ -66,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;
|
||||
}
|
||||
@ -102,7 +102,7 @@ bool PMS5003T::begin(void) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
_ver = pms.getFirmwareVersion();
|
||||
this->_isBegin = true;
|
||||
return true;
|
||||
}
|
||||
@ -133,7 +133,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 +151,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,9 +160,44 @@ 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
|
||||
*
|
||||
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
|
||||
*
|
||||
* @param pm25 PM2.5 raw value
|
||||
* @param humidity Humidity value
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003T::compensate(int pm25, float humidity) {
|
||||
return pms.compensate(pm25, humidity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get module(s) firmware version
|
||||
*
|
||||
* @return int Version code
|
||||
*/
|
||||
int PMS5003T::getFirmwareVersion(void) { return _ver; }
|
||||
|
||||
/**
|
||||
* @brief Get sensor error code
|
||||
*
|
||||
* @return uint8_t
|
||||
*/
|
||||
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
|
||||
*
|
||||
@ -192,13 +229,26 @@ 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(); }
|
||||
void PMS5003T::handle(void) { pms.readPackage(this->_serial); }
|
||||
|
||||
void PMS5003T::updateFailCount(void) {
|
||||
pms.updateFailCount();
|
||||
}
|
||||
|
||||
void PMS5003T::resetFailCount(void) {
|
||||
pms.resetFailCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sensor status
|
||||
* @brief Get fail count
|
||||
*
|
||||
* @return true No problem
|
||||
* @return false Communication timeout or sensor has removed
|
||||
* @return int
|
||||
*/
|
||||
bool PMS5003T::isFailed(void) { return pms.isFailed(); }
|
||||
int PMS5003T::getFailCount(void) { return pms.getFailCount(); }
|
||||
|
||||
/**
|
||||
* @brief Get fail count max
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int PMS5003T::getFailCountMax(void) { return pms.getFailCountMax(); }
|
||||
|
@ -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,10 @@ public:
|
||||
void end(void);
|
||||
|
||||
void handle(void);
|
||||
bool isFailed(void);
|
||||
void updateFailCount(void);
|
||||
void resetFailCount(void);
|
||||
int getFailCount(void);
|
||||
int getFailCountMax(void);
|
||||
int getPm01Ae(void);
|
||||
int getPm25Ae(void);
|
||||
int getPm10Ae(void);
|
||||
@ -29,16 +35,22 @@ public:
|
||||
int convertPm25ToUsAqi(int pm25);
|
||||
float getTemperature(void);
|
||||
float getRelativeHumidity(void);
|
||||
int compensate(int pm25, float humidity);
|
||||
int getFirmwareVersion(void);
|
||||
uint8_t getErrorCode(void);
|
||||
bool connected(void);
|
||||
|
||||
private:
|
||||
bool _isBegin = false;
|
||||
bool _isSleep = false;
|
||||
int _ver; /** Firmware version code */
|
||||
|
||||
BoardType _boardDef;
|
||||
const BoardDef *bsp;
|
||||
#if defined(ESP8266)
|
||||
Stream *_debugStream;
|
||||
const char *TAG = "PMS5003T";
|
||||
SoftwareSerial *_serial;
|
||||
#else
|
||||
HardwareSerial *_serial;
|
||||
#endif
|
||||
|
@ -4,14 +4,30 @@ PMS5003TBase::PMS5003TBase() {}
|
||||
|
||||
PMS5003TBase::~PMS5003TBase() {}
|
||||
|
||||
float PMS5003TBase::temperatureCompensated(float temp) {
|
||||
/**
|
||||
* @brief Compensate the temperature
|
||||
*
|
||||
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
|
||||
*
|
||||
* @param temp
|
||||
* @return * float
|
||||
*/
|
||||
float PMS5003TBase::compensateTemp(float temp) {
|
||||
if (temp < 10.0f) {
|
||||
return temp * 1.327f - 6.738f;
|
||||
}
|
||||
return temp * 1.181f - 5.113f;
|
||||
}
|
||||
|
||||
float PMS5003TBase::humidityCompensated(float hum) {
|
||||
/**
|
||||
* @brief Compensate the humidity
|
||||
*
|
||||
* Reference formula: https://www.airgradient.com/documentation/correction-algorithms/
|
||||
*
|
||||
* @param temp
|
||||
* @return * float
|
||||
*/
|
||||
float PMS5003TBase::compensateHum(float hum) {
|
||||
hum = hum * 1.259f + 7.34f;
|
||||
|
||||
if (hum > 100.0f) {
|
||||
|
@ -8,8 +8,8 @@ private:
|
||||
public:
|
||||
PMS5003TBase();
|
||||
~PMS5003TBase();
|
||||
float temperatureCompensated(float temp);
|
||||
float humidityCompensated(float hum);
|
||||
float compensateTemp(float temp);
|
||||
float compensateHum(float hum);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ private:
|
||||
bool onConditioning = true;
|
||||
bool ready = false;
|
||||
bool _isBegin = false;
|
||||
uint8_t _handleFailCount = 0;
|
||||
void *_sensor;
|
||||
void *_vocAlgorithm;
|
||||
void *_noxAlgorithm;
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user