fix: Local Configuration

This commit is contained in:
Phat Nguyen
2024-04-08 10:15:45 +07:00
parent 51ff8f8df4
commit cb7a6a2dfd
6 changed files with 200 additions and 42 deletions

View File

@ -50,7 +50,7 @@ void LocalServer::_PUT_config(void) {
statusCode = 200; statusCode = 200;
response = "Success"; response = "Success";
} else { } else {
response = "Set for cloud configuration. Local configuration ignored"; response = config.getFailedMesage();
} }
server.send(statusCode, "text/plain", response); server.send(statusCode, "text/plain", response);
} }

View File

@ -102,7 +102,6 @@ static void configurationUpdateSchedule(void);
static void executeCo2Calibration(void); static void executeCo2Calibration(void);
static void appLedHandler(void); static void appLedHandler(void);
static void appDispHandler(void); static void appDispHandler(void);
static void updateWiFiConnect(void);
static void oledDisplayLedBarSchedule(void); static void oledDisplayLedBarSchedule(void);
static void updateTvoc(void); static void updateTvoc(void);
static void updatePm(void); static void updatePm(void);
@ -186,6 +185,7 @@ void setup() {
sendDataToAg(); sendDataToAg();
apiClient.fetchServerConfiguration(); apiClient.fetchServerConfiguration();
configSchedule.update();
if (apiClient.isFetchConfigureFailed()) { if (apiClient.isFetchConfigureFailed()) {
if (ag->isOne()) { if (ag->isOne()) {
stateMachine.displayHandle( stateMachine.displayHandle(

View File

@ -60,12 +60,12 @@ void Configuration::loadConfig(void) {
} }
readSuccess = true; readSuccess = true;
#else #else
if (EEPROM.readBytes(0, &config, sizeof(config)) != sizeof(config)) { if (EEPROM.readBytes(0, &config, sizeof(config)) == sizeof(config)) {
readSuccess = true; readSuccess = true;
} }
#endif #endif
if (readSuccess) { if (!readSuccess) {
logError("Load configure failed"); logError("Load configure failed");
defaultConfig(); defaultConfig();
} else { } else {
@ -79,6 +79,23 @@ void Configuration::loadConfig(void) {
if (sum != config._check) { if (sum != config._check) {
logError("Configure validate invalid"); logError("Configure validate invalid");
defaultConfig(); defaultConfig();
} else {
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();
}
} }
} }
} }
@ -152,8 +169,10 @@ bool Configuration::begin(void) {
*/ */
bool Configuration::parse(String data, bool isLocal) { bool Configuration::parse(String data, bool isLocal) {
JSONVar root = JSON.parse(data); JSONVar root = JSON.parse(data);
failedMessage = "";
if (JSON.typeof_(root) == "undefined") { if (JSON.typeof_(root) == "undefined") {
logError("Configuration JSON invalid"); failedMessage = "JSON invalid";
logError(failedMessage);
return false; return false;
} }
logInfo("Parse configure success"); logInfo("Parse configure success");
@ -185,29 +204,36 @@ bool Configuration::parse(String data, bool isLocal) {
(uint8_t)ConfigurationControl::ConfigurationControlBoth; (uint8_t)ConfigurationControl::ConfigurationControlBoth;
changed = true; changed = true;
} else { } else {
failedMessage = jsonValueInvalidMessage("configurationControl",
logError(String("'configurationControl' value '" + configurationControl);
configurationControl + "' invalid") jsonInvalid();
.c_str());
return false; return false;
} }
} else { } else {
if (jsonTypeInvalid(root["configurationControl"], "string")) {
failedMessage =
jsonTypeInvalidMessage("configurationControl", "string");
jsonInvalid();
return false; return false;
} }
}
if ((config.configurationControl == if ((config.configurationControl ==
(byte)ConfigurationControl::ConfigurationControlCloud)) { (byte)ConfigurationControl::ConfigurationControlCloud)) {
logWarning("Local configure ignored"); failedMessage = "Local configure ignored";
jsonInvalid();
return false; return false;
} }
} else { } else {
if (config.configurationControl == if (config.configurationControl ==
(byte)ConfigurationControl::ConfigurationControlLocal) { (byte)ConfigurationControl::ConfigurationControlLocal) {
logWarning("Cloud configure ignored"); failedMessage = "Cloud configure ignored";
jsonInvalid();
return false; return false;
} }
} }
char temperatureUnit = 0;
if (JSON.typeof_(root["country"]) == "string") { if (JSON.typeof_(root["country"]) == "string") {
String country = root["country"]; String country = root["country"];
if (country.length() == 2) { if (country.length() == 2) {
@ -220,21 +246,23 @@ bool Configuration::parse(String data, bool isLocal) {
// Update temperature unit if get configuration from server // Update temperature unit if get configuration from server
if (isLocal == false) { if (isLocal == false) {
if (country == "US") { if (country == "US") {
if (config.temperatureUnit == 'c') { temperatureUnit = 'f';
changed = true;
config.temperatureUnit = 'f';
}
} else { } else {
if (config.temperatureUnit == 'f') { temperatureUnit = 'c';
changed = true;
config.temperatureUnit = 'c';
}
} }
} }
} else { } else {
logInfo("Country name " + country + failedMessage = "Country name " + country +
" invalid. Find details here (ALPHA-2): " " invalid. Find details here (ALPHA-2): "
"https://www.iban.com/country-codes"); "https://www.iban.com/country-codes";
jsonInvalid();
return false;
}
} else {
if (jsonTypeInvalid(root["country"], "string")) {
failedMessage = jsonTypeInvalidMessage("country", "string");
jsonInvalid();
return false;
} }
} }
@ -243,6 +271,12 @@ bool Configuration::parse(String data, bool isLocal) {
bool inUSAQI = true; bool inUSAQI = true;
if (pmStandard == "ugm3") { if (pmStandard == "ugm3") {
inUSAQI = false; inUSAQI = false;
} else if (pmStandard == "USAQI") {
inUSAQI = true;
} else {
failedMessage = jsonValueInvalidMessage("pmStandard", pmStandard);
jsonInvalid();
return false;
} }
if (inUSAQI != config.inUSAQI) { if (inUSAQI != config.inUSAQI) {
@ -250,16 +284,35 @@ bool Configuration::parse(String data, bool isLocal) {
changed = true; changed = true;
logInfo("Set PM standard: " + pmStandard); logInfo("Set PM standard: " + pmStandard);
} }
} else {
if (jsonTypeInvalid(root["pmStandard"], "string")) {
failedMessage = jsonTypeInvalidMessage("pmStandard", "string");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["co2CalibrationRequested"]) == "boolean") { if (JSON.typeof_(root["co2CalibrationRequested"]) == "boolean") {
co2CalibrationRequested = root["co2CalibrationRequested"]; co2CalibrationRequested = root["co2CalibrationRequested"];
logInfo("Set co2CalibrationRequested: " + String(co2CalibrationRequested)); logInfo("Set co2CalibrationRequested: " + String(co2CalibrationRequested));
} else {
if (jsonTypeInvalid(root["co2CalibrationRequested"], "boolean")) {
failedMessage =
jsonTypeInvalidMessage("co2CalibrationRequested", "boolean");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["ledBarTestRequested"]) == "boolean") { if (JSON.typeof_(root["ledBarTestRequested"]) == "boolean") {
ledBarTestRequested = root["ledBarTestRequested"]; ledBarTestRequested = root["ledBarTestRequested"];
logInfo("Set ledBarTestRequested: " + String(ledBarTestRequested)); logInfo("Set ledBarTestRequested: " + String(ledBarTestRequested));
} else {
if (jsonTypeInvalid(root["ledBarTestRequested"], "boolean")) {
failedMessage = jsonTypeInvalidMessage("ledBarTestRequested", "boolean");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["ledBarMode"]) == "string") { if (JSON.typeof_(root["ledBarMode"]) == "string") {
@ -272,8 +325,9 @@ bool Configuration::parse(String data, bool isLocal) {
} else if (mode == String(LED_BAR_MODE_NAMES[LedBarModeOff])) { } else if (mode == String(LED_BAR_MODE_NAMES[LedBarModeOff])) {
ledBarMode = LedBarModeOff; ledBarMode = LedBarModeOff;
} else { } else {
ledBarMode = config.useRGBLedBar; failedMessage = jsonValueInvalidMessage("ledBarMode", mode);
logInfo("ledBarMode value '" + mode + "' invalid"); jsonInvalid();
return false;
} }
if (ledBarMode != config.useRGBLedBar) { if (ledBarMode != config.useRGBLedBar) {
@ -281,6 +335,12 @@ bool Configuration::parse(String data, bool isLocal) {
changed = true; changed = true;
logInfo("Set ledBarMode: " + mode); logInfo("Set ledBarMode: " + mode);
} }
} else {
if (jsonTypeInvalid(root["ledBarMode"], "string")) {
failedMessage = jsonTypeInvalidMessage("ledBarMode", "string");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["displayMode"]) == "string") { if (JSON.typeof_(root["displayMode"]) == "string") {
@ -291,8 +351,9 @@ bool Configuration::parse(String data, bool isLocal) {
} else if (mode == "off") { } else if (mode == "off") {
displayMode = false; displayMode = false;
} else { } else {
displayMode = config.displayMode; failedMessage = jsonTypeInvalidMessage("displayMode", mode);
logInfo("displayMode '" + mode + "' invalid"); jsonInvalid();
return false;
} }
if (displayMode != config.displayMode) { if (displayMode != config.displayMode) {
@ -300,15 +361,32 @@ bool Configuration::parse(String data, bool isLocal) {
config.displayMode = displayMode; config.displayMode = displayMode;
logInfo("Set displayMode: " + mode); logInfo("Set displayMode: " + mode);
} }
} else {
if (jsonTypeInvalid(root["displayMode"], "string")) {
failedMessage = jsonTypeInvalidMessage("displayMode", "string");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["abcDays"]) == "number") { if (JSON.typeof_(root["abcDays"]) == "number") {
int abcDays = root["abcDays"]; int abcDays = root["abcDays"];
if (abcDays <= 0) {
failedMessage = jsonTypeInvalidMessage("abcDaysabcDays", String(abcDays));
jsonInvalid();
return false;
}
if (abcDays != config.abcDays) { if (abcDays != config.abcDays) {
config.abcDays = abcDays; config.abcDays = abcDays;
changed = true; changed = true;
logInfo("Set abcDays: " + String(abcDays)); logInfo("Set abcDays: " + String(abcDays));
} }
} else {
if (jsonTypeInvalid(root["abcDays"], "number")) {
failedMessage = jsonTypeInvalidMessage("abcDays", "number");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["tvocLearningOffset"]) == "number") { if (JSON.typeof_(root["tvocLearningOffset"]) == "number") {
@ -318,6 +396,12 @@ bool Configuration::parse(String data, bool isLocal) {
config.tvocLearningOffset = tvocLearningOffset; config.tvocLearningOffset = tvocLearningOffset;
logInfo("Set tvocLearningOffset: " + String(tvocLearningOffset)); logInfo("Set tvocLearningOffset: " + String(tvocLearningOffset));
} }
} else {
if (jsonTypeInvalid(root["tvocLearningOffset"], "number")) {
failedMessage = jsonTypeInvalidMessage("tvocLearningOffset", "number");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["noxLearningOffset"]) == "number") { if (JSON.typeof_(root["noxLearningOffset"]) == "number") {
@ -327,6 +411,12 @@ bool Configuration::parse(String data, bool isLocal) {
config.noxLearningOffset = noxLearningOffset; config.noxLearningOffset = noxLearningOffset;
logInfo("Set noxLearningOffset: " + String(noxLearningOffset)); logInfo("Set noxLearningOffset: " + String(noxLearningOffset));
} }
} else {
if (jsonTypeInvalid(root["noxLearningOffset"], "number")) {
failedMessage = jsonTypeInvalidMessage("noxLearningOffset", "number");
jsonInvalid();
return false;
}
} }
if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") { if (JSON.typeof_(root["mqttBrokerUrl"]) == "string") {
@ -338,31 +428,44 @@ bool Configuration::parse(String data, bool isLocal) {
logInfo("Set mqttBrokerUrl: " + broker); logInfo("Set mqttBrokerUrl: " + broker);
} }
} else { } else {
logError("Error: mqttBroker length invalid: " + String(broker.length())); failedMessage =
"'mqttBroker' value length invalid: " + String(broker.length());
jsonInvalid();
return false;
}
} else {
if (jsonTypeInvalid(root["mqttBrokerUrl"], "string")) {
failedMessage = jsonTypeInvalidMessage("mqttBrokerUrl", "string");
jsonInvalid();
return false;
} }
} }
char temperatureUnit = 0;
if (JSON.typeof_(root["temperatureUnit"]) == "string") { if (JSON.typeof_(root["temperatureUnit"]) == "string") {
String unit = root["temperatureUnit"]; String unit = root["temperatureUnit"];
if (unit == "c" || unit == "C") { unit.toLowerCase();
if (unit == "c") {
temperatureUnit = 'c'; temperatureUnit = 'c';
} else if (unit == "f" || unit == "F") { } else if (unit == "f") {
temperatureUnit = 'f'; temperatureUnit = 'f';
} else { } else {
temperatureUnit = 0; failedMessage = "'temperatureUnit' value '" + unit + "' invalid";
logError(failedMessage);
return false;
}
} else {
if (jsonTypeInvalid(root["temperatureUnit"], "string")) {
failedMessage = jsonTypeInvalidMessage("temperatureUnit", "string");
jsonInvalid();
return false;
} }
} }
if (temperatureUnit != config.temperatureUnit) { if (temperatureUnit != 0 && temperatureUnit != config.temperatureUnit) {
changed = true; changed = true;
config.temperatureUnit = temperatureUnit; config.temperatureUnit = temperatureUnit;
if (temperatureUnit == 0) {
logInfo("set temperatureUnit: null");
} else {
logInfo("set temperatureUnit: " + String(temperatureUnit)); logInfo("set temperatureUnit: " + String(temperatureUnit));
} }
}
if (JSON.typeof_(root["postDataToAirGradient"]) == "boolean") { if (JSON.typeof_(root["postDataToAirGradient"]) == "boolean") {
bool post = root["postDataToAirGradient"]; bool post = root["postDataToAirGradient"];
@ -371,6 +474,13 @@ bool Configuration::parse(String data, bool isLocal) {
config.postDataToAirGradient = post; config.postDataToAirGradient = post;
logInfo("Set postDataToAirGradient: " + String(post)); logInfo("Set postDataToAirGradient: " + String(post));
} }
} else {
if (jsonTypeInvalid(root["postDataToAirGradient"], "boolean")) {
failedMessage =
jsonTypeInvalidMessage("postDataToAirGradient", "boolean");
jsonInvalid();
return false;
}
} }
/** Parse data only got from AirGradient server */ /** Parse data only got from AirGradient server */
@ -383,7 +493,16 @@ bool Configuration::parse(String data, bool isLocal) {
snprintf(config.model, sizeof(config.model), model.c_str()); snprintf(config.model, sizeof(config.model), model.c_str());
} }
} else { } else {
logError("Error: modal name length invalid: " + String(model.length())); failedMessage =
"'modal' value length invalid: " + String(model.length());
jsonInvalid();
return false;
}
} else {
if (jsonTypeInvalid(root["model"], "string")) {
failedMessage = jsonTypeInvalidMessage("model", "string");
jsonInvalid();
return false;
} }
} }
} }
@ -406,7 +525,7 @@ String Configuration::toString(void) {
JSONVar root; JSONVar root;
/** "country" */ /** "country" */
root["Country"] = String(config.country); root["country"] = String(config.country);
/** "pmStandard" */ /** "pmStandard" */
if (config.inUSAQI) { if (config.inUSAQI) {
@ -422,7 +541,11 @@ String Configuration::toString(void) {
root["ledBarMode"] = getLedBarModeName(); root["ledBarMode"] = getLedBarModeName();
/** "displayMode" */ /** "displayMode" */
root["displayMode"] = config.displayMode; if (config.displayMode) {
root["displayMode"] = "on";
} else {
root["displayMode"] = "off";
}
/** "abcDays" */ /** "abcDays" */
root["abcDays"] = config.abcDays; root["abcDays"] = config.abcDays;
@ -582,3 +705,26 @@ bool Configuration::isUpdated(void) {
this->udpated = false; this->udpated = false;
return updated; return updated;
} }
bool Configuration::jsonTypeInvalid(JSONVar root, String validType) {
String type = JSON.typeof_(root);
if (type == validType || type == "undefined" || type == "unknown" || type == "null") {
return false;
}
return true;
}
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);
}
String Configuration::getFailedMesage(void) { return failedMessage; }

View File

@ -33,12 +33,17 @@ private:
bool co2CalibrationRequested; bool co2CalibrationRequested;
bool ledBarTestRequested; bool ledBarTestRequested;
bool udpated; bool udpated;
String failedMessage;
String getLedBarModeName(LedBarMode mode); String getLedBarModeName(LedBarMode mode);
void saveConfig(void); void saveConfig(void);
void loadConfig(void); void loadConfig(void);
void defaultConfig(void); void defaultConfig(void);
void printConfig(void); void printConfig(void);
bool jsonTypeInvalid(JSONVar root, String validType);
String jsonTypeInvalidMessage(String name, String type);
String jsonValueInvalidMessage(String name, String value);
void jsonInvalid(void);
public: public:
Configuration(Stream &debugLog); Configuration(Stream &debugLog);
@ -68,6 +73,7 @@ public:
void reset(void); void reset(void);
String getModel(void); String getModel(void);
bool isUpdated(void); bool isUpdated(void);
String getFailedMesage(void);
}; };
#endif /** _AG_CONFIG_H_ */ #endif /** _AG_CONFIG_H_ */

View File

@ -19,3 +19,8 @@ void AgSchedule::run(void) {
* @param period Period in ms * @param period Period in ms
*/ */
void AgSchedule::setPeriod(int period) { this->period = period; } void AgSchedule::setPeriod(int period) { this->period = period; }
/**
* @brief Update period
*/
void AgSchedule::update(void) { count = millis(); }

View File

@ -13,6 +13,7 @@ public:
AgSchedule(int period, void (*handler)(void)); AgSchedule(int period, void (*handler)(void));
~AgSchedule(); ~AgSchedule();
void run(void); void run(void);
void update(void);
void setPeriod(int period); void setPeriod(int period);
}; };