Saving work

This commit is contained in:
Phat Nguyen
2024-09-21 13:06:01 +07:00
parent ca5fc8d65b
commit 20245f2110
7 changed files with 145 additions and 95 deletions

View File

@ -41,33 +41,35 @@ You get the following response:
"bootCount": 6, "bootCount": 6,
"ledMode": "pm", "ledMode": "pm",
"firmware": "3.1.3", "firmware": "3.1.3",
"model": "I-9PSL" "model": "I-9PSL",
"monitorDisplayCompensatedValues": true
} }
``` ```
| Properties | Type | Explanation | | Properties | Type | Explanation |
|------------------|--------|--------------------------------------------------------------------| |-----------------------------------|---------|----------------------------------------------------------------------------------------|
| `serialno` | String | Serial Number of the monitor | | `serialno` | String | Serial Number of the monitor |
| `wifi` | Number | WiFi signal strength | | `wifi` | Number | WiFi signal strength |
| `pm01` | Number | PM1 in ug/m3 | | `pm01` | Number | PM1 in ug/m3 |
| `pm02` | Number | PM2.5 in ug/m3 | | `pm02` | Number | PM2.5 in ug/m3 |
| `pm10` | Number | PM10 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) | | `pm02Compensated` | Number | PM2.5 in ug/m3 with correction applied (from fw version 3.1.4 onwards) |
| `rco2` | Number | CO2 in ppm | | `rco2` | Number | CO2 in ppm |
| `pm003Count` | Number | Particle count per dL | | `pm003Count` | Number | Particle count per dL |
| `atmp` | Number | Temperature in Degrees Celsius | | `atmp` | Number | Temperature in Degrees Celsius |
| `atmpCompensated` | Number | Temperature in Degrees Celsius with correction applied | | `atmpCompensated` | Number | Temperature in Degrees Celsius with correction applied |
| `rhum` | Number | Relative Humidity | | `rhum` | Number | Relative Humidity |
| `rhumCompensated` | Number | Relative Humidity with correction applied | | `rhumCompensated` | Number | Relative Humidity with correction applied |
| `tvocIndex` | Number | Senisiron VOC Index | | `tvocIndex` | Number | Senisiron VOC Index |
| `tvocRaw` | Number | VOC raw value | | `tvocRaw` | Number | VOC raw value |
| `noxIndex` | Number | Senisirion NOx Index | | `noxIndex` | Number | Senisirion NOx Index |
| `noxRaw` | Number | NOx raw value | | `noxRaw` | Number | NOx raw value |
| `boot` | Number | Counts every measurement cycle. Low boot counts indicate restarts. | | `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. | | `bootCount` | Number | Same as boot property. Required for Home Assistant compatability. Will be depreciated. |
| `ledMode` | String | Current configuration of the LED mode | | `ledMode` | String | Current configuration of the LED mode |
| `firmware` | String | Current firmware version | | `firmware` | String | Current firmware version |
| `model` | String | Current model name | | `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. 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.
@ -110,21 +112,22 @@ If the monitor is set up on the AirGradient dashboard, it will also receive conf
#### Configuration Parameters (GET/PUT) #### Configuration Parameters (GET/PUT)
| Properties | Description | Type | Accepted Values | Example | | 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"} | | `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"} | | `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"} | | `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"} | | `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} | | `displayBrightness` | Brightness of the Display. | Number | 0-100 | `{"displayBrightness": 50}` |
| `ledBarBrightness` | Brightness of the LEDBar. | Number | 0-100 | {"ledBarBrightness": 40} | | `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} | | `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"} | | `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"} | | `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"} | | `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} | | `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} | | `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} | | `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} | | `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} | | `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} | | `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.8]()) | Boolean | `false`: Without compensate (default) <br> `true`: with compensate | `{"monitorDisplayCompensatedValues": false }` |

View File

@ -41,21 +41,23 @@ JSON_PROP_DEF(displayBrightness);
JSON_PROP_DEF(co2CalibrationRequested); JSON_PROP_DEF(co2CalibrationRequested);
JSON_PROP_DEF(ledBarTestRequested); JSON_PROP_DEF(ledBarTestRequested);
JSON_PROP_DEF(offlineMode); JSON_PROP_DEF(offlineMode);
JSON_PROP_DEF(monitorDisplayCompensatedValues);
#define jprop_model_default "" #define jprop_model_default ""
#define jprop_country_default "TH" #define jprop_country_default "TH"
#define jprop_pmStandard_default getPMStandardString(false) #define jprop_pmStandard_default getPMStandardString(false)
#define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2) #define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2)
#define jprop_abcDays_default 8 #define jprop_abcDays_default 8
#define jprop_tvocLearningOffset_default 12 #define jprop_tvocLearningOffset_default 12
#define jprop_noxLearningOffset_default 12 #define jprop_noxLearningOffset_default 12
#define jprop_mqttBrokerUrl_default "" #define jprop_mqttBrokerUrl_default ""
#define jprop_temperatureUnit_default "c" #define jprop_temperatureUnit_default "c"
#define jprop_configurationControl_default String(CONFIGURATION_CONTROL_NAME[ConfigurationControl::ConfigurationControlBoth]) #define jprop_configurationControl_default String(CONFIGURATION_CONTROL_NAME[ConfigurationControl::ConfigurationControlBoth])
#define jprop_postDataToAirGradient_default true #define jprop_postDataToAirGradient_default true
#define jprop_ledBarBrightness_default 100 #define jprop_ledBarBrightness_default 100
#define jprop_displayBrightness_default 100 #define jprop_displayBrightness_default 100
#define jprop_offlineMode_default false #define jprop_offlineMode_default false
#define jprop_monitorDisplayCompensatedValues_default false
JSONVar jconfig; JSONVar jconfig;
@ -167,6 +169,7 @@ void Configuration::defaultConfig(void) {
jconfig[jprop_abcDays] = jprop_abcDays_default; jconfig[jprop_abcDays] = jprop_abcDays_default;
jconfig[jprop_model] = jprop_model_default; jconfig[jprop_model] = jprop_model_default;
jconfig[jprop_offlineMode] = jprop_offlineMode_default; jconfig[jprop_offlineMode] = jprop_offlineMode_default;
jconfig[jprop_monitorDisplayCompensatedValues] = jprop_monitorDisplayCompensatedValues_default;
saveConfig(); saveConfig();
} }
@ -628,6 +631,27 @@ bool Configuration::parse(String data, bool isLocal) {
} }
} }
if (JSON.typeof_(root[jprop_monitorDisplayCompensatedValues]) == "boolean") {
bool value = root[jprop_monitorDisplayCompensatedValues];
bool oldValue = jconfig[jprop_monitorDisplayCompensatedValues];
if (value != oldValue) {
changed = true;
jconfig[jprop_monitorDisplayCompensatedValues] = value;
configLogInfo(String(jprop_monitorDisplayCompensatedValues),
String(oldValue ? "true" : "false"),
String(value ? "true" : "false"));
}
} else {
if (jsonTypeInvalid(root[jprop_monitorDisplayCompensatedValues],
"boolean")) {
failedMessage = jsonTypeInvalidMessage(
String(jprop_monitorDisplayCompensatedValues), "boolean");
jsonInvalid();
return false;
}
}
if (ag->getBoardType() == ONE_INDOOR || if (ag->getBoardType() == ONE_INDOOR ||
ag->getBoardType() == OPEN_AIR_OUTDOOR) { ag->getBoardType() == OPEN_AIR_OUTDOOR) {
if (JSON.typeof_(root["targetFirmware"]) == "string") { if (JSON.typeof_(root["targetFirmware"]) == "string") {
@ -1082,12 +1106,14 @@ void Configuration::toConfig(const char *buf) {
} }
if (JSON.typeof_(jconfig[jprop_offlineMode]) != "boolean") { if (JSON.typeof_(jconfig[jprop_offlineMode]) != "boolean") {
isInvalid = true; jconfig[jprop_offlineMode] = jprop_offlineMode_default;
} else {
isInvalid = false;
} }
if (isInvalid) {
jconfig[jprop_offlineMode] = false; /** Validate monitorDisplayCompensatedValues */
if (JSON.typeof_(jconfig[jprop_monitorDisplayCompensatedValues]) !=
"boolean") {
jconfig[jprop_monitorDisplayCompensatedValues] =
jprop_monitorDisplayCompensatedValues_default;
} }
if (changed) { if (changed) {
@ -1173,6 +1199,10 @@ bool Configuration::isLedBarModeChanged(void) {
return changed; return changed;
} }
bool Configuration::isMonitorDisplayCompensatedValues(void) {
return jconfig[jprop_monitorDisplayCompensatedValues];
}
bool Configuration::isDisplayBrightnessChanged(void) { bool Configuration::isDisplayBrightnessChanged(void) {
bool changed = displayBrightnessChanged; bool changed = displayBrightnessChanged;
displayBrightnessChanged = false; displayBrightnessChanged = false;

View File

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

View File

@ -10,37 +10,49 @@
* *
* @param hasStatus * @param hasStatus
*/ */
void OledDisplay::showTempHum(bool hasStatus) { void OledDisplay::showTempHum(bool hasStatus, char* buf, int buf_size) {
char buf[16];
if (utils::isValidTemperature(value.Temperature)) { if (utils::isValidTemperature(value.Temperature)) {
float t = 0.0f;
if(ag->isOpenAir() && config.isMonitorDisplayCompensatedValues()) {
if(config.isTemperatureUnitInF()) {
/** Compensate temperature */
t = ag->pms5003t_1.compensateTemp(value.Temperature);
/** Convert C to F */
t = (t * 9)/5.0f + 32.0f;
}
} else {
}
if (config.isTemperatureUnitInF()) { if (config.isTemperatureUnitInF()) {
float tempF = (value.Temperature * 9) / 5 + 32; float tempF = (value.Temperature * 9) / 5 + 32;
if (hasStatus) { if (hasStatus) {
snprintf(buf, sizeof(buf), "%0.1f", tempF); snprintf(buf, buf_size, "%0.1f", tempF);
} else { } else {
snprintf(buf, sizeof(buf), "%0.1f°F", tempF); snprintf(buf, buf_size, "%0.1f°F", tempF);
} }
} else { } else {
if (hasStatus) { if (hasStatus) {
snprintf(buf, sizeof(buf), "%.1f", value.Temperature); snprintf(buf, buf_size, "%.1f", value.Temperature);
} else { } else {
snprintf(buf, sizeof(buf), "%.1f°C", value.Temperature); snprintf(buf, buf_size, "%.1f°C", value.Temperature);
} }
} }
} else { } else {
if (config.isTemperatureUnitInF()) { if (config.isTemperatureUnitInF()) {
snprintf(buf, sizeof(buf), "-°F"); snprintf(buf, buf_size, "-°F");
} else { } else {
snprintf(buf, sizeof(buf), "-°C"); snprintf(buf, buf_size, "-°C");
} }
} }
DISP()->drawUTF8(1, 10, buf); DISP()->drawUTF8(1, 10, buf);
/** Show humidty */ /** Show humidty */
if (utils::isValidHumidity(value.Humidity)) { if (utils::isValidHumidity(value.Humidity)) {
snprintf(buf, sizeof(buf), "%d%%", value.Humidity); snprintf(buf, buf_size, "%d%%", value.Humidity);
} else { } else {
snprintf(buf, sizeof(buf), "-%%"); snprintf(buf, buf_size, "-%%");
} }
if (value.Humidity > 99) { if (value.Humidity > 99) {
@ -261,7 +273,7 @@ void OledDisplay::showDashboard(const char *status) {
do { do {
DISP()->setFont(u8g2_font_t0_16_tf); DISP()->setFont(u8g2_font_t0_16_tf);
if ((status == NULL) || (strlen(status) == 0)) { if ((status == NULL) || (strlen(status) == 0)) {
showTempHum(false); showTempHum(false, strBuf, sizeof(strBuf));
} else { } else {
String strStatus = "Show status: " + String(status); String strStatus = "Show status: " + String(status);
logInfo(strStatus); logInfo(strStatus);
@ -272,7 +284,7 @@ void OledDisplay::showDashboard(const char *status) {
/** Show WiFi NA*/ /** Show WiFi NA*/
if (strcmp(status, "WiFi N/A") == 0) { if (strcmp(status, "WiFi N/A") == 0) {
DISP()->setFont(u8g2_font_t0_12_tf); DISP()->setFont(u8g2_font_t0_12_tf);
showTempHum(true); showTempHum(true, strBuf, sizeof(strBuf));
} }
} }
@ -304,29 +316,27 @@ void OledDisplay::showDashboard(const char *status) {
DISP()->drawStr(55, 27, "PM2.5"); DISP()->drawStr(55, 27, "PM2.5");
/** Draw PM2.5 value */ /** Draw PM2.5 value */
int pm25 = value.pm25_1; if (utils::isValidPm(value.pm25_1)) {
if (config.hasSensorSHT) { int pm25 = value.pm25_1;
pm25 = ag->pms5003.compensate(pm25, value.Humidity); if (config.isPmStandardInUSAQI() &&
logInfo("PM2.5:" + String(value.pm25_1) + String("Compensated:") + String(pm25)); config.isMonitorDisplayCompensatedValues()) {
} if (config.hasSensorSHT) {
DISP()->setFont(u8g2_font_t0_22b_tf); pm25 = ag->pms5003.compensate(pm25, value.Humidity);
if (config.isPmStandardInUSAQI()) { }
if (utils::isValidPm(pm25)) {
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(pm25)); sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(pm25));
} else { } else {
sprintf(strBuf, "%s", "-"); sprintf(strBuf, "%d", pm25);
} }
DISP()->drawStr(55, 48, strBuf); } else {
DISP()->setFont(u8g2_font_t0_12_tf); sprintf(strBuf, "%s", "-");
}
DISP()->setFont(u8g2_font_t0_22b_tf);
DISP()->drawStr(55, 48, strBuf);
DISP()->setFont(u8g2_font_t0_12_tf);
if (config.isPmStandardInUSAQI()) {
DISP()->drawUTF8(55, 61, "AQI"); DISP()->drawUTF8(55, 61, "AQI");
} else { } else {
if (utils::isValidPm(pm25)) {
sprintf(strBuf, "%d", pm25);
} else {
sprintf(strBuf, "%s", "-");
}
DISP()->drawStr(55, 48, strBuf);
DISP()->setFont(u8g2_font_t0_12_tf);
DISP()->drawUTF8(55, 61, "ug/m³"); DISP()->drawUTF8(55, 61, "ug/m³");
} }
@ -355,18 +365,18 @@ void OledDisplay::showDashboard(const char *status) {
ag->display.clear(); ag->display.clear();
/** Set CO2 */ /** Set CO2 */
if(utils::isValidCO2(value.CO2)) { if (utils::isValidCO2(value.CO2)) {
snprintf(strBuf, sizeof(strBuf), "CO2:%d", value.CO2); snprintf(strBuf, sizeof(strBuf), "CO2:%d", value.CO2);
} else { } else {
snprintf(strBuf, sizeof(strBuf), "CO2:-"); snprintf(strBuf, sizeof(strBuf), "CO2:-");
} }
ag->display.setCursor(0, 0); ag->display.setCursor(0, 0);
ag->display.setText(strBuf); ag->display.setText(strBuf);
/** Set PM */ /** Set PM */
int pm25 = value.pm25_1; int pm25 = value.pm25_1;
if(config.hasSensorSHT) { if (config.hasSensorSHT && config.isMonitorDisplayCompensatedValues()) {
pm25 = (int)ag->pms5003.compensate(pm25, value.Humidity); pm25 = (int)ag->pms5003.compensate(pm25, value.Humidity);
} }
ag->display.setCursor(0, 12); ag->display.setCursor(0, 12);

View File

@ -16,7 +16,7 @@ private:
Measurements &value; Measurements &value;
bool isDisplayOff = false; 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, String text);
void setCentralText(int y, const char *text); void setCentralText(int y, const char *text);

View File

@ -87,3 +87,8 @@ int utils::getInvalidPmValue(void) { return INVALID_PMS; }
int utils::getInvalidNOx(void) { return INVALID_NOX; } int utils::getInvalidNOx(void) { return INVALID_NOX; }
int utils::getInvalidVOC(void) { return INVALID_VOC; } int utils::getInvalidVOC(void) { return INVALID_VOC; }
float utils::degreeC_To_F(float t) {
/** (t * 9)/5 + 32 */
return t * 1.8f + 32.0f;
}

View File

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