2024-04-03 07:04:55 +07:00
|
|
|
#include "AgConfigure.h"
|
2024-04-11 09:29:29 +07:00
|
|
|
#include "Libraries/Arduino_JSON/src/Arduino_JSON.h"
|
2024-04-30 20:51:08 +07:00
|
|
|
#if ESP32
|
|
|
|
#include "FS.h"
|
|
|
|
#include "SPIFFS.h"
|
|
|
|
#else
|
|
|
|
#include "EEPROM.h"
|
|
|
|
#endif
|
2024-05-02 10:19:49 +07:00
|
|
|
#include <time.h>
|
2024-04-30 20:51:08 +07:00
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
#define EEPROM_CONFIG_SIZE 1024
|
2024-05-10 09:11:43 +07:00
|
|
|
#define CONFIG_FILE_NAME "/AgConfigure_Configuration.json"
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
const char *CONFIGURATION_CONTROL_NAME[] = {
|
|
|
|
[ConfigurationControlLocal] = "local",
|
2024-04-03 21:26:04 +07:00
|
|
|
[ConfigurationControlCloud] = "cloud",
|
2024-04-03 07:04:55 +07:00
|
|
|
[ConfigurationControlBoth] = "both"};
|
2024-04-05 06:39:59 +07:00
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
const char *LED_BAR_MODE_NAMES[] = {
|
|
|
|
[LedBarModeOff] = "off",
|
|
|
|
[LedBarModePm] = "pm",
|
|
|
|
[LedBarModeCO2] = "co2",
|
|
|
|
};
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
#define JSON_PROP_NAME(name) jprop_##name
|
|
|
|
#define JSON_PROP_DEF(name) const char *JSON_PROP_NAME(name) = #name
|
|
|
|
|
|
|
|
JSON_PROP_DEF(model);
|
|
|
|
JSON_PROP_DEF(country);
|
|
|
|
JSON_PROP_DEF(pmStandard);
|
|
|
|
JSON_PROP_DEF(ledBarMode);
|
|
|
|
JSON_PROP_DEF(abcDays);
|
|
|
|
JSON_PROP_DEF(tvocLearningOffset);
|
|
|
|
JSON_PROP_DEF(noxLearningOffset);
|
|
|
|
JSON_PROP_DEF(mqttBrokerUrl);
|
|
|
|
JSON_PROP_DEF(temperatureUnit);
|
|
|
|
JSON_PROP_DEF(configurationControl);
|
|
|
|
JSON_PROP_DEF(postDataToAirGradient);
|
2024-05-13 21:28:37 +07:00
|
|
|
JSON_PROP_DEF(ledBarBrightness);
|
2024-05-08 12:22:34 +07:00
|
|
|
JSON_PROP_DEF(displayBrightness);
|
|
|
|
JSON_PROP_DEF(co2CalibrationRequested);
|
|
|
|
JSON_PROP_DEF(ledBarTestRequested);
|
2024-05-09 14:32:42 +07:00
|
|
|
JSON_PROP_DEF(offlineMode);
|
2024-05-10 09:11:43 +07:00
|
|
|
|
|
|
|
#define jprop_model_default ""
|
|
|
|
#define jprop_country_default ""
|
|
|
|
#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
|
2024-05-13 21:28:37 +07:00
|
|
|
#define jprop_ledBarBrightness_default 100
|
2024-05-10 09:11:43 +07:00
|
|
|
#define jprop_displayBrightness_default 100
|
2024-05-12 10:49:13 +07:00
|
|
|
#define jprop_offlineMode_default false
|
2024-05-10 09:11:43 +07:00
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
JSONVar jconfig;
|
|
|
|
|
2024-04-11 09:29:29 +07:00
|
|
|
static bool jsonTypeInvalid(JSONVar root, String validType) {
|
|
|
|
String type = JSON.typeof_(root);
|
|
|
|
if (type == validType || type == "undefined" || type == "unknown" ||
|
|
|
|
type == "null") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get LedBarMode Name
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @param mode LedBarMode value
|
|
|
|
* @return String
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
String Configuration::getLedBarModeName(LedBarMode mode) {
|
2024-04-04 18:35:15 +07:00
|
|
|
if (mode == LedBarModeOff) {
|
|
|
|
return String(LED_BAR_MODE_NAMES[LedBarModeOff]);
|
|
|
|
} else if (mode == LedBarModePm) {
|
|
|
|
return String(LED_BAR_MODE_NAMES[LedBarModePm]);
|
|
|
|
} else if (mode == LedBarModeCO2) {
|
|
|
|
return String(LED_BAR_MODE_NAMES[LedBarModeCO2]);
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
return String("unknown");
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Save configure to device storage (EEPROM)
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void Configuration::saveConfig(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String data = toString();
|
|
|
|
int len = data.length();
|
2024-04-04 18:35:15 +07:00
|
|
|
#ifdef ESP8266
|
2024-05-08 12:22:34 +07:00
|
|
|
for (int i = 0; i < len; i++) {
|
2024-04-04 18:35:15 +07:00
|
|
|
EEPROM.write(i, data[i]);
|
|
|
|
}
|
2024-04-30 20:51:08 +07:00
|
|
|
EEPROM.commit();
|
2024-04-04 18:35:15 +07:00
|
|
|
#else
|
2024-04-30 20:51:08 +07:00
|
|
|
File file = SPIFFS.open(CONFIG_FILE_NAME, "w", true);
|
|
|
|
if (file && !file.isDirectory()) {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (file.write((const uint8_t *)data.c_str(), len) != len) {
|
2024-04-30 20:51:08 +07:00
|
|
|
logError("Write SPIFFS file failed");
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
} else {
|
|
|
|
logError("Open SPIFFS file to write failed");
|
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
#endif
|
2024-04-03 21:26:04 +07:00
|
|
|
logInfo("Save Config");
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
void Configuration::loadConfig(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
char *buf = (char *)malloc(EEPROM_CONFIG_SIZE);
|
|
|
|
if (buf == NULL) {
|
|
|
|
logError("Malloc read file buffer failed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memset(buf, 0, EEPROM_CONFIG_SIZE);
|
2024-04-04 18:35:15 +07:00
|
|
|
#ifdef ESP8266
|
2024-05-08 12:22:34 +07:00
|
|
|
for (int i = 0; i < EEPROM_CONFIG_SIZE; i++) {
|
|
|
|
buf[i] = EEPROM.read(i);
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
|
|
|
#else
|
2024-04-30 20:51:08 +07:00
|
|
|
File file = SPIFFS.open(CONFIG_FILE_NAME);
|
|
|
|
if (file && !file.isDirectory()) {
|
2024-05-10 09:11:43 +07:00
|
|
|
logInfo("Reading file...");
|
|
|
|
if(file.readBytes(buf, file.size()) != file.size()) {
|
|
|
|
logError("Reading file: failed - size not match");
|
|
|
|
} else {
|
|
|
|
logInfo("Reading file: success");
|
|
|
|
}
|
2024-04-30 20:51:08 +07:00
|
|
|
file.close();
|
2024-04-03 07:04:55 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
SPIFFS.format();
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
#endif
|
|
|
|
toConfig(buf);
|
|
|
|
free(buf);
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-04-05 06:39:59 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set configuration default
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void Configuration::defaultConfig(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
jconfig = JSON.parse("{}");
|
|
|
|
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_country] = jprop_country_default;
|
|
|
|
jconfig[jprop_mqttBrokerUrl] = jprop_mqttBrokerUrl_default;
|
|
|
|
jconfig[jprop_configurationControl] = jprop_configurationControl_default;
|
|
|
|
jconfig[jprop_pmStandard] = jprop_pmStandard_default;
|
|
|
|
jconfig[jprop_temperatureUnit] = jprop_temperatureUnit_default;
|
|
|
|
jconfig[jprop_postDataToAirGradient] = jprop_postDataToAirGradient_default;
|
2024-05-13 21:28:37 +07:00
|
|
|
jconfig[jprop_ledBarBrightness] = jprop_ledBarBrightness_default;
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_displayBrightness] = jprop_displayBrightness_default;
|
2024-05-13 21:28:37 +07:00
|
|
|
jconfig[jprop_ledBarMode] = jprop_ledBarBrightness_default;
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_tvocLearningOffset] = jprop_tvocLearningOffset_default;
|
|
|
|
jconfig[jprop_noxLearningOffset] = jprop_noxLearningOffset_default;
|
|
|
|
jconfig[jprop_abcDays] = jprop_abcDays_default;
|
|
|
|
jconfig[jprop_model] = jprop_model_default;
|
2024-05-12 10:49:13 +07:00
|
|
|
jconfig[jprop_offlineMode] = jprop_offlineMode_default;
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
saveConfig();
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Show configuration as JSON string message over log
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
void Configuration::printConfig(void) {
|
|
|
|
String cfg = toString();
|
|
|
|
logInfo(cfg);
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Construct a new Ag Configure:: Ag Configure object
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @param debugLog Serial Stream
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
Configuration::Configuration(Stream &debugLog)
|
|
|
|
: PrintLog(debugLog, "Configure") {}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Destroy the Ag Configure:: Ag Configure object
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
Configuration::~Configuration() {}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Initialize configuration
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return true Success
|
|
|
|
* @return false Failure
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::begin(void) {
|
2024-04-30 20:51:08 +07:00
|
|
|
#ifdef ESP32
|
|
|
|
if (!SPIFFS.begin(true)) {
|
|
|
|
logError("Init SPIFFS failed");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
EEPROM.begin(EEPROM_CONFIG_SIZE);
|
|
|
|
#endif
|
|
|
|
|
2024-04-03 07:04:55 +07:00
|
|
|
loadConfig();
|
|
|
|
printConfig();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Parse JSON configura string to local configure
|
|
|
|
*
|
|
|
|
* @param data JSON string data
|
|
|
|
* @param isLocal true of data got from local, otherwise get from Aigradient
|
|
|
|
* server
|
|
|
|
* @return true Success
|
|
|
|
* @return false Failure
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::parse(String data, bool isLocal) {
|
2024-04-22 06:27:57 +07:00
|
|
|
logInfo("Parse configure: " + data);
|
|
|
|
|
2024-04-03 07:04:55 +07:00
|
|
|
JSONVar root = JSON.parse(data);
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "";
|
2024-05-08 12:22:34 +07:00
|
|
|
if (root == undefined) {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "JSON invalid";
|
|
|
|
logError(failedMessage);
|
2024-04-03 07:04:55 +07:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 21:26:04 +07:00
|
|
|
logInfo("Parse configure success");
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
/** Is configuration changed */
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
/** Get ConfigurationControl */
|
2024-05-08 12:22:34 +07:00
|
|
|
String lasCtrl = jconfig[jprop_configurationControl];
|
2024-04-04 18:35:15 +07:00
|
|
|
if (isLocal) {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_configurationControl]) == "string") {
|
|
|
|
String ctrl = root[jprop_configurationControl];
|
|
|
|
if (ctrl ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlBoth]) ||
|
|
|
|
ctrl ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlLocal]) ||
|
|
|
|
ctrl ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlCloud])) {
|
|
|
|
if (ctrl != lasCtrl) {
|
|
|
|
jconfig[jprop_configurationControl] = ctrl;
|
2024-04-22 16:32:17 +07:00
|
|
|
changed = true;
|
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
} else {
|
|
|
|
failedMessage =
|
|
|
|
jsonValueInvalidMessage(String(jprop_configurationControl), ctrl);
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_configurationControl], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(
|
|
|
|
String(jprop_configurationControl), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
if (changed) {
|
|
|
|
changed = false;
|
|
|
|
saveConfig();
|
2024-05-08 12:22:34 +07:00
|
|
|
configLogInfo(String(jprop_configurationControl), lasCtrl,
|
|
|
|
jconfig[jprop_configurationControl]);
|
2024-04-22 16:32:17 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jconfig[jprop_configurationControl] ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlCloud])) {
|
2024-05-15 17:15:36 +07:00
|
|
|
failedMessage = "Monitor set to accept only configuration from the "
|
|
|
|
"cloud. Use property configurationControl to change.";
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
2024-04-04 18:35:15 +07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jconfig[jprop_configurationControl] ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlLocal])) {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "Cloud configure ignored";
|
|
|
|
jsonInvalid();
|
2024-04-04 18:35:15 +07:00
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-08 10:15:45 +07:00
|
|
|
char temperatureUnit = 0;
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_country]) == "string") {
|
|
|
|
String country = root[jprop_country];
|
2024-04-03 07:04:55 +07:00
|
|
|
if (country.length() == 2) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String oldCountry = jconfig[jprop_country];
|
|
|
|
if (country != oldCountry) {
|
2024-04-03 07:04:55 +07:00
|
|
|
changed = true;
|
2024-05-08 12:22:34 +07:00
|
|
|
configLogInfo(String(jprop_country), oldCountry, country);
|
|
|
|
jconfig[jprop_country] = country;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "Country name " + country +
|
|
|
|
" invalid. Find details here (ALPHA-2): "
|
|
|
|
"https://www.iban.com/country-codes";
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_country], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(String(jprop_country), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_pmStandard]) == "string") {
|
|
|
|
String standard = root[jprop_pmStandard];
|
|
|
|
if (standard == getPMStandardString(true) ||
|
|
|
|
standard == getPMStandardString(false)) {
|
|
|
|
String oldStandard = jconfig[jprop_pmStandard];
|
|
|
|
if (standard != oldStandard) {
|
|
|
|
configLogInfo(String(jprop_pmStandard), oldStandard, standard);
|
|
|
|
jconfig[jprop_pmStandard] = standard;
|
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
failedMessage =
|
|
|
|
jsonValueInvalidMessage(String(jprop_pmStandard), standard);
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_pmStandard], "string")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_pmStandard), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_co2CalibrationRequested]) == "boolean") {
|
|
|
|
co2CalibrationRequested = root[jprop_co2CalibrationRequested];
|
2024-04-30 20:51:08 +07:00
|
|
|
if (co2CalibrationRequested) {
|
2024-05-08 12:22:34 +07:00
|
|
|
logInfo(String(jprop_co2CalibrationRequested) + String(": ") +
|
2024-04-22 16:32:17 +07:00
|
|
|
String(co2CalibrationRequested ? "True" : "False"));
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_co2CalibrationRequested], "boolean")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(
|
|
|
|
String(jprop_co2CalibrationRequested), "boolean");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_ledBarTestRequested]) == "boolean") {
|
|
|
|
ledBarTestRequested = root[jprop_ledBarTestRequested];
|
2024-04-30 20:51:08 +07:00
|
|
|
if (ledBarTestRequested) {
|
2024-05-08 12:22:34 +07:00
|
|
|
logInfo(String(jprop_ledBarTestRequested) + String(": ") +
|
2024-04-22 16:32:17 +07:00
|
|
|
String(ledBarTestRequested ? "True" : "False"));
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_ledBarTestRequested], "boolean")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_ledBarTestRequested), "boolean");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_ledBarMode]) == "string") {
|
|
|
|
String mode = root[jprop_ledBarMode];
|
|
|
|
if (mode == getLedBarModeName(LedBarMode::LedBarModeCO2) ||
|
|
|
|
mode == getLedBarModeName(LedBarMode::LedBarModeOff) ||
|
|
|
|
mode == getLedBarModeName(LedBarMode::LedBarModePm)) {
|
|
|
|
String oldMode = jconfig[jprop_ledBarMode];
|
|
|
|
if (mode != oldMode) {
|
|
|
|
jconfig[jprop_ledBarMode] = mode;
|
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
failedMessage = jsonValueInvalidMessage(String(jprop_ledBarMode), mode);
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_ledBarMode], "string")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_ledBarMode), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_abcDays]) == "number") {
|
|
|
|
int value = root[jprop_abcDays];
|
|
|
|
if (value <= 0) {
|
|
|
|
value = 0;
|
2024-04-08 10:15:45 +07:00
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
int oldValue = jconfig[jprop_abcDays];
|
|
|
|
if (value != oldValue) {
|
|
|
|
logInfo(String("Set ") + String(jprop_abcDays) + String(": ") +
|
|
|
|
String(value));
|
|
|
|
configLogInfo(String(jprop_abcDays), getAbcDayString(oldValue),
|
|
|
|
String(getAbcDayString(value)));
|
|
|
|
|
|
|
|
jconfig[jprop_abcDays] = value;
|
2024-04-03 07:04:55 +07:00
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_abcDays], "number")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(String(jprop_abcDays), "number");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
_tvocLearningOffsetChanged = false;
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_tvocLearningOffset]) == "number") {
|
|
|
|
int value = root[jprop_tvocLearningOffset];
|
|
|
|
int oldValue = jconfig[jprop_tvocLearningOffset];
|
|
|
|
if (value < 0) {
|
|
|
|
jsonValueInvalidMessage(String(jprop_tvocLearningOffset), String(value));
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-05-08 12:22:34 +07:00
|
|
|
} else {
|
|
|
|
if (value != oldValue) {
|
|
|
|
changed = true;
|
|
|
|
_tvocLearningOffsetChanged = true;
|
|
|
|
configLogInfo(String(jprop_tvocLearningOffset), String(oldValue),
|
|
|
|
String(value));
|
|
|
|
jconfig[jprop_tvocLearningOffset] = value;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_tvocLearningOffset], "number")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_tvocLearningOffset), "number");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
_noxLearnOffsetChanged = false;
|
|
|
|
if (JSON.typeof_(root[jprop_noxLearningOffset]) == "number") {
|
|
|
|
int value = root[jprop_noxLearningOffset];
|
|
|
|
int oldValue = jconfig[jprop_noxLearningOffset];
|
|
|
|
if (value > 0) {
|
|
|
|
if (value != oldValue) {
|
2024-04-03 07:04:55 +07:00
|
|
|
changed = true;
|
2024-05-08 12:22:34 +07:00
|
|
|
_noxLearnOffsetChanged = true;
|
|
|
|
configLogInfo(String(jprop_noxLearningOffset), String(oldValue),
|
|
|
|
String(value));
|
|
|
|
jconfig[jprop_noxLearningOffset] = value;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
failedMessage = jsonValueInvalidMessage(String(jprop_noxLearningOffset),
|
|
|
|
String(value));
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root[jprop_noxLearningOffset], "number")) {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage =
|
2024-05-08 12:22:34 +07:00
|
|
|
jsonTypeInvalidMessage(String(jprop_noxLearningOffset), "number");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root[jprop_mqttBrokerUrl]) == "string") {
|
|
|
|
String broker = root[jprop_mqttBrokerUrl];
|
|
|
|
String oldBroker = jconfig[jprop_mqttBrokerUrl];
|
2024-05-13 17:43:42 +07:00
|
|
|
if (broker.length() <= 255) {
|
|
|
|
if (broker != oldBroker) {
|
|
|
|
changed = true;
|
|
|
|
configLogInfo(String(jprop_mqttBrokerUrl), oldBroker, broker);
|
|
|
|
jconfig[jprop_mqttBrokerUrl] = broker;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
failedMessage = "\"mqttBrokerUrl\" length should <= 255";
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-05-08 12:22:34 +07:00
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_mqttBrokerUrl], "string")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_mqttBrokerUrl), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_temperatureUnit]) == "string") {
|
|
|
|
String unit = root[jprop_temperatureUnit];
|
|
|
|
String oldUnit = jconfig[jprop_temperatureUnit];
|
2024-04-08 10:15:45 +07:00
|
|
|
unit.toLowerCase();
|
2024-05-08 12:22:34 +07:00
|
|
|
if (unit == "c" || unit == "f") {
|
|
|
|
if (unit != oldUnit) {
|
|
|
|
changed = true;
|
|
|
|
jconfig[jprop_temperatureUnit] = unit;
|
|
|
|
configLogInfo(String(jprop_temperatureUnit), oldUnit, unit);
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
} else {
|
2024-05-13 17:43:42 +07:00
|
|
|
failedMessage = jsonValueInvalidMessage(String(jprop_temperatureUnit), unit);
|
2024-05-08 12:22:34 +07:00
|
|
|
jsonInvalid();
|
2024-04-08 10:15:45 +07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_temperatureUnit], "string")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_temperatureUnit), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 06:27:57 +07:00
|
|
|
if (isLocal) {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_postDataToAirGradient]) == "boolean") {
|
|
|
|
bool value = root[jprop_postDataToAirGradient];
|
|
|
|
bool oldValue = jconfig[jprop_postDataToAirGradient];
|
|
|
|
if (value != oldValue) {
|
2024-04-22 06:27:57 +07:00
|
|
|
changed = true;
|
2024-05-08 12:22:34 +07:00
|
|
|
configLogInfo(String(jprop_postDataToAirGradient),
|
|
|
|
String(oldValue ? "true" : "false"),
|
|
|
|
String(value ? "true" : "false"));
|
|
|
|
jconfig[jprop_postDataToAirGradient] = value;
|
2024-04-22 06:27:57 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_postDataToAirGradient], "boolean")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(
|
|
|
|
String(jprop_postDataToAirGradient), "boolean");
|
2024-04-22 06:27:57 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse data only got from AirGradient server */
|
|
|
|
if (isLocal == false) {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_model]) == "string") {
|
|
|
|
String model = root[jprop_model];
|
|
|
|
String oldModel = jconfig[jprop_model];
|
|
|
|
if (model != oldModel) {
|
|
|
|
changed = true;
|
|
|
|
configLogInfo(String(jprop_model), oldModel, model);
|
|
|
|
jconfig[jprop_model] = model;
|
2024-04-08 10:15:45 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_model], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage(String(jprop_model), "string");
|
2024-04-08 10:15:45 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-13 21:28:37 +07:00
|
|
|
if (JSON.typeof_(root[jprop_ledBarBrightness]) == "number") {
|
|
|
|
int value = root[jprop_ledBarBrightness];
|
|
|
|
int oldValue = jconfig[jprop_ledBarBrightness];
|
2024-05-08 12:22:34 +07:00
|
|
|
if (value >= 0 && value <= 100) {
|
|
|
|
if (value != oldValue) {
|
2024-05-01 21:25:35 +07:00
|
|
|
changed = true;
|
2024-05-13 21:28:37 +07:00
|
|
|
configLogInfo(String(jprop_ledBarBrightness), String(oldValue),
|
2024-05-08 12:22:34 +07:00
|
|
|
String(value));
|
2024-05-01 21:25:35 +07:00
|
|
|
ledBarBrightnessChanged = true;
|
2024-05-13 21:28:37 +07:00
|
|
|
jconfig[jprop_ledBarBrightness] = value;
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
} else {
|
2024-05-13 21:28:37 +07:00
|
|
|
failedMessage = jsonValueInvalidMessage(String(jprop_ledBarBrightness),
|
2024-05-08 12:22:34 +07:00
|
|
|
String(value));
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-13 21:28:37 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_ledBarBrightness], "number")) {
|
2024-05-08 12:22:34 +07:00
|
|
|
failedMessage =
|
2024-05-13 21:28:37 +07:00
|
|
|
jsonTypeInvalidMessage(String(jprop_ledBarBrightness), "number");
|
2024-05-01 21:25:35 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (JSON.typeof_(root[jprop_displayBrightness]) == "number") {
|
|
|
|
int value = root[jprop_displayBrightness];
|
|
|
|
int oldValue = jconfig[jprop_displayBrightness];
|
|
|
|
if (value >= 0 && value <= 100) {
|
|
|
|
if (value != oldValue) {
|
2024-05-01 21:25:35 +07:00
|
|
|
changed = true;
|
|
|
|
displayBrightnessChanged = true;
|
2024-05-08 12:22:34 +07:00
|
|
|
configLogInfo(String(jprop_displayBrightness), String(oldValue),
|
|
|
|
String(value));
|
|
|
|
jconfig[jprop_displayBrightness] = value;
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
2024-05-08 12:22:34 +07:00
|
|
|
} else {
|
|
|
|
failedMessage = jsonValueInvalidMessage(String(jprop_displayBrightness),
|
|
|
|
String(value));
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
|
|
|
} else {
|
2024-05-08 12:22:34 +07:00
|
|
|
if (jsonTypeInvalid(root[jprop_displayBrightness], "number")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage(String(jprop_displayBrightness), "number");
|
2024-05-01 21:25:35 +07:00
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-02 10:19:49 +07:00
|
|
|
if (JSON.typeof_(root["targetFirmware"]) == "string") {
|
|
|
|
String newVer = root["targetFirmware"];
|
|
|
|
String curVer = String(GIT_VERSION);
|
|
|
|
if (curVer != newVer) {
|
2024-05-15 17:20:10 +07:00
|
|
|
logInfo("Detected new firmware version: " + newVer);
|
2024-05-02 10:19:49 +07:00
|
|
|
otaNewFirmwareVersion = newVer;
|
|
|
|
udpated = true;
|
|
|
|
} else {
|
|
|
|
otaNewFirmwareVersion = String("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-03 07:04:55 +07:00
|
|
|
if (changed) {
|
2024-04-14 21:30:56 +07:00
|
|
|
udpated = true;
|
2024-04-03 07:04:55 +07:00
|
|
|
saveConfig();
|
2024-04-22 16:32:17 +07:00
|
|
|
printConfig();
|
2024-04-22 06:27:57 +07:00
|
|
|
} else {
|
|
|
|
if (ledBarTestRequested || co2CalibrationRequested) {
|
|
|
|
udpated = true;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get current configuration value as JSON string
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return String
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
String Configuration::toString(void) { return JSON.stringify(jconfig); }
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-05-13 18:11:46 +07:00
|
|
|
/**
|
|
|
|
* @brief Get current configuration value as JSON string
|
|
|
|
*
|
|
|
|
* @param fwMode Firmware mode value
|
|
|
|
* @return String
|
|
|
|
*/
|
|
|
|
String Configuration::toString(AgFirmwareMode fwMode) {
|
|
|
|
String model = jconfig[jprop_model];
|
|
|
|
jconfig[jprop_model] = AgFirmwareModeName(fwMode);
|
|
|
|
String value = toString();
|
|
|
|
jconfig[jprop_model] = model;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Temperature unit (F or C)
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return true F
|
|
|
|
* @return false C
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::isTemperatureUnitInF(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String unit = jconfig[jprop_temperatureUnit];
|
|
|
|
return (unit == "f");
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Country name, it's short name ex: TH = Thailand
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return String
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
String Configuration::getCountry(void) {
|
|
|
|
String country = jconfig[jprop_country];
|
|
|
|
return country;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief PM unit standard (USAQI, ugm3)
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return true USAQI
|
|
|
|
* @return false ugm3
|
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
bool Configuration::isPmStandardInUSAQI(void) {
|
|
|
|
String standard = jconfig[jprop_pmStandard];
|
|
|
|
return (standard == getPMStandardString(true));
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get CO2 calibration ABC time
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return int Number of day
|
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
int Configuration::getCO2CalibrationAbcDays(void) {
|
|
|
|
int value = jconfig[jprop_abcDays];
|
|
|
|
return value;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get Led Bar Mode
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return LedBarMode
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
LedBarMode Configuration::getLedBarMode(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String mode = jconfig[jprop_ledBarMode];
|
|
|
|
if (mode == getLedBarModeName(LedBarModeCO2)) {
|
|
|
|
return LedBarModeCO2;
|
|
|
|
}
|
|
|
|
if (mode == getLedBarModeName(LedBarModeOff)) {
|
|
|
|
return LedBarModeOff;
|
|
|
|
}
|
|
|
|
if (mode == getLedBarModeName(LedBarModePm)) {
|
|
|
|
return LedBarModePm;
|
|
|
|
}
|
|
|
|
return LedBarModeOff;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get LED bar mode name
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return String
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
String Configuration::getLedBarModeName(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String mode = jconfig[jprop_ledBarMode];
|
|
|
|
return mode;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get MQTT uri
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return String
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
String Configuration::getMqttBrokerUri(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String broker = jconfig[jprop_mqttBrokerUrl];
|
|
|
|
return broker;
|
2024-04-07 16:39:01 +07:00
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get configuratoin post data to AirGradient cloud
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return true Post
|
|
|
|
* @return false No-Post
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::isPostDataToAirGradient(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
bool post = jconfig[jprop_postDataToAirGradient];
|
|
|
|
return post;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get current configuration control
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
|
|
|
* @return ConfigurationControl
|
2024-04-05 06:39:59 +07:00
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
ConfigurationControl Configuration::getConfigurationControl(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
String ctrl = jconfig[jprop_configurationControl];
|
|
|
|
if (ctrl == String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlBoth])) {
|
|
|
|
return ConfigurationControl::ConfigurationControlBoth;
|
|
|
|
}
|
|
|
|
if (ctrl == String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlLocal])) {
|
|
|
|
return ConfigurationControl::ConfigurationControlLocal;
|
|
|
|
}
|
|
|
|
if (ctrl == String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlCloud])) {
|
|
|
|
return ConfigurationControl::ConfigurationControlCloud;
|
|
|
|
}
|
|
|
|
return ConfigurationControl::ConfigurationControlBoth;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief CO2 manual calib request, the request flag will clear after get. Must
|
|
|
|
* call this after parse success
|
|
|
|
*
|
|
|
|
* @return true Requested
|
|
|
|
* @return false Not requested
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::isCo2CalibrationRequested(void) {
|
2024-04-03 07:04:55 +07:00
|
|
|
bool requested = co2CalibrationRequested;
|
|
|
|
co2CalibrationRequested = false; // clear requested
|
|
|
|
return requested;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief LED bar test request, the request flag will clear after get. Must call
|
|
|
|
* this function after parse success
|
|
|
|
*
|
|
|
|
* @return true Requested
|
|
|
|
* @return false Not requested
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::isLedBarTestRequested(void) {
|
2024-04-03 07:04:55 +07:00
|
|
|
bool requested = ledBarTestRequested;
|
|
|
|
ledBarTestRequested = false;
|
|
|
|
return requested;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Reset default configure
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
void Configuration::reset(void) {
|
2024-04-03 07:04:55 +07:00
|
|
|
defaultConfig();
|
2024-04-03 21:26:04 +07:00
|
|
|
logInfo("Reset to default configure");
|
2024-04-03 07:04:55 +07:00
|
|
|
printConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get model name, it's usage for offline mode
|
|
|
|
*
|
|
|
|
* @return String
|
|
|
|
*/
|
2024-05-08 12:22:34 +07:00
|
|
|
String Configuration::getModel(void) {
|
|
|
|
String model = jconfig[jprop_model];
|
|
|
|
return model;
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
|
|
|
|
bool Configuration::isUpdated(void) {
|
|
|
|
bool updated = this->udpated;
|
|
|
|
this->udpated = false;
|
|
|
|
return updated;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
|
|
|
|
String Configuration::jsonTypeInvalidMessage(String name, String type) {
|
|
|
|
return "'" + name + "' type invalid, it's should '" + type + "'";
|
|
|
|
}
|
|
|
|
|
|
|
|
String Configuration::jsonValueInvalidMessage(String name, String value) {
|
|
|
|
return "'" + name + "' value '" + value + "' invalid";
|
|
|
|
}
|
|
|
|
|
|
|
|
void Configuration::jsonInvalid(void) {
|
|
|
|
loadConfig();
|
|
|
|
logError(failedMessage);
|
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
void Configuration::configLogInfo(String name, String fromValue,
|
|
|
|
String toValue) {
|
|
|
|
logInfo(String("Setting '") + name + String("' from '") + fromValue +
|
|
|
|
String("' to '") + toValue + String("'"));
|
|
|
|
}
|
|
|
|
|
|
|
|
String Configuration::getPMStandardString(bool usaqi) {
|
|
|
|
if (usaqi) {
|
|
|
|
return "us-aqi";
|
|
|
|
}
|
|
|
|
return "ugm3";
|
|
|
|
}
|
|
|
|
|
2024-04-30 20:51:08 +07:00
|
|
|
String Configuration::getAbcDayString(int value) {
|
|
|
|
if (value <= 0) {
|
2024-04-22 16:32:17 +07:00
|
|
|
return String("off");
|
|
|
|
}
|
|
|
|
return String(value);
|
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
void Configuration::toConfig(const char *buf) {
|
|
|
|
logInfo("Parse file to JSON");
|
|
|
|
JSONVar root = JSON.parse(buf);
|
|
|
|
if (!(root == undefined)) {
|
|
|
|
jconfig = root;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool changed = false;
|
|
|
|
bool isInvalid = false;
|
|
|
|
|
|
|
|
/** Validate country */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_country]) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
String country = jconfig[jprop_country];
|
|
|
|
if (country.length() != 2) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_country] = jprop_country_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: country changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate: PM standard */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_pmStandard]) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
String standard = jconfig[jprop_pmStandard];
|
|
|
|
if (standard != getPMStandardString(true) &&
|
|
|
|
standard != getPMStandardString(false)) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_pmStandard] = jprop_pmStandard_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: pmStandard changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate led bar mode */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_ledBarMode]) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
String mode = jconfig[jprop_ledBarMode];
|
|
|
|
if (mode != getLedBarModeName(LedBarMode::LedBarModeCO2) &&
|
|
|
|
mode != getLedBarModeName(LedBarMode::LedBarModeOff) &&
|
|
|
|
mode != getLedBarModeName(LedBarMode::LedBarModePm)) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_ledBarMode] = jprop_ledBarMode_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: ledBarMode changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate abcday */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_abcDays]) != "number") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_abcDays] = jprop_abcDays_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: abcDays changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate tvoc learning offset */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_tvocLearningOffset]) != "number") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
int value = jconfig[jprop_tvocLearningOffset];
|
|
|
|
if (value < 0) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_tvocLearningOffset] = jprop_tvocLearningOffset_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: tvocLearningOffset changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate nox learning offset */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_noxLearningOffset]) != "number") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
int value = jconfig[jprop_noxLearningOffset];
|
|
|
|
if (value < 0) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_noxLearningOffset] = jprop_noxLearningOffset_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: noxLearningOffset changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate mqtt broker */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_mqttBrokerUrl]) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
|
|
|
changed = true;
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_mqttBrokerUrl] = jprop_mqttBrokerUrl_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
logInfo("toConfig: mqttBroker changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Validate temperature unit */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_temperatureUnit]) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
String unit = jconfig[jprop_temperatureUnit];
|
|
|
|
if (unit != "c" && unit != "f") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_temperatureUnit] = jprop_temperatureUnit_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: temperatureUnit changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate configuration control */
|
|
|
|
if (JSON.typeof_(jprop_configurationControl) != "string") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
String ctrl = jconfig[jprop_configurationControl];
|
|
|
|
if (ctrl != String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlBoth]) &&
|
|
|
|
ctrl != String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlLocal]) &&
|
|
|
|
ctrl != String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlCloud])) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_configurationControl] =jprop_configurationControl_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: configurationControl changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Validate post to airgradient cloud */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_postDataToAirGradient]) != "boolean") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_postDataToAirGradient] = jprop_postDataToAirGradient_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: postToAirGradient changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** validate led bar brightness */
|
2024-05-13 21:28:37 +07:00
|
|
|
if (JSON.typeof_(jconfig[jprop_ledBarBrightness]) != "number") {
|
2024-05-08 12:22:34 +07:00
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
2024-05-13 21:28:37 +07:00
|
|
|
int value = jconfig[jprop_ledBarBrightness];
|
2024-05-08 12:22:34 +07:00
|
|
|
if (value < 0 || value > 100) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-13 21:28:37 +07:00
|
|
|
jconfig[jprop_ledBarBrightness] = jprop_ledBarBrightness_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: ledBarBrightness changed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Validate display brightness */
|
|
|
|
if (JSON.typeof_(jconfig[jprop_displayBrightness]) != "number") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
int value = jconfig[jprop_displayBrightness];
|
|
|
|
if (value < 0 || value > 100) {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
2024-05-10 09:11:43 +07:00
|
|
|
jconfig[jprop_displayBrightness] = jprop_displayBrightness_default;
|
2024-05-08 12:22:34 +07:00
|
|
|
changed = true;
|
|
|
|
logInfo("toConfig: displayBrightness changed");
|
|
|
|
}
|
|
|
|
|
2024-05-09 14:32:42 +07:00
|
|
|
if (JSON.typeof_(jconfig[jprop_offlineMode]) != "boolean") {
|
|
|
|
isInvalid = true;
|
|
|
|
} else {
|
|
|
|
isInvalid = false;
|
|
|
|
}
|
|
|
|
if (isInvalid) {
|
|
|
|
jconfig[jprop_offlineMode] = false;
|
|
|
|
}
|
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
if (changed) {
|
|
|
|
saveConfig();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-08 10:15:45 +07:00
|
|
|
String Configuration::getFailedMesage(void) { return failedMessage; }
|
2024-04-11 06:33:56 +07:00
|
|
|
|
|
|
|
void Configuration::setPostToAirGradient(bool enable) {
|
2024-05-08 12:22:34 +07:00
|
|
|
bool oldEnabled = jconfig[jprop_postDataToAirGradient];
|
|
|
|
if (enable != oldEnabled) {
|
|
|
|
jconfig[jprop_postDataToAirGradient] = enable;
|
2024-04-11 06:33:56 +07:00
|
|
|
logInfo("postDataToAirGradient set to: " + String(enable));
|
|
|
|
saveConfig();
|
|
|
|
} else {
|
|
|
|
logInfo("postDataToAirGradient: Ignored set to " + String(enable));
|
|
|
|
}
|
|
|
|
}
|
2024-04-14 21:30:56 +07:00
|
|
|
|
|
|
|
bool Configuration::noxLearnOffsetChanged(void) {
|
|
|
|
bool changed = _noxLearnOffsetChanged;
|
|
|
|
_noxLearnOffsetChanged = false;
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Configuration::tvocLearnOffsetChanged(void) {
|
|
|
|
bool changed = _tvocLearningOffsetChanged;
|
|
|
|
_tvocLearningOffsetChanged = false;
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Configuration::getTvocLearningOffset(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
int value = jconfig[jprop_tvocLearningOffset];
|
|
|
|
return value;
|
2024-04-14 21:30:56 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int Configuration::getNoxLearningOffset(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
int value = jconfig[jprop_noxLearningOffset];
|
|
|
|
return value;
|
2024-04-14 21:30:56 +07:00
|
|
|
}
|
2024-04-25 06:49:14 +07:00
|
|
|
|
2024-04-30 20:51:08 +07:00
|
|
|
String Configuration::wifiSSID(void) { return "airgradient-" + ag->deviceId(); }
|
2024-04-25 06:49:14 +07:00
|
|
|
|
|
|
|
String Configuration::wifiPass(void) { return String("cleanair"); }
|
|
|
|
|
2024-04-30 20:51:08 +07:00
|
|
|
void Configuration::setAirGradient(AirGradient *ag) { this->ag = ag; }
|
2024-05-01 21:25:35 +07:00
|
|
|
|
2024-05-08 12:22:34 +07:00
|
|
|
int Configuration::getLedBarBrightness(void) {
|
2024-05-13 21:28:37 +07:00
|
|
|
int value = jconfig[jprop_ledBarBrightness];
|
2024-05-08 12:22:34 +07:00
|
|
|
return value;
|
|
|
|
}
|
2024-05-01 21:25:35 +07:00
|
|
|
|
|
|
|
bool Configuration::isLedBarBrightnessChanged(void) {
|
|
|
|
bool changed = ledBarBrightnessChanged;
|
|
|
|
ledBarBrightnessChanged = false;
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Configuration::getDisplayBrightness(void) {
|
2024-05-08 12:22:34 +07:00
|
|
|
int value = jconfig[jprop_displayBrightness];
|
|
|
|
return value;
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
|
|
|
|
2024-05-09 14:32:42 +07:00
|
|
|
bool Configuration::isOfflineMode(void) {
|
|
|
|
bool offline = jconfig[jprop_offlineMode];
|
2024-05-13 14:43:53 +07:00
|
|
|
return (offline || _offlineMode);
|
2024-05-09 14:32:42 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Configuration::setOfflineMode(bool offline) {
|
|
|
|
logInfo("Set offline mode: " + String(offline ? "True" : "False"));
|
|
|
|
jconfig[jprop_offlineMode] = offline;
|
|
|
|
saveConfig();
|
|
|
|
}
|
|
|
|
|
2024-05-13 14:43:53 +07:00
|
|
|
void Configuration::setOfflineModeWithoutSave(bool offline) {
|
|
|
|
_offlineMode = offline;
|
|
|
|
}
|
|
|
|
|
2024-05-01 21:25:35 +07:00
|
|
|
bool Configuration::isDisplayBrightnessChanged(void) {
|
|
|
|
bool changed = displayBrightnessChanged;
|
|
|
|
displayBrightnessChanged = false;
|
|
|
|
return changed;
|
|
|
|
}
|
2024-05-02 10:19:49 +07:00
|
|
|
|
|
|
|
String Configuration::newFirmwareVersion(void) {
|
|
|
|
String newFw = otaNewFirmwareVersion;
|
|
|
|
otaNewFirmwareVersion = String("");
|
|
|
|
return newFw;
|
|
|
|
}
|