From 88c2437907e86624b77a7f73a637f8e65c96e015 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Wed, 22 Jan 2025 01:53:55 +0700 Subject: [PATCH] Handle correction configuration for atmp and rhum From local and cloud --- src/AgConfigure.cpp | 141 ++++++++++++++++++++++++++++++++++++++++++-- src/AgConfigure.h | 14 ++++- src/App/AppDef.h | 8 +++ 3 files changed, 158 insertions(+), 5 deletions(-) diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp index 57e864b..8a247d2 100644 --- a/src/AgConfigure.cpp +++ b/src/AgConfigure.cpp @@ -33,6 +33,13 @@ const char *PM_CORRECTION_ALGORITHM_NAMES[] = { [SLR_PMS5003_20240104] = "slr_PMS5003_20240104", }; +const char *TEMP_HUM_CORRECTION_ALGORITHM_NAMES[] = { + [CA_TH_UNKNOWN] = "-", // This is only to pass "non-trivial designated initializers" error + [CA_TH_NONE] = "none", + [CA_TH_AG_PMS5003T_2024] = "ag_pms5003t_2024", + [CA_TH_SLR_CUSTOM] = "custom", +}; + #define JSON_PROP_NAME(name) jprop_##name #define JSON_PROP_DEF(name) const char *JSON_PROP_NAME(name) = #name @@ -54,6 +61,8 @@ JSON_PROP_DEF(ledBarTestRequested); JSON_PROP_DEF(offlineMode); JSON_PROP_DEF(monitorDisplayCompensatedValues); JSON_PROP_DEF(corrections); +JSON_PROP_DEF(atmp); +JSON_PROP_DEF(rhum); #define jprop_model_default "" #define jprop_country_default "TH" @@ -117,6 +126,21 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) { return result; } +TempHumCorrectionAlgorithm Configuration::matchTempHumAlgorithm(String algorithm) { + // Get the actual size of the enum + const int enumSize = static_cast(CA_TH_SLR_CUSTOM); + TempHumCorrectionAlgorithm result = CA_TH_UNKNOWN; + + // Loop through enum values + for (size_t enumVal = 0; enumVal <= enumSize; enumVal++) { + if (algorithm == TEMP_HUM_CORRECTION_ALGORITHM_NAMES[enumVal]) { + result = static_cast(enumVal); + } + } + + return result; +} + bool Configuration::updatePmCorrection(JSONVar &json) { if (!json.hasOwnProperty("corrections")) { // TODO: need to response message? @@ -205,6 +229,89 @@ bool Configuration::updatePmCorrection(JSONVar &json) { return true; } +bool Configuration::updateTempHumCorrection(JSONVar &json, TempHumCorrection &target, + const char *correctionName) { + if (!json.hasOwnProperty(jprop_corrections)) { + // TODO: need to response message? + return false; + } + + JSONVar corrections = json[jprop_corrections]; + if (!corrections.hasOwnProperty(correctionName)) { + Serial.println("pm02 not found"); + logWarning(String(correctionName) + " correction field not found on configuration"); + return false; + } + + JSONVar correctionTarget = corrections[correctionName]; + if (!correctionTarget.hasOwnProperty("correctionAlgorithm")) { + Serial.println("correctionAlgorithm not found"); + return false; + } + + String algorithm = correctionTarget["correctionAlgorithm"]; + TempHumCorrectionAlgorithm algo = matchTempHumAlgorithm(algorithm); + if (algo == CA_TH_UNKNOWN) { + logInfo("Uknown temp/hum algorithm"); + return false; + } + logInfo(String(correctionName) + " correction algorithm: " + algorithm); + + // If algo is None or Standard, then no need to check slr + // But first check if target correction different from algo + if (algo == CA_TH_NONE || algo == CA_TH_AG_PMS5003T_2024) { + if (target.algorithm != algo) { + // Deep copy corrections from root to jconfig, so it will be saved later + jconfig[jprop_corrections][correctionName]["correctionAlgorithm"] = algorithm; + jconfig[jprop_corrections][correctionName]["slr"] = JSON.parse("{}"); // Clear slr + // Update pmCorrection with new values + target.algorithm = algo; + target.changed = true; + logInfo(String(correctionName) + " correction updated"); + return true; + } + + return false; + } + + // Check if correction.target (atmp or rhum) has slr object + if (!correctionTarget.hasOwnProperty("slr")) { + logWarning(String(correctionName) + " slr not found"); + return false; + } + + JSONVar slr = correctionTarget["slr"]; + + // Validate required slr properties exist + if (!slr.hasOwnProperty("intercept") || !slr.hasOwnProperty("scalingFactor")) { + Serial.println("Missing required slr properties"); + return false; + } + + // arduino_json doesn't support float type, need to cast to double first + float intercept = (float)((double)slr["intercept"]); + float scalingFactor = (float)((double)slr["scalingFactor"]); + + // Compare with current target correciont + if (target.algorithm == algo && target.intercept == intercept && + target.scalingFactor == scalingFactor) { + return false; // No changes needed + } + + // Deep copy corrections from root to jconfig, so it will be saved later + jconfig[jprop_corrections] = corrections; + + // Update target with new values + target.algorithm = algo; + target.intercept = intercept; + target.scalingFactor = scalingFactor; + target.changed = true; + + // Correction values were updated + logInfo(String(correctionName) + " correction updated"); + return true; +} + /** * @brief Save configure to device storage (EEPROM) * @@ -792,11 +899,21 @@ bool Configuration::parse(String data, bool isLocal) { } } - // Corrections + // PM2.5 Corrections if (updatePmCorrection(root)) { changed = true; } + // Temperature correction + if (updateTempHumCorrection(root, tempCorrection, jprop_atmp)) { + changed = true; + } + + // Relative humidity correction + if (updateTempHumCorrection(root, rhumCorrection, jprop_rhum)) { + changed = true; + } + if (changed) { updated = true; saveConfig(); @@ -1248,15 +1365,31 @@ void Configuration::toConfig(const char *buf) { jprop_monitorDisplayCompensatedValues_default; } - - // Set default first before parsing local config + // PM2.5 correction + /// Set default first before parsing local config pmCorrection.algorithm = PMCorrectionAlgorithm::None; pmCorrection.intercept = 0; pmCorrection.scalingFactor = 0; pmCorrection.useEPA = false; - // Load correction from saved config + /// Load correction from saved config updatePmCorrection(jconfig); + // Temperature correction + /// Set default first before parsing local config + tempCorrection.algorithm = CA_TH_NONE; + tempCorrection.intercept = 0; + tempCorrection.scalingFactor = 0; + /// Load correction from saved config + updateTempHumCorrection(jconfig, tempCorrection, jprop_atmp); + + // Relative humidity correction + /// Set default first before parsing local config + rhumCorrection.algorithm = CA_TH_NONE; + rhumCorrection.intercept = 0; + rhumCorrection.scalingFactor = 0; + /// Load correction from saved config + updateTempHumCorrection(jconfig, rhumCorrection, jprop_rhum); + if (changed) { saveConfig(); } diff --git a/src/AgConfigure.h b/src/AgConfigure.h index 1cca028..e80a7fa 100644 --- a/src/AgConfigure.h +++ b/src/AgConfigure.h @@ -17,6 +17,13 @@ public: bool changed; }; + struct TempHumCorrection { + TempHumCorrectionAlgorithm algorithm; + float intercept; + float scalingFactor; + bool changed; + }; + private: bool co2CalibrationRequested; bool ledBarTestRequested; @@ -30,12 +37,17 @@ private: bool _offlineMode = false; bool _ledBarModeChanged = false; PMCorrection pmCorrection; + TempHumCorrection tempCorrection; + TempHumCorrection rhumCorrection; AirGradient* ag; String getLedBarModeName(LedBarMode mode); PMCorrectionAlgorithm matchPmAlgorithm(String algorithm); + TempHumCorrectionAlgorithm matchTempHumAlgorithm(String algorithm); bool updatePmCorrection(JSONVar &json); + bool updateTempHumCorrection(JSONVar &json, TempHumCorrection &target, + const char *correctionName); void saveConfig(void); void loadConfig(void); void defaultConfig(void); @@ -46,7 +58,7 @@ private: void configLogInfo(String name, String fromValue, String toValue); String getPMStandardString(bool usaqi); String getAbcDayString(int value); - void toConfig(const char* buf); + void toConfig(const char *buf); public: Configuration(Stream &debugLog); diff --git a/src/App/AppDef.h b/src/App/AppDef.h index df5707e..9a03a71 100644 --- a/src/App/AppDef.h +++ b/src/App/AppDef.h @@ -106,6 +106,14 @@ enum PMCorrectionAlgorithm { SLR_PMS5003_20240104, }; +// Don't change the order of the enum +enum TempHumCorrectionAlgorithm { + CA_TH_UNKNOWN, // Unknown algorithm + CA_TH_NONE, // No PM correction + CA_TH_AG_PMS5003T_2024, + CA_TH_SLR_CUSTOM +}; + enum AgFirmwareMode { FW_MODE_I_9PSL, /** ONE_INDOOR */ FW_MODE_O_1PST, /** PMS5003T, S8 and SGP41 */