2024-04-03 07:04:55 +07:00
|
|
|
#include "AgConfigure.h"
|
|
|
|
#include "EEPROM.h"
|
2024-04-11 09:29:29 +07:00
|
|
|
#include "Libraries/Arduino_JSON/src/Arduino_JSON.h"
|
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-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-04-03 07:04:55 +07:00
|
|
|
config._check = 0;
|
|
|
|
int len = sizeof(config) - sizeof(config._check);
|
|
|
|
uint8_t *data = (uint8_t *)&config;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
config._check += data[i];
|
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
#ifdef ESP8266
|
|
|
|
for (int i = 0; i < sizeof(config); i++) {
|
|
|
|
EEPROM.write(i, data[i]);
|
|
|
|
}
|
|
|
|
#else
|
2024-04-03 07:04:55 +07:00
|
|
|
EEPROM.writeBytes(0, &config, sizeof(config));
|
2024-04-04 18:35:15 +07:00
|
|
|
#endif
|
2024-04-03 07:04:55 +07:00
|
|
|
EEPROM.commit();
|
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-04-04 18:35:15 +07:00
|
|
|
bool readSuccess = false;
|
|
|
|
#ifdef ESP8266
|
|
|
|
uint8_t *data = (uint8_t *)&config;
|
|
|
|
for (int i = 0; i < sizeof(config); i++) {
|
|
|
|
data[i] = EEPROM.read(i);
|
|
|
|
}
|
|
|
|
readSuccess = true;
|
|
|
|
#else
|
2024-04-08 10:15:45 +07:00
|
|
|
if (EEPROM.readBytes(0, &config, sizeof(config)) == sizeof(config)) {
|
2024-04-04 18:35:15 +07:00
|
|
|
readSuccess = true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-08 10:15:45 +07:00
|
|
|
if (!readSuccess) {
|
2024-04-03 21:26:04 +07:00
|
|
|
logError("Load configure failed");
|
2024-04-03 07:04:55 +07:00
|
|
|
defaultConfig();
|
|
|
|
} else {
|
|
|
|
uint32_t sum = 0;
|
|
|
|
uint8_t *data = (uint8_t *)&config;
|
|
|
|
int len = sizeof(config) - sizeof(config._check);
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
sum += data[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sum != config._check) {
|
2024-04-03 21:26:04 +07:00
|
|
|
logError("Configure validate invalid");
|
2024-04-03 07:04:55 +07:00
|
|
|
defaultConfig();
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
2024-04-22 16:32:17 +07:00
|
|
|
/** Correct configuration parameter value. */
|
2024-04-08 10:15:45 +07:00
|
|
|
bool changed = false;
|
|
|
|
if ((config.temperatureUnit != 'c') && (config.temperatureUnit != 'f')) {
|
|
|
|
config.temperatureUnit = 'c';
|
|
|
|
changed = true;
|
|
|
|
logError("Temperture unit invalid, set default 'c'");
|
|
|
|
}
|
|
|
|
if ((config.useRGBLedBar != (uint8_t)LedBarModeCO2) &&
|
|
|
|
(config.useRGBLedBar != (uint8_t)LedBarModePm) &&
|
|
|
|
(config.useRGBLedBar != (uint8_t)LedBarModeOff)) {
|
|
|
|
config.useRGBLedBar = (uint8_t)LedBarModeCO2;
|
|
|
|
changed = true;
|
|
|
|
logError("LedBarMode invalid, set default: co2");
|
|
|
|
}
|
|
|
|
if (changed) {
|
|
|
|
saveConfig();
|
|
|
|
}
|
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-04-03 07:04:55 +07:00
|
|
|
// Default country is null
|
|
|
|
memset(config.country, 0, sizeof(config.country));
|
|
|
|
// Default MQTT broker is null.
|
|
|
|
memset(config.mqttBroker, 0, sizeof(config.mqttBroker));
|
|
|
|
|
|
|
|
config.configurationControl = ConfigurationControl::ConfigurationControlBoth;
|
|
|
|
config.inUSAQI = false; // pmStandard = ugm3
|
|
|
|
config.inF = false;
|
|
|
|
config.postDataToAirGradient = true;
|
|
|
|
config.displayMode = true;
|
|
|
|
config.useRGBLedBar = LedBarMode::LedBarModeCO2;
|
2024-04-21 16:44:43 +07:00
|
|
|
config.abcDays = 8;
|
2024-04-03 07:04:55 +07:00
|
|
|
config.tvocLearningOffset = 12;
|
|
|
|
config.noxLearningOffset = 12;
|
|
|
|
config.temperatureUnit = 'c';
|
|
|
|
|
|
|
|
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-04-07 16:39:01 +07:00
|
|
|
void Configuration::printConfig(void) { logInfo(toString().c_str()); }
|
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-03 07:04:55 +07:00
|
|
|
EEPROM.begin(512);
|
|
|
|
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-04-03 07:04:55 +07:00
|
|
|
if (JSON.typeof_(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-04-04 18:35:15 +07:00
|
|
|
if (isLocal) {
|
2024-04-22 16:32:17 +07:00
|
|
|
uint8_t configurationControl = config.configurationControl;
|
2024-04-04 18:35:15 +07:00
|
|
|
if (JSON.typeof_(root["configurationControl"]) == "string") {
|
|
|
|
String configurationControl = root["configurationControl"];
|
2024-04-22 16:32:17 +07:00
|
|
|
if (configurationControl !=
|
|
|
|
String(CONFIGURATION_CONTROL_NAME[config.configurationControl])) {
|
|
|
|
if (configurationControl ==
|
|
|
|
String(CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlLocal])) {
|
|
|
|
config.configurationControl =
|
|
|
|
(uint8_t)ConfigurationControl::ConfigurationControlLocal;
|
|
|
|
changed = true;
|
|
|
|
} else if (configurationControl ==
|
|
|
|
String(
|
|
|
|
CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlCloud])) {
|
|
|
|
config.configurationControl =
|
|
|
|
(uint8_t)ConfigurationControl::ConfigurationControlCloud;
|
|
|
|
changed = true;
|
|
|
|
} else if (configurationControl ==
|
|
|
|
String(
|
|
|
|
CONFIGURATION_CONTROL_NAME
|
|
|
|
[ConfigurationControl::ConfigurationControlBoth])) {
|
|
|
|
config.configurationControl =
|
|
|
|
(uint8_t)ConfigurationControl::ConfigurationControlBoth;
|
|
|
|
changed = true;
|
|
|
|
} else {
|
|
|
|
failedMessage = jsonValueInvalidMessage("configurationControl",
|
|
|
|
configurationControl);
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
if (jsonTypeInvalid(root["configurationControl"], "string")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage("configurationControl", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
if (changed) {
|
|
|
|
changed = false;
|
|
|
|
saveConfig();
|
|
|
|
configLogInfo(
|
|
|
|
"configurationControl",
|
|
|
|
String(CONFIGURATION_CONTROL_NAME[configurationControl]),
|
|
|
|
String(CONFIGURATION_CONTROL_NAME[config.configurationControl]));
|
|
|
|
}
|
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
if ((config.configurationControl ==
|
|
|
|
(byte)ConfigurationControl::ConfigurationControlCloud)) {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "Local configure ignored";
|
|
|
|
jsonInvalid();
|
2024-04-04 18:35:15 +07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (config.configurationControl ==
|
|
|
|
(byte)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-04-03 07:04:55 +07:00
|
|
|
if (JSON.typeof_(root["country"]) == "string") {
|
|
|
|
String country = root["country"];
|
|
|
|
if (country.length() == 2) {
|
|
|
|
if (country != String(config.country)) {
|
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("country", String(config.country), country);
|
2024-04-03 07:04:55 +07:00
|
|
|
snprintf(config.country, sizeof(config.country), country.c_str());
|
|
|
|
}
|
|
|
|
} 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 {
|
|
|
|
if (jsonTypeInvalid(root["country"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("country", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["pmStandard"]) == "string") {
|
|
|
|
String pmStandard = root["pmStandard"];
|
|
|
|
bool inUSAQI = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
if (pmStandard == getPMStandardString(false)) {
|
2024-04-03 07:04:55 +07:00
|
|
|
inUSAQI = false;
|
2024-04-22 16:32:17 +07:00
|
|
|
} else if (pmStandard == getPMStandardString(true)) {
|
2024-04-08 10:15:45 +07:00
|
|
|
inUSAQI = true;
|
|
|
|
} else {
|
|
|
|
failedMessage = jsonValueInvalidMessage("pmStandard", pmStandard);
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (inUSAQI != config.inUSAQI) {
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("pmStandard", getPMStandardString(config.inUSAQI), pmStandard);
|
2024-04-03 07:04:55 +07:00
|
|
|
config.inUSAQI = inUSAQI;
|
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["pmStandard"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("pmStandard", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["co2CalibrationRequested"]) == "boolean") {
|
|
|
|
co2CalibrationRequested = root["co2CalibrationRequested"];
|
2024-04-22 16:32:17 +07:00
|
|
|
if(co2CalibrationRequested) {
|
|
|
|
logInfo("co2CalibrationRequested: " +
|
|
|
|
String(co2CalibrationRequested ? "True" : "False"));
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["co2CalibrationRequested"], "boolean")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage("co2CalibrationRequested", "boolean");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["ledBarTestRequested"]) == "boolean") {
|
|
|
|
ledBarTestRequested = root["ledBarTestRequested"];
|
2024-04-22 16:32:17 +07:00
|
|
|
if(ledBarTestRequested){
|
|
|
|
logInfo("ledBarTestRequested: " +
|
|
|
|
String(ledBarTestRequested ? "True" : "False"));
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["ledBarTestRequested"], "boolean")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("ledBarTestRequested", "boolean");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["ledBarMode"]) == "string") {
|
|
|
|
String mode = root["ledBarMode"];
|
2024-04-04 18:35:15 +07:00
|
|
|
uint8_t ledBarMode = LedBarModeOff;
|
|
|
|
if (mode == String(LED_BAR_MODE_NAMES[LedBarModeCO2])) {
|
2024-04-03 07:04:55 +07:00
|
|
|
ledBarMode = LedBarModeCO2;
|
2024-04-04 18:35:15 +07:00
|
|
|
} else if (mode == String(LED_BAR_MODE_NAMES[LedBarModePm])) {
|
2024-04-03 07:04:55 +07:00
|
|
|
ledBarMode = LedBarModePm;
|
2024-04-04 18:35:15 +07:00
|
|
|
} else if (mode == String(LED_BAR_MODE_NAMES[LedBarModeOff])) {
|
2024-04-03 07:04:55 +07:00
|
|
|
ledBarMode = LedBarModeOff;
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = jsonValueInvalidMessage("ledBarMode", mode);
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ledBarMode != config.useRGBLedBar) {
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("useRGBLedBar",
|
|
|
|
String(LED_BAR_MODE_NAMES[config.useRGBLedBar]),
|
|
|
|
String(LED_BAR_MODE_NAMES[ledBarMode]));
|
2024-04-03 07:04:55 +07:00
|
|
|
config.useRGBLedBar = ledBarMode;
|
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["ledBarMode"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("ledBarMode", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["displayMode"]) == "string") {
|
|
|
|
String mode = root["displayMode"];
|
|
|
|
bool displayMode = false;
|
2024-04-22 16:32:17 +07:00
|
|
|
if (mode == getDisplayModeString(true)) {
|
2024-04-03 07:04:55 +07:00
|
|
|
displayMode = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
} else if (mode == getDisplayModeString(false)) {
|
2024-04-03 07:04:55 +07:00
|
|
|
displayMode = false;
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = jsonTypeInvalidMessage("displayMode", mode);
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (displayMode != config.displayMode) {
|
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("displayMode", getDisplayModeString(config.displayMode), mode);
|
2024-04-03 07:04:55 +07:00
|
|
|
config.displayMode = displayMode;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["displayMode"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("displayMode", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["abcDays"]) == "number") {
|
|
|
|
int abcDays = root["abcDays"];
|
2024-04-08 10:15:45 +07:00
|
|
|
if (abcDays <= 0) {
|
2024-04-21 16:44:43 +07:00
|
|
|
abcDays = 0;
|
2024-04-08 10:15:45 +07:00
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
if (abcDays != config.abcDays) {
|
2024-04-22 16:32:17 +07:00
|
|
|
logInfo("Set abcDays: " + String(abcDays));
|
|
|
|
configLogInfo("abcDays", getAbcDayString(config.abcDays),
|
|
|
|
String(getAbcDayString(abcDays)));
|
2024-04-03 07:04:55 +07:00
|
|
|
config.abcDays = abcDays;
|
|
|
|
changed = true;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["abcDays"], "number")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("abcDays", "number");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
_tvocLearningOffsetChanged = false;
|
2024-04-03 07:04:55 +07:00
|
|
|
if (JSON.typeof_(root["tvocLearningOffset"]) == "number") {
|
|
|
|
int tvocLearningOffset = root["tvocLearningOffset"];
|
|
|
|
if (tvocLearningOffset != config.tvocLearningOffset) {
|
|
|
|
changed = true;
|
2024-04-14 21:30:56 +07:00
|
|
|
_tvocLearningOffsetChanged = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("tvocLearningOffset", String(config.tvocLearningOffset),
|
|
|
|
String(tvocLearningOffset));
|
2024-04-03 07:04:55 +07:00
|
|
|
config.tvocLearningOffset = tvocLearningOffset;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["tvocLearningOffset"], "number")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("tvocLearningOffset", "number");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
2024-04-22 16:32:17 +07:00
|
|
|
_noxLearnOffsetChanged = false;
|
2024-04-03 07:04:55 +07:00
|
|
|
if (JSON.typeof_(root["noxLearningOffset"]) == "number") {
|
|
|
|
int noxLearningOffset = root["noxLearningOffset"];
|
|
|
|
if (noxLearningOffset != config.noxLearningOffset) {
|
|
|
|
changed = true;
|
2024-04-14 21:30:56 +07:00
|
|
|
_noxLearnOffsetChanged = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("noxLearningOffset", String(config.noxLearningOffset),
|
|
|
|
String(noxLearningOffset));
|
2024-04-03 07:04:55 +07:00
|
|
|
config.noxLearningOffset = noxLearningOffset;
|
|
|
|
}
|
2024-04-08 10:15:45 +07:00
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["noxLearningOffset"], "number")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("noxLearningOffset", "number");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") {
|
|
|
|
String broker = root["mqttBrokerUrl"];
|
|
|
|
if (broker.length() < sizeof(config.mqttBroker)) {
|
|
|
|
if (broker != String(config.mqttBroker)) {
|
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("mqttBrokerUrl", String(config.mqttBroker), broker);
|
2024-04-03 07:04:55 +07:00
|
|
|
snprintf(config.mqttBroker, sizeof(config.mqttBroker), broker.c_str());
|
|
|
|
}
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage =
|
|
|
|
"'mqttBroker' value length invalid: " + String(broker.length());
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["mqttBrokerUrl"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("mqttBrokerUrl", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.typeof_(root["temperatureUnit"]) == "string") {
|
|
|
|
String unit = root["temperatureUnit"];
|
2024-04-08 10:15:45 +07:00
|
|
|
unit.toLowerCase();
|
2024-04-22 16:32:17 +07:00
|
|
|
if ((unit == "c") || (unit == "celsius")) {
|
2024-04-03 07:04:55 +07:00
|
|
|
temperatureUnit = 'c';
|
2024-04-22 16:32:17 +07:00
|
|
|
} else if ((unit == "f") || (unit == "fahrenheit")) {
|
2024-04-03 07:04:55 +07:00
|
|
|
temperatureUnit = 'f';
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage = "'temperatureUnit' value '" + unit + "' invalid";
|
|
|
|
logError(failedMessage);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["temperatureUnit"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("temperatureUnit", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
2024-04-03 07:04:55 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-08 10:15:45 +07:00
|
|
|
if (temperatureUnit != 0 && temperatureUnit != config.temperatureUnit) {
|
2024-04-03 07:04:55 +07:00
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("temperatureUnit", String(config.temperatureUnit),
|
|
|
|
String(temperatureUnit));
|
2024-04-03 07:04:55 +07:00
|
|
|
config.temperatureUnit = temperatureUnit;
|
|
|
|
}
|
|
|
|
|
2024-04-22 06:27:57 +07:00
|
|
|
if (isLocal) {
|
|
|
|
if (JSON.typeof_(root["postDataToAirGradient"]) == "boolean") {
|
|
|
|
bool post = root["postDataToAirGradient"];
|
|
|
|
if (post != config.postDataToAirGradient) {
|
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("postDataToAirGradient",
|
|
|
|
String(config.postDataToAirGradient ? "true" : "false"),
|
|
|
|
String(post ? "true" : "false"));
|
2024-04-22 06:27:57 +07:00
|
|
|
config.postDataToAirGradient = post;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["postDataToAirGradient"], "boolean")) {
|
|
|
|
failedMessage =
|
|
|
|
jsonTypeInvalidMessage("postDataToAirGradient", "boolean");
|
|
|
|
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) {
|
|
|
|
if (JSON.typeof_(root["model"]) == "string") {
|
|
|
|
String model = root["model"];
|
|
|
|
if (model.length() < sizeof(config.model)) {
|
|
|
|
if (model != String(config.model)) {
|
|
|
|
changed = true;
|
2024-04-22 16:32:17 +07:00
|
|
|
configLogInfo("model", String(config.model), model);
|
2024-04-03 07:04:55 +07:00
|
|
|
snprintf(config.model, sizeof(config.model), model.c_str());
|
|
|
|
}
|
|
|
|
} else {
|
2024-04-08 10:15:45 +07:00
|
|
|
failedMessage =
|
|
|
|
"'modal' value length invalid: " + String(model.length());
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (jsonTypeInvalid(root["model"], "string")) {
|
|
|
|
failedMessage = jsonTypeInvalidMessage("model", "string");
|
|
|
|
jsonInvalid();
|
|
|
|
return false;
|
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 {
|
2024-04-22 16:32:17 +07:00
|
|
|
logInfo("Nothing changed ignore udpate");
|
2024-04-22 06:27:57 +07:00
|
|
|
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-04-07 16:39:01 +07:00
|
|
|
String Configuration::toString(void) {
|
2024-04-03 07:04:55 +07:00
|
|
|
JSONVar root;
|
|
|
|
|
|
|
|
/** "country" */
|
2024-04-08 10:15:45 +07:00
|
|
|
root["country"] = String(config.country);
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
/** "pmStandard" */
|
2024-04-22 16:32:17 +07:00
|
|
|
root["pmStandard"] = getPMStandardString(config.inUSAQI);
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
/** co2CalibrationRequested */
|
|
|
|
/** ledBarTestRequested */
|
|
|
|
|
|
|
|
/** "ledBarMode" */
|
|
|
|
root["ledBarMode"] = getLedBarModeName();
|
|
|
|
|
|
|
|
/** "displayMode" */
|
2024-04-08 10:15:45 +07:00
|
|
|
if (config.displayMode) {
|
|
|
|
root["displayMode"] = "on";
|
|
|
|
} else {
|
|
|
|
root["displayMode"] = "off";
|
|
|
|
}
|
2024-04-03 07:04:55 +07:00
|
|
|
|
|
|
|
/** "abcDays" */
|
|
|
|
root["abcDays"] = config.abcDays;
|
|
|
|
|
|
|
|
/** "tvocLearningOffset" */
|
|
|
|
root["tvocLearningOffset"] = config.tvocLearningOffset;
|
|
|
|
|
|
|
|
/** "noxLearningOffset" */
|
|
|
|
root["noxLearningOffset"] = config.noxLearningOffset;
|
|
|
|
|
|
|
|
/** "mqttBrokerUrl" */
|
|
|
|
root["mqttBrokerUrl"] = String(config.mqttBroker);
|
|
|
|
|
|
|
|
/** "temperatureUnit" */
|
|
|
|
root["temperatureUnit"] = String(config.temperatureUnit);
|
|
|
|
|
|
|
|
/** configurationControl */
|
|
|
|
root["configurationControl"] =
|
|
|
|
String(CONFIGURATION_CONTROL_NAME[config.configurationControl]);
|
|
|
|
|
|
|
|
/** "postDataToAirGradient" */
|
|
|
|
root["postDataToAirGradient"] = config.postDataToAirGradient;
|
|
|
|
|
|
|
|
return JSON.stringify(root);
|
|
|
|
}
|
|
|
|
|
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-04-03 07:04:55 +07:00
|
|
|
return (config.temperatureUnit == 'f');
|
|
|
|
}
|
|
|
|
|
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-04-07 16:39:01 +07:00
|
|
|
String Configuration::getCountry(void) { return String(config.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-04-07 16:39:01 +07:00
|
|
|
bool Configuration::isPmStandardInUSAQI(void) { return config.inUSAQI; }
|
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-04-07 16:39:01 +07:00
|
|
|
int Configuration::getCO2CalibrationAbcDays(void) { return config.abcDays; }
|
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-04-03 07:04:55 +07:00
|
|
|
return (LedBarMode)config.useRGBLedBar;
|
|
|
|
}
|
|
|
|
|
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-04-03 07:04:55 +07:00
|
|
|
return getLedBarModeName((LedBarMode)config.useRGBLedBar);
|
|
|
|
}
|
|
|
|
|
2024-04-05 06:39:59 +07:00
|
|
|
/**
|
|
|
|
* @brief Get display mode
|
2024-04-07 16:39:01 +07:00
|
|
|
*
|
2024-04-05 06:39:59 +07:00
|
|
|
* @return true On
|
|
|
|
* @return false Off
|
|
|
|
*/
|
2024-04-07 16:39:01 +07:00
|
|
|
bool Configuration::getDisplayMode(void) { return config.displayMode; }
|
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) {
|
|
|
|
return String(config.mqttBroker);
|
|
|
|
}
|
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-04-03 07:04:55 +07:00
|
|
|
return config.postDataToAirGradient;
|
|
|
|
}
|
|
|
|
|
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-04-03 07:04:55 +07:00
|
|
|
return (ConfigurationControl)config.configurationControl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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-04-07 16:39:01 +07:00
|
|
|
String Configuration::getModel(void) { return String(config.model); }
|
|
|
|
|
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
|
|
|
String Configuration::getDisplayModeString(bool dispMode) {
|
|
|
|
if(dispMode){
|
|
|
|
return String("on");
|
|
|
|
}
|
|
|
|
return String("off");
|
|
|
|
}
|
|
|
|
|
|
|
|
String Configuration::getAbcDayString(int value) {
|
|
|
|
if(value <= 0){
|
|
|
|
return String("off");
|
|
|
|
}
|
|
|
|
return String(value);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
if (enable != config.postDataToAirGradient) {
|
|
|
|
config.postDataToAirGradient = enable;
|
|
|
|
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) {
|
|
|
|
return config.tvocLearningOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Configuration::getNoxLearningOffset(void) {
|
|
|
|
return config.noxLearningOffset;
|
|
|
|
}
|
2024-04-25 06:49:14 +07:00
|
|
|
|
|
|
|
String Configuration::wifiSSID(void) {
|
|
|
|
return "airgradient-" + ag->deviceId();
|
|
|
|
}
|
|
|
|
|
|
|
|
String Configuration::wifiPass(void) { return String("cleanair"); }
|
|
|
|
|
|
|
|
void Configuration::setAirGradient(AirGradient *ag) { this->ag = ag;}
|