From c842346724d7059142ee39557220540ec3629ee7 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sun, 19 Jan 2025 15:45:09 +0700
Subject: [PATCH 01/36] Fix invalidate value check for getAverage
---
src/AgValue.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index a8463ce..1a46ece 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -406,12 +406,12 @@ float Measurements::getAverage(MeasurementType type, int ch) {
// Sanity check to validate channel, assert if invalid
validateChannel(ch);
+ bool undefined = false;
+
// Follow array indexing just for get address of the value type
ch = ch - 1;
// Define data point source. Data type doesn't matter because only to get the average value
- FloatValue *temporary = nullptr;
- Update update;
float measurementAverage;
switch (type) {
case CO2:
@@ -434,12 +434,12 @@ float Measurements::getAverage(MeasurementType type, int ch) {
break;
default:
// Invalidate, measurements type not handled
- measurementAverage = -1000;
+ undefined = true;
break;
};
- // Sanity check if measurement type is not defined
- if (measurementAverage == -1000) {
+ // Sanity check if measurement type is not defined
+ if (undefined) {
Serial.printf("ERROR! %s is not defined on get average value function\n", measurementTypeStr(type).c_str());
delay(1000);
assert(0);
From e9b27185b42f99bf0ce436c9f904415d6695f3fd Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 22 Jan 2025 01:46:08 +0700
Subject: [PATCH 02/36] Fix spaces
---
src/App/AppDef.h | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/App/AppDef.h b/src/App/AppDef.h
index 1e114e7..df5707e 100644
--- a/src/App/AppDef.h
+++ b/src/App/AppDef.h
@@ -107,14 +107,14 @@ enum PMCorrectionAlgorithm {
};
enum AgFirmwareMode {
- FW_MODE_I_9PSL, /** ONE_INDOOR */
- FW_MODE_O_1PST, /** PMS5003T, S8 and SGP41 */
- FW_MODE_O_1PPT, /** PMS5003T_1, PMS5003T_2, SGP41 */
- FW_MODE_O_1PP, /** PMS5003T_1, PMS5003T_2 */
- FW_MODE_O_1PS, /** PMS5003T, S8 */
- FW_MODE_O_1P, /** PMS5003T */
- FW_MODE_I_42PS, /** DIY_PRO 4.2 */
- FW_MODE_I_33PS, /** DIY_PRO 3.3 */
+ FW_MODE_I_9PSL, /** ONE_INDOOR */
+ FW_MODE_O_1PST, /** PMS5003T, S8 and SGP41 */
+ FW_MODE_O_1PPT, /** PMS5003T_1, PMS5003T_2, SGP41 */
+ FW_MODE_O_1PP, /** PMS5003T_1, PMS5003T_2 */
+ FW_MODE_O_1PS, /** PMS5003T, S8 */
+ FW_MODE_O_1P, /** PMS5003T */
+ FW_MODE_I_42PS, /** DIY_PRO 4.2 */
+ FW_MODE_I_33PS, /** DIY_PRO 3.3 */
FW_MODE_I_BASIC_40PS, /** DIY_BASIC 4.0 */
};
const char *AgFirmwareModeName(AgFirmwareMode mode);
From 88c2437907e86624b77a7f73a637f8e65c96e015 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 22 Jan 2025 01:53:55 +0700
Subject: [PATCH 03/36] 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 */
From 20db9d699b19de7149ebdeeaeafbff6d0b3d45ac Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 23 Jan 2025 01:16:49 +0700
Subject: [PATCH 04/36] Retrieve temp hum correction object
---
src/AgConfigure.cpp | 8 +++++---
src/AgConfigure.h | 2 ++
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 8a247d2..63e5e8f 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -1510,6 +1510,8 @@ bool Configuration::isPMCorrectionEnabled(void) {
return true;
}
-Configuration::PMCorrection Configuration::getPMCorrection(void) {
- return pmCorrection;
-}
+Configuration::PMCorrection Configuration::getPMCorrection(void) { return pmCorrection; }
+
+Configuration::TempHumCorrection Configuration::getTempCorrection(void) { return tempCorrection; }
+
+Configuration::TempHumCorrection Configuration::getHumCorrection(void) { return rhumCorrection; }
diff --git a/src/AgConfigure.h b/src/AgConfigure.h
index e80a7fa..863d876 100644
--- a/src/AgConfigure.h
+++ b/src/AgConfigure.h
@@ -111,6 +111,8 @@ public:
bool isPMCorrectionChanged(void);
bool isPMCorrectionEnabled(void);
PMCorrection getPMCorrection(void);
+ TempHumCorrection getTempCorrection(void);
+ TempHumCorrection getHumCorrection(void);
};
#endif /** _AG_CONFIG_H_ */
From 89475ddf95c5c6a5b963b2368e001054e78972a2 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 23 Jan 2025 01:21:27 +0700
Subject: [PATCH 05/36] Get correction of temp and hum based on configuration
---
src/AgValue.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++
src/AgValue.h | 3 +++
2 files changed, 60 insertions(+)
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index 1a46ece..f724d9e 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -535,6 +535,63 @@ void Measurements::validateChannel(int ch) {
}
}
+float Measurements::getCorrectedTempHum(AirGradient &ag, Configuration &config,
+ MeasurementType type, int ch, bool forceCorrection) {
+ // Sanity check to validate channel, assert if invalid
+ validateChannel(ch);
+
+ // Follow array indexing just for get address of the value type
+ ch = ch - 1;
+ bool undefined = false;
+
+ float rawValue;
+ Configuration::TempHumCorrection correction;
+
+ switch (type) {
+ case Temperature: {
+ rawValue = _temperature[ch].update.avg;
+
+ Configuration::TempHumCorrection tmp = config.getTempCorrection();
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
+ return ag.pms5003t_1.compensateTemp(rawValue);
+ }
+
+ correction.algorithm = tmp.algorithm;
+ correction.intercept = tmp.intercept;
+ correction.scalingFactor = tmp.scalingFactor;
+ break;
+ }
+ case Humidity: {
+ rawValue = _humidity[ch].update.avg;
+
+ Configuration::TempHumCorrection tmp = config.getHumCorrection();
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
+ return ag.pms5003t_1.compensateHum(rawValue);
+ }
+
+ correction.algorithm = tmp.algorithm;
+ correction.intercept = tmp.intercept;
+ correction.scalingFactor = tmp.scalingFactor;
+ break;
+ }
+ default:
+ // Should not be called for other measurements
+ delay(1000);
+ assert(0);
+ }
+
+ // Use raw if correction not defined
+ if (correction.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE ||
+ correction.algorithm == TempHumCorrectionAlgorithm::CA_TH_UNKNOWN) {
+ return rawValue;
+ }
+
+ // Custom correction constants
+ float corrected = (rawValue * correction.scalingFactor) + correction.intercept;
+
+ return corrected;
+}
+
float Measurements::getCorrectedPM25(AirGradient &ag, Configuration &config, bool useAvg, int ch) {
float pm25;
float corrected;
diff --git a/src/AgValue.h b/src/AgValue.h
index 6cc7a05..7402e1d 100644
--- a/src/AgValue.h
+++ b/src/AgValue.h
@@ -123,6 +123,9 @@ public:
*/
float getAverage(MeasurementType type, int ch = 1);
+ float getCorrectedTempHum(AirGradient &ag, Configuration &config, MeasurementType type,
+ int ch = 1, bool forceCorrection = false);
+
/**
* @brief Get the Corrected PM25 object based on the correction algorithm from configuration
*
From 1666923ab31cc81508b3580ac9164a34e495e213 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 23 Jan 2025 03:33:47 +0700
Subject: [PATCH 06/36] Add AirGradient and Configuration object to AgValue
---
examples/OneOpenAir/LocalServer.cpp | 2 +-
examples/OneOpenAir/OneOpenAir.ino | 8 +-
examples/OneOpenAir/OpenMetrics.cpp | 10 +-
src/AgOledDisplay.cpp | 4 +-
src/AgStateMachine.cpp | 2 +-
src/AgValue.cpp | 356 ++++++++++++++--------------
src/AgValue.h | 26 +-
7 files changed, 204 insertions(+), 204 deletions(-)
diff --git a/examples/OneOpenAir/LocalServer.cpp b/examples/OneOpenAir/LocalServer.cpp
index e0b5c98..69434e2 100644
--- a/examples/OneOpenAir/LocalServer.cpp
+++ b/examples/OneOpenAir/LocalServer.cpp
@@ -64,7 +64,7 @@ void LocalServer::_GET_metrics(void) {
}
void LocalServer::_GET_measure(void) {
- String toSend = measure.toString(true, fwMode, wifiConnector.RSSI(), *ag, config);
+ String toSend = measure.toString(true, fwMode, wifiConnector.RSSI());
server.send(200, "application/json", toSend);
}
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index ee4b680..5c374a3 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -76,7 +76,7 @@ static MqttClient mqttClient(Serial);
static TaskHandle_t mqttTask = NULL;
static Configuration configuration(Serial);
static AgApiClient apiClient(Serial, configuration);
-static Measurements measurements;
+static Measurements measurements(configuration);
static AirGradient *ag;
static OledDisplay oledDisplay(configuration, measurements, Serial);
static StateMachine stateMachine(oledDisplay, Serial, measurements,
@@ -164,6 +164,7 @@ void setup() {
apiClient.setAirGradient(ag);
openMetrics.setAirGradient(ag);
localServer.setAirGraident(ag);
+ measurements.setAirGradient(ag);
/** Example set custom API root URL */
// apiClient.setApiRoot("https://example.custom.api");
@@ -368,8 +369,7 @@ static void createMqttTask(void) {
/** Send data */
if (mqttClient.isConnected()) {
- String payload =
- measurements.toString(true, fwMode, wifiConnector.RSSI(), *ag, configuration);
+ String payload = measurements.toString(true, fwMode, wifiConnector.RSSI());
String topic = "airgradient/readings/" + ag->deviceId();
if (mqttClient.publish(topic.c_str(), payload.c_str(),
@@ -1145,7 +1145,7 @@ static void sendDataToServer(void) {
return;
}
- String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), *ag, configuration);
+ String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI());
if (apiClient.postToServer(syncData)) {
Serial.println();
Serial.println(
diff --git a/examples/OneOpenAir/OpenMetrics.cpp b/examples/OneOpenAir/OpenMetrics.cpp
index fa59444..753f9c7 100644
--- a/examples/OneOpenAir/OpenMetrics.cpp
+++ b/examples/OneOpenAir/OpenMetrics.cpp
@@ -81,8 +81,8 @@ String OpenMetrics::getPayload(void) {
measure.getFloat(Measurements::Humidity, 2)) /
2.0f;
pm01 = (measure.get(Measurements::PM01, 1) + measure.get(Measurements::PM01, 2)) / 2.0f;
- float correctedPm25_1 = measure.getCorrectedPM25(*ag, config, false, 1);
- float correctedPm25_2 = measure.getCorrectedPM25(*ag, config, false, 2);
+ float correctedPm25_1 = measure.getCorrectedPM25(false, 1);
+ float correctedPm25_2 = measure.getCorrectedPM25(false, 2);
float correctedPm25 = (correctedPm25_1 + correctedPm25_2) / 2.0f;
pm25 = round(correctedPm25);
pm10 = (measure.get(Measurements::PM10, 1) + measure.get(Measurements::PM10, 2)) / 2.0f;
@@ -97,7 +97,7 @@ String OpenMetrics::getPayload(void) {
if (config.hasSensorPMS1) {
pm01 = measure.get(Measurements::PM01);
- float correctedPm = measure.getCorrectedPM25(*ag, config, false, 1);
+ float correctedPm = measure.getCorrectedPM25(false, 1);
pm25 = round(correctedPm);
pm10 = measure.get(Measurements::PM10);
pm03PCount = measure.get(Measurements::PM03_PC);
@@ -107,7 +107,7 @@ String OpenMetrics::getPayload(void) {
_temp = measure.getFloat(Measurements::Temperature, 1);
_hum = measure.getFloat(Measurements::Humidity, 1);
pm01 = measure.get(Measurements::PM01, 1);
- float correctedPm = measure.getCorrectedPM25(*ag, config, false, 1);
+ float correctedPm = measure.getCorrectedPM25(false, 1);
pm25 = round(correctedPm);
pm10 = measure.get(Measurements::PM10, 1);
pm03PCount = measure.get(Measurements::PM03_PC, 1);
@@ -116,7 +116,7 @@ String OpenMetrics::getPayload(void) {
_temp = measure.getFloat(Measurements::Temperature, 2);
_hum = measure.getFloat(Measurements::Humidity, 2);
pm01 = measure.get(Measurements::PM01, 2);
- float correctedPm = measure.getCorrectedPM25(*ag, config, false, 2);
+ float correctedPm = measure.getCorrectedPM25(false, 2);
pm25 = round(correctedPm);
pm10 = measure.get(Measurements::PM10, 2);
pm03PCount = measure.get(Measurements::PM03_PC, 2);
diff --git a/src/AgOledDisplay.cpp b/src/AgOledDisplay.cpp
index 0682038..bccab18 100644
--- a/src/AgOledDisplay.cpp
+++ b/src/AgOledDisplay.cpp
@@ -316,7 +316,7 @@ void OledDisplay::showDashboard(const char *status) {
int pm25 = round(value.getAverage(Measurements::PM25));
if (utils::isValidPm(pm25)) {
if (config.hasSensorSHT && config.isPMCorrectionEnabled()) {
- pm25 = round(value.getCorrectedPM25(*ag, config, true));
+ pm25 = round(value.getCorrectedPM25(true));
}
if (config.isPmStandardInUSAQI()) {
sprintf(strBuf, "%d", ag->pms5003.convertPm25ToUsAqi(pm25));
@@ -377,7 +377,7 @@ void OledDisplay::showDashboard(const char *status) {
/** Set PM */
int pm25 = round(value.getAverage(Measurements::PM25));
if (config.hasSensorSHT && config.isPMCorrectionEnabled()) {
- pm25 = round(value.getCorrectedPM25(*ag, config, true));
+ pm25 = round(value.getCorrectedPM25(true));
}
ag->display.setCursor(0, 12);
diff --git a/src/AgStateMachine.cpp b/src/AgStateMachine.cpp
index 3656bde..8d1f45d 100644
--- a/src/AgStateMachine.cpp
+++ b/src/AgStateMachine.cpp
@@ -174,7 +174,7 @@ int StateMachine::pm25handleLeds(void) {
int pm25Value = round(value.getAverage(Measurements::PM25));
if (config.hasSensorSHT && config.isPMCorrectionEnabled()) {
- pm25Value = round(value.getCorrectedPM25(*ag, config, true));
+ pm25Value = round(value.getCorrectedPM25(true));
}
if (pm25Value <= 5) {
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index f724d9e..e265c89 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -27,12 +27,14 @@
#define json_prop_noxRaw "noxRaw"
#define json_prop_co2 "rco2"
-Measurements::Measurements() {
+Measurements::Measurements(Configuration &config) : config(config) {
#ifndef ESP8266
_resetReason = (int)ESP_RST_UNKNOWN;
#endif
}
+void Measurements::setAirGradient(AirGradient *ag) { this->ag = ag; }
+
void Measurements::maxPeriod(MeasurementType type, int max) {
switch (type) {
case Temperature:
@@ -535,8 +537,7 @@ void Measurements::validateChannel(int ch) {
}
}
-float Measurements::getCorrectedTempHum(AirGradient &ag, Configuration &config,
- MeasurementType type, int ch, bool forceCorrection) {
+float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool forceCorrection) {
// Sanity check to validate channel, assert if invalid
validateChannel(ch);
@@ -553,7 +554,7 @@ float Measurements::getCorrectedTempHum(AirGradient &ag, Configuration &config,
Configuration::TempHumCorrection tmp = config.getTempCorrection();
if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
- return ag.pms5003t_1.compensateTemp(rawValue);
+ return ag->pms5003t_1.compensateTemp(rawValue);
}
correction.algorithm = tmp.algorithm;
@@ -566,7 +567,7 @@ float Measurements::getCorrectedTempHum(AirGradient &ag, Configuration &config,
Configuration::TempHumCorrection tmp = config.getHumCorrection();
if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
- return ag.pms5003t_1.compensateHum(rawValue);
+ return ag->pms5003t_1.compensateHum(rawValue);
}
correction.algorithm = tmp.algorithm;
@@ -592,7 +593,7 @@ float Measurements::getCorrectedTempHum(AirGradient &ag, Configuration &config,
return corrected;
}
-float Measurements::getCorrectedPM25(AirGradient &ag, Configuration &config, bool useAvg, int ch) {
+float Measurements::getCorrectedPM25(bool useAvg, int ch) {
float pm25;
float corrected;
float humidity;
@@ -617,15 +618,15 @@ float Measurements::getCorrectedPM25(AirGradient &ag, Configuration &config, boo
corrected = pm25;
break;
case PMCorrectionAlgorithm::EPA_2021:
- corrected = ag.pms5003.compensate(pm25, humidity);
+ corrected = ag->pms5003.compensate(pm25, humidity);
break;
default: {
// All SLR correction using the same flow, hence default condition
- corrected = ag.pms5003.slrCorrection(pm25, pm003Count, pmCorrection.scalingFactor,
- pmCorrection.intercept);
+ corrected = ag->pms5003.slrCorrection(pm25, pm003Count, pmCorrection.scalingFactor,
+ pmCorrection.intercept);
if (pmCorrection.useEPA) {
// Add EPA compensation on top of SLR
- corrected = ag.pms5003.compensate(corrected, humidity);
+ corrected = ag->pms5003.compensate(corrected, humidity);
}
}
}
@@ -633,34 +634,33 @@ float Measurements::getCorrectedPM25(AirGradient &ag, Configuration &config, boo
return corrected;
}
-String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, AirGradient &ag,
- Configuration &config) {
+String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi) {
JSONVar root;
- if (ag.isOne() || (ag.isPro4_2()) || ag.isPro3_3() || ag.isBasic()) {
- root = buildIndoor(localServer, ag, config);
+ if (ag->isOne() || (ag->isPro4_2()) || ag->isPro3_3() || ag->isBasic()) {
+ root = buildIndoor(localServer);
} else {
- root = buildOutdoor(localServer, fwMode, ag, config);
+ root = buildOutdoor(localServer, fwMode);
}
// CO2
if (config.hasSensorS8 && utils::isValidCO2(_co2.update.avg)) {
- root[json_prop_co2] = ag.round2(_co2.update.avg);
+ root[json_prop_co2] = ag->round2(_co2.update.avg);
}
/// TVOx and NOx
if (config.hasSensorSGP) {
if (utils::isValidVOC(_tvoc.update.avg)) {
- root[json_prop_tvoc] = ag.round2(_tvoc.update.avg);
+ root[json_prop_tvoc] = ag->round2(_tvoc.update.avg);
}
if (utils::isValidVOC(_tvoc_raw.update.avg)) {
- root[json_prop_tvocRaw] = ag.round2(_tvoc_raw.update.avg);
+ root[json_prop_tvocRaw] = ag->round2(_tvoc_raw.update.avg);
}
if (utils::isValidNOx(_nox.update.avg)) {
- root[json_prop_nox] = ag.round2(_nox.update.avg);
+ root[json_prop_nox] = ag->round2(_nox.update.avg);
}
if (utils::isValidNOx(_nox_raw.update.avg)) {
- root[json_prop_noxRaw] = ag.round2(_nox_raw.update.avg);
+ root[json_prop_noxRaw] = ag->round2(_nox_raw.update.avg);
}
}
@@ -669,11 +669,11 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
root["wifi"] = rssi;
if (localServer) {
- if (ag.isOne()) {
+ if (ag->isOne()) {
root["ledMode"] = config.getLedBarModeName();
}
- root["serialno"] = ag.deviceId();
- root["firmware"] = ag.getVersion();
+ root["serialno"] = ag->deviceId();
+ root["firmware"] = ag->getVersion();
root["model"] = AgFirmwareModeName(fwMode);
} else {
#ifndef ESP8266
@@ -687,8 +687,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
return result;
}
-JSONVar Measurements::buildOutdoor(bool localServer, AgFirmwareMode fwMode, AirGradient &ag,
- Configuration &config) {
+JSONVar Measurements::buildOutdoor(bool localServer, AgFirmwareMode fwMode) {
JSONVar outdoor;
if (fwMode == FW_MODE_O_1P || fwMode == FW_MODE_O_1PS || fwMode == FW_MODE_O_1PST) {
// buildPMS params:
@@ -697,14 +696,16 @@ JSONVar Measurements::buildOutdoor(bool localServer, AgFirmwareMode fwMode, AirG
/// compensated values if requested by local server
/// Set ch based on hasSensorPMSx
if (config.hasSensorPMS1) {
- outdoor = buildPMS(ag, 1, false, true, localServer);
+ outdoor = buildPMS(1, false, true, localServer);
if (!localServer) {
- outdoor[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag.pms5003t_1.getFirmwareVersion());
+ outdoor[json_prop_pmFirmware] =
+ pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
}
} else {
- outdoor = buildPMS(ag, 2, false, true, localServer);
+ outdoor = buildPMS(2, false, true, localServer);
if (!localServer) {
- outdoor[json_prop_pmFirmware] = pms5003TFirmwareVersion(ag.pms5003t_2.getFirmwareVersion());
+ outdoor[json_prop_pmFirmware] =
+ pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
}
}
} else {
@@ -713,20 +714,20 @@ JSONVar Measurements::buildOutdoor(bool localServer, AgFirmwareMode fwMode, AirG
/// Have 2 PMS sensor, allCh is set to true (ch params ignored)
/// Enable temp hum from PMS
/// compensated values if requested by local server
- outdoor = buildPMS(ag, 1, true, true, localServer);
+ outdoor = buildPMS(1, true, true, localServer);
// PMS5003T version
if (!localServer) {
outdoor["channels"]["1"][json_prop_pmFirmware] =
- pms5003TFirmwareVersion(ag.pms5003t_1.getFirmwareVersion());
+ pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
outdoor["channels"]["2"][json_prop_pmFirmware] =
- pms5003TFirmwareVersion(ag.pms5003t_2.getFirmwareVersion());
+ pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
}
}
return outdoor;
}
-JSONVar Measurements::buildIndoor(bool localServer, AirGradient &ag, Configuration &config) {
+JSONVar Measurements::buildIndoor(bool localServer) {
JSONVar indoor;
if (config.hasSensorPMS1) {
@@ -734,26 +735,26 @@ JSONVar Measurements::buildIndoor(bool localServer, AirGradient &ag, Configurati
/// PMS channel 1 (indoor only have 1 PMS; hence allCh false)
/// Not include temperature and humidity from PMS sensor
/// Not include compensated calculation
- indoor = buildPMS(ag, 1, false, false, false);
+ indoor = buildPMS(1, false, false, false);
if (!localServer) {
// Indoor is using PMS5003
- indoor[json_prop_pmFirmware] = this->pms5003FirmwareVersion(ag.pms5003.getFirmwareVersion());
+ indoor[json_prop_pmFirmware] = this->pms5003FirmwareVersion(ag->pms5003.getFirmwareVersion());
}
}
if (config.hasSensorSHT) {
// Add temperature
if (utils::isValidTemperature(_temperature[0].update.avg)) {
- indoor[json_prop_temp] = ag.round2(_temperature[0].update.avg);
+ indoor[json_prop_temp] = ag->round2(_temperature[0].update.avg);
if (localServer) {
- indoor[json_prop_tempCompensated] = ag.round2(_temperature[0].update.avg);
+ indoor[json_prop_tempCompensated] = ag->round2(_temperature[0].update.avg);
}
}
// Add humidity
if (utils::isValidHumidity(_humidity[0].update.avg)) {
- indoor[json_prop_rhum] = ag.round2(_humidity[0].update.avg);
+ indoor[json_prop_rhum] = ag->round2(_humidity[0].update.avg);
if (localServer) {
- indoor[json_prop_rhumCompensated] = ag.round2(_humidity[0].update.avg);
+ indoor[json_prop_rhumCompensated] = ag->round2(_humidity[0].update.avg);
}
}
}
@@ -762,16 +763,15 @@ JSONVar Measurements::buildIndoor(bool localServer, AirGradient &ag, Configurati
if (config.hasSensorPMS1 && utils::isValidPm(_pm_25[0].update.avg)) {
if (config.hasSensorSHT && utils::isValidHumidity(_humidity[0].update.avg)) {
// Correction using moving average value
- float tmp = getCorrectedPM25(ag, config, true);
- indoor[json_prop_pm25Compensated] = ag.round2(tmp);
+ float tmp = getCorrectedPM25(true);
+ indoor[json_prop_pm25Compensated] = ag->round2(tmp);
}
}
return indoor;
}
-JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTempHum,
- bool compensate) {
+JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compensate) {
JSONVar pms;
// When only one of the channel
@@ -783,47 +783,47 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
ch = ch - 1;
if (utils::isValidPm(_pm_01[ch].update.avg)) {
- pms[json_prop_pm01Ae] = ag.round2(_pm_01[ch].update.avg);
+ pms[json_prop_pm01Ae] = ag->round2(_pm_01[ch].update.avg);
}
if (utils::isValidPm(_pm_25[ch].update.avg)) {
- pms[json_prop_pm25Ae] = ag.round2(_pm_25[ch].update.avg);
+ pms[json_prop_pm25Ae] = ag->round2(_pm_25[ch].update.avg);
}
if (utils::isValidPm(_pm_10[ch].update.avg)) {
- pms[json_prop_pm10Ae] = ag.round2(_pm_10[ch].update.avg);
+ pms[json_prop_pm10Ae] = ag->round2(_pm_10[ch].update.avg);
}
if (utils::isValidPm(_pm_01_sp[ch].update.avg)) {
- pms[json_prop_pm01Sp] = ag.round2(_pm_01_sp[ch].update.avg);
+ pms[json_prop_pm01Sp] = ag->round2(_pm_01_sp[ch].update.avg);
}
if (utils::isValidPm(_pm_25_sp[ch].update.avg)) {
- pms[json_prop_pm25Sp] = ag.round2(_pm_25_sp[ch].update.avg);
+ pms[json_prop_pm25Sp] = ag->round2(_pm_25_sp[ch].update.avg);
}
if (utils::isValidPm(_pm_10_sp[ch].update.avg)) {
- pms[json_prop_pm10Sp] = ag.round2(_pm_10_sp[ch].update.avg);
+ pms[json_prop_pm10Sp] = ag->round2(_pm_10_sp[ch].update.avg);
}
if (utils::isValidPm03Count(_pm_03_pc[ch].update.avg)) {
- pms[json_prop_pm03Count] = ag.round2(_pm_03_pc[ch].update.avg);
+ pms[json_prop_pm03Count] = ag->round2(_pm_03_pc[ch].update.avg);
}
if (utils::isValidPm03Count(_pm_05_pc[ch].update.avg)) {
- pms[json_prop_pm05Count] = ag.round2(_pm_05_pc[ch].update.avg);
+ pms[json_prop_pm05Count] = ag->round2(_pm_05_pc[ch].update.avg);
}
if (utils::isValidPm03Count(_pm_01_pc[ch].update.avg)) {
- pms[json_prop_pm1Count] = ag.round2(_pm_01_pc[ch].update.avg);
+ pms[json_prop_pm1Count] = ag->round2(_pm_01_pc[ch].update.avg);
}
if (utils::isValidPm03Count(_pm_25_pc[ch].update.avg)) {
- pms[json_prop_pm25Count] = ag.round2(_pm_25_pc[ch].update.avg);
+ pms[json_prop_pm25Count] = ag->round2(_pm_25_pc[ch].update.avg);
}
if (_pm_5_pc[ch].listValues.empty() == false) {
// Only include pm5.0 count when values available on its list
// If not, means no pm5_pc available from the sensor
if (utils::isValidPm03Count(_pm_5_pc[ch].update.avg)) {
- pms[json_prop_pm5Count] = ag.round2(_pm_5_pc[ch].update.avg);
+ pms[json_prop_pm5Count] = ag->round2(_pm_5_pc[ch].update.avg);
}
}
if (_pm_10_pc[ch].listValues.empty() == false) {
// Only include pm10 count when values available on its list
// If not, means no pm10_pc available from the sensor
if (utils::isValidPm03Count(_pm_10_pc[ch].update.avg)) {
- pms[json_prop_pm10Count] = ag.round2(_pm_10_pc[ch].update.avg);
+ pms[json_prop_pm10Count] = ag->round2(_pm_10_pc[ch].update.avg);
}
}
@@ -831,23 +831,23 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
float _vc;
// Set temperature if valid
if (utils::isValidTemperature(_temperature[ch].update.avg)) {
- pms[json_prop_temp] = ag.round2(_temperature[ch].update.avg);
+ pms[json_prop_temp] = ag->round2(_temperature[ch].update.avg);
// Compensate temperature when flag is set
if (compensate) {
- _vc = ag.pms5003t_1.compensateTemp(_temperature[ch].update.avg);
+ _vc = ag->pms5003t_1.compensateTemp(_temperature[ch].update.avg);
if (utils::isValidTemperature(_vc)) {
- pms[json_prop_tempCompensated] = ag.round2(_vc);
+ pms[json_prop_tempCompensated] = ag->round2(_vc);
}
}
}
// Set humidity if valid
if (utils::isValidHumidity(_humidity[ch].update.avg)) {
- pms[json_prop_rhum] = ag.round2(_humidity[ch].update.avg);
+ pms[json_prop_rhum] = ag->round2(_humidity[ch].update.avg);
// Compensate relative humidity when flag is set
if (compensate) {
- _vc = ag.pms5003t_1.compensateHum(_humidity[ch].update.avg);
+ _vc = ag->pms5003t_1.compensateHum(_humidity[ch].update.avg);
if (utils::isValidTemperature(_vc)) {
- pms[json_prop_rhumCompensated] = ag.round2(_vc);
+ pms[json_prop_rhumCompensated] = ag->round2(_vc);
}
}
}
@@ -858,9 +858,9 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
utils::isValidHumidity(_humidity[ch].update.avg)) {
// Note: the pms5003t object is not matter either for channel 1 or 2, compensate points to
// the same base function
- float pm25 = ag.pms5003t_1.compensate(_pm_25[ch].update.avg, _humidity[ch].update.avg);
+ float pm25 = ag->pms5003t_1.compensate(_pm_25[ch].update.avg, _humidity[ch].update.avg);
if (utils::isValidPm(pm25)) {
- pms[json_prop_pm25Compensated] = ag.round2(pm25);
+ pms[json_prop_pm25Compensated] = ag->round2(pm25);
}
}
}
@@ -876,144 +876,144 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
/// PM1.0 atmospheric environment
if (utils::isValidPm(_pm_01[0].update.avg) && utils::isValidPm(_pm_01[1].update.avg)) {
float avg = (_pm_01[0].update.avg + _pm_01[1].update.avg) / 2.0f;
- pms[json_prop_pm01Ae] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm01Ae] = ag.round2(_pm_01[0].update.avg);
- pms["channels"]["2"][json_prop_pm01Ae] = ag.round2(_pm_01[1].update.avg);
+ pms[json_prop_pm01Ae] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm01Ae] = ag->round2(_pm_01[0].update.avg);
+ pms["channels"]["2"][json_prop_pm01Ae] = ag->round2(_pm_01[1].update.avg);
} else if (utils::isValidPm(_pm_01[0].update.avg)) {
- pms[json_prop_pm01Ae] = ag.round2(_pm_01[0].update.avg);
- pms["channels"]["1"][json_prop_pm01Ae] = ag.round2(_pm_01[0].update.avg);
+ pms[json_prop_pm01Ae] = ag->round2(_pm_01[0].update.avg);
+ pms["channels"]["1"][json_prop_pm01Ae] = ag->round2(_pm_01[0].update.avg);
} else if (utils::isValidPm(_pm_01[1].update.avg)) {
- pms[json_prop_pm01Ae] = ag.round2(_pm_01[1].update.avg);
- pms["channels"]["2"][json_prop_pm01Ae] = ag.round2(_pm_01[1].update.avg);
+ pms[json_prop_pm01Ae] = ag->round2(_pm_01[1].update.avg);
+ pms["channels"]["2"][json_prop_pm01Ae] = ag->round2(_pm_01[1].update.avg);
}
/// PM2.5 atmospheric environment
if (utils::isValidPm(_pm_25[0].update.avg) && utils::isValidPm(_pm_25[1].update.avg)) {
float avg = (_pm_25[0].update.avg + _pm_25[1].update.avg) / 2.0f;
- pms[json_prop_pm25Ae] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm25Ae] = ag.round2(_pm_25[0].update.avg);
- pms["channels"]["2"][json_prop_pm25Ae] = ag.round2(_pm_25[1].update.avg);
+ pms[json_prop_pm25Ae] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm25Ae] = ag->round2(_pm_25[0].update.avg);
+ pms["channels"]["2"][json_prop_pm25Ae] = ag->round2(_pm_25[1].update.avg);
} else if (utils::isValidPm(_pm_25[0].update.avg)) {
- pms[json_prop_pm25Ae] = ag.round2(_pm_25[0].update.avg);
- pms["channels"]["1"][json_prop_pm25Ae] = ag.round2(_pm_25[0].update.avg);
+ pms[json_prop_pm25Ae] = ag->round2(_pm_25[0].update.avg);
+ pms["channels"]["1"][json_prop_pm25Ae] = ag->round2(_pm_25[0].update.avg);
} else if (utils::isValidPm(_pm_25[1].update.avg)) {
- pms[json_prop_pm25Ae] = ag.round2(_pm_25[1].update.avg);
- pms["channels"]["2"][json_prop_pm25Ae] = ag.round2(_pm_25[1].update.avg);
+ pms[json_prop_pm25Ae] = ag->round2(_pm_25[1].update.avg);
+ pms["channels"]["2"][json_prop_pm25Ae] = ag->round2(_pm_25[1].update.avg);
}
/// PM10 atmospheric environment
if (utils::isValidPm(_pm_10[0].update.avg) && utils::isValidPm(_pm_10[1].update.avg)) {
float avg = (_pm_10[0].update.avg + _pm_10[1].update.avg) / 2.0f;
- pms[json_prop_pm10Ae] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm10Ae] = ag.round2(_pm_10[0].update.avg);
- pms["channels"]["2"][json_prop_pm10Ae] = ag.round2(_pm_10[1].update.avg);
+ pms[json_prop_pm10Ae] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm10Ae] = ag->round2(_pm_10[0].update.avg);
+ pms["channels"]["2"][json_prop_pm10Ae] = ag->round2(_pm_10[1].update.avg);
} else if (utils::isValidPm(_pm_10[0].update.avg)) {
- pms[json_prop_pm10Ae] = ag.round2(_pm_10[0].update.avg);
- pms["channels"]["1"][json_prop_pm10Ae] = ag.round2(_pm_10[0].update.avg);
+ pms[json_prop_pm10Ae] = ag->round2(_pm_10[0].update.avg);
+ pms["channels"]["1"][json_prop_pm10Ae] = ag->round2(_pm_10[0].update.avg);
} else if (utils::isValidPm(_pm_10[1].update.avg)) {
- pms[json_prop_pm10Ae] = ag.round2(_pm_10[1].update.avg);
- pms["channels"]["2"][json_prop_pm10Ae] = ag.round2(_pm_10[1].update.avg);
+ pms[json_prop_pm10Ae] = ag->round2(_pm_10[1].update.avg);
+ pms["channels"]["2"][json_prop_pm10Ae] = ag->round2(_pm_10[1].update.avg);
}
/// PM1.0 standard particle
if (utils::isValidPm(_pm_01_sp[0].update.avg) && utils::isValidPm(_pm_01_sp[1].update.avg)) {
float avg = (_pm_01_sp[0].update.avg + _pm_01_sp[1].update.avg) / 2.0f;
- pms[json_prop_pm01Sp] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm01Sp] = ag.round2(_pm_01_sp[0].update.avg);
- pms["channels"]["2"][json_prop_pm01Sp] = ag.round2(_pm_01_sp[1].update.avg);
+ pms[json_prop_pm01Sp] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm01Sp] = ag->round2(_pm_01_sp[0].update.avg);
+ pms["channels"]["2"][json_prop_pm01Sp] = ag->round2(_pm_01_sp[1].update.avg);
} else if (utils::isValidPm(_pm_01_sp[0].update.avg)) {
- pms[json_prop_pm01Sp] = ag.round2(_pm_01_sp[0].update.avg);
- pms["channels"]["1"][json_prop_pm01Sp] = ag.round2(_pm_01_sp[0].update.avg);
+ pms[json_prop_pm01Sp] = ag->round2(_pm_01_sp[0].update.avg);
+ pms["channels"]["1"][json_prop_pm01Sp] = ag->round2(_pm_01_sp[0].update.avg);
} else if (utils::isValidPm(_pm_01_sp[1].update.avg)) {
- pms[json_prop_pm01Sp] = ag.round2(_pm_01_sp[1].update.avg);
- pms["channels"]["2"][json_prop_pm01Sp] = ag.round2(_pm_01_sp[1].update.avg);
+ pms[json_prop_pm01Sp] = ag->round2(_pm_01_sp[1].update.avg);
+ pms["channels"]["2"][json_prop_pm01Sp] = ag->round2(_pm_01_sp[1].update.avg);
}
/// PM2.5 standard particle
if (utils::isValidPm(_pm_25_sp[0].update.avg) && utils::isValidPm(_pm_25_sp[1].update.avg)) {
float avg = (_pm_25_sp[0].update.avg + _pm_25_sp[1].update.avg) / 2.0f;
- pms[json_prop_pm25Sp] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm25Sp] = ag.round2(_pm_25_sp[0].update.avg);
- pms["channels"]["2"][json_prop_pm25Sp] = ag.round2(_pm_25_sp[1].update.avg);
+ pms[json_prop_pm25Sp] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm25Sp] = ag->round2(_pm_25_sp[0].update.avg);
+ pms["channels"]["2"][json_prop_pm25Sp] = ag->round2(_pm_25_sp[1].update.avg);
} else if (utils::isValidPm(_pm_25_sp[0].update.avg)) {
- pms[json_prop_pm25Sp] = ag.round2(_pm_25_sp[0].update.avg);
- pms["channels"]["1"][json_prop_pm25Sp] = ag.round2(_pm_25_sp[0].update.avg);
+ pms[json_prop_pm25Sp] = ag->round2(_pm_25_sp[0].update.avg);
+ pms["channels"]["1"][json_prop_pm25Sp] = ag->round2(_pm_25_sp[0].update.avg);
} else if (utils::isValidPm(_pm_25_sp[1].update.avg)) {
- pms[json_prop_pm25Sp] = ag.round2(_pm_25_sp[1].update.avg);
- pms["channels"]["2"][json_prop_pm25Sp] = ag.round2(_pm_25_sp[1].update.avg);
+ pms[json_prop_pm25Sp] = ag->round2(_pm_25_sp[1].update.avg);
+ pms["channels"]["2"][json_prop_pm25Sp] = ag->round2(_pm_25_sp[1].update.avg);
}
/// PM10 standard particle
if (utils::isValidPm(_pm_10_sp[0].update.avg) && utils::isValidPm(_pm_10_sp[1].update.avg)) {
float avg = (_pm_10_sp[0].update.avg + _pm_10_sp[1].update.avg) / 2.0f;
- pms[json_prop_pm10Sp] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm10Sp] = ag.round2(_pm_10_sp[0].update.avg);
- pms["channels"]["2"][json_prop_pm10Sp] = ag.round2(_pm_10_sp[1].update.avg);
+ pms[json_prop_pm10Sp] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm10Sp] = ag->round2(_pm_10_sp[0].update.avg);
+ pms["channels"]["2"][json_prop_pm10Sp] = ag->round2(_pm_10_sp[1].update.avg);
} else if (utils::isValidPm(_pm_10_sp[0].update.avg)) {
- pms[json_prop_pm10Sp] = ag.round2(_pm_10_sp[0].update.avg);
- pms["channels"]["1"][json_prop_pm10Sp] = ag.round2(_pm_10_sp[0].update.avg);
+ pms[json_prop_pm10Sp] = ag->round2(_pm_10_sp[0].update.avg);
+ pms["channels"]["1"][json_prop_pm10Sp] = ag->round2(_pm_10_sp[0].update.avg);
} else if (utils::isValidPm(_pm_10_sp[1].update.avg)) {
- pms[json_prop_pm10Sp] = ag.round2(_pm_10_sp[1].update.avg);
- pms["channels"]["2"][json_prop_pm10Sp] = ag.round2(_pm_10_sp[1].update.avg);
+ pms[json_prop_pm10Sp] = ag->round2(_pm_10_sp[1].update.avg);
+ pms["channels"]["2"][json_prop_pm10Sp] = ag->round2(_pm_10_sp[1].update.avg);
}
/// PM003 particle count
if (utils::isValidPm03Count(_pm_03_pc[0].update.avg) &&
utils::isValidPm03Count(_pm_03_pc[1].update.avg)) {
float avg = (_pm_03_pc[0].update.avg + _pm_03_pc[1].update.avg) / 2.0f;
- pms[json_prop_pm03Count] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm03Count] = ag.round2(_pm_03_pc[0].update.avg);
- pms["channels"]["2"][json_prop_pm03Count] = ag.round2(_pm_03_pc[1].update.avg);
+ pms[json_prop_pm03Count] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm03Count] = ag->round2(_pm_03_pc[0].update.avg);
+ pms["channels"]["2"][json_prop_pm03Count] = ag->round2(_pm_03_pc[1].update.avg);
} else if (utils::isValidPm03Count(_pm_03_pc[0].update.avg)) {
- pms[json_prop_pm03Count] = ag.round2(_pm_03_pc[0].update.avg);
- pms["channels"]["1"][json_prop_pm03Count] = ag.round2(_pm_03_pc[0].update.avg);
+ pms[json_prop_pm03Count] = ag->round2(_pm_03_pc[0].update.avg);
+ pms["channels"]["1"][json_prop_pm03Count] = ag->round2(_pm_03_pc[0].update.avg);
} else if (utils::isValidPm03Count(_pm_03_pc[1].update.avg)) {
- pms[json_prop_pm03Count] = ag.round2(_pm_03_pc[1].update.avg);
- pms["channels"]["2"][json_prop_pm03Count] = ag.round2(_pm_03_pc[1].update.avg);
+ pms[json_prop_pm03Count] = ag->round2(_pm_03_pc[1].update.avg);
+ pms["channels"]["2"][json_prop_pm03Count] = ag->round2(_pm_03_pc[1].update.avg);
}
/// PM0.5 particle count
if (utils::isValidPm03Count(_pm_05_pc[0].update.avg) &&
utils::isValidPm03Count(_pm_05_pc[1].update.avg)) {
float avg = (_pm_05_pc[0].update.avg + _pm_05_pc[1].update.avg) / 2.0f;
- pms[json_prop_pm05Count] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm05Count] = ag.round2(_pm_05_pc[0].update.avg);
- pms["channels"]["2"][json_prop_pm05Count] = ag.round2(_pm_05_pc[1].update.avg);
+ pms[json_prop_pm05Count] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm05Count] = ag->round2(_pm_05_pc[0].update.avg);
+ pms["channels"]["2"][json_prop_pm05Count] = ag->round2(_pm_05_pc[1].update.avg);
} else if (utils::isValidPm03Count(_pm_05_pc[0].update.avg)) {
- pms[json_prop_pm05Count] = ag.round2(_pm_05_pc[0].update.avg);
- pms["channels"]["1"][json_prop_pm05Count] = ag.round2(_pm_05_pc[0].update.avg);
+ pms[json_prop_pm05Count] = ag->round2(_pm_05_pc[0].update.avg);
+ pms["channels"]["1"][json_prop_pm05Count] = ag->round2(_pm_05_pc[0].update.avg);
} else if (utils::isValidPm03Count(_pm_05_pc[1].update.avg)) {
- pms[json_prop_pm05Count] = ag.round2(_pm_05_pc[1].update.avg);
- pms["channels"]["2"][json_prop_pm05Count] = ag.round2(_pm_05_pc[1].update.avg);
+ pms[json_prop_pm05Count] = ag->round2(_pm_05_pc[1].update.avg);
+ pms["channels"]["2"][json_prop_pm05Count] = ag->round2(_pm_05_pc[1].update.avg);
}
/// PM1.0 particle count
if (utils::isValidPm03Count(_pm_01_pc[0].update.avg) &&
utils::isValidPm03Count(_pm_01_pc[1].update.avg)) {
float avg = (_pm_01_pc[0].update.avg + _pm_01_pc[1].update.avg) / 2.0f;
- pms[json_prop_pm1Count] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm1Count] = ag.round2(_pm_01_pc[0].update.avg);
- pms["channels"]["2"][json_prop_pm1Count] = ag.round2(_pm_01_pc[1].update.avg);
+ pms[json_prop_pm1Count] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm1Count] = ag->round2(_pm_01_pc[0].update.avg);
+ pms["channels"]["2"][json_prop_pm1Count] = ag->round2(_pm_01_pc[1].update.avg);
} else if (utils::isValidPm03Count(_pm_01_pc[0].update.avg)) {
- pms[json_prop_pm1Count] = ag.round2(_pm_01_pc[0].update.avg);
- pms["channels"]["1"][json_prop_pm1Count] = ag.round2(_pm_01_pc[0].update.avg);
+ pms[json_prop_pm1Count] = ag->round2(_pm_01_pc[0].update.avg);
+ pms["channels"]["1"][json_prop_pm1Count] = ag->round2(_pm_01_pc[0].update.avg);
} else if (utils::isValidPm03Count(_pm_01_pc[1].update.avg)) {
- pms[json_prop_pm1Count] = ag.round2(_pm_01_pc[1].update.avg);
- pms["channels"]["2"][json_prop_pm1Count] = ag.round2(_pm_01_pc[1].update.avg);
+ pms[json_prop_pm1Count] = ag->round2(_pm_01_pc[1].update.avg);
+ pms["channels"]["2"][json_prop_pm1Count] = ag->round2(_pm_01_pc[1].update.avg);
}
/// PM2.5 particle count
if (utils::isValidPm03Count(_pm_25_pc[0].update.avg) &&
utils::isValidPm03Count(_pm_25_pc[1].update.avg)) {
float avg = (_pm_25_pc[0].update.avg + _pm_25_pc[1].update.avg) / 2.0f;
- pms[json_prop_pm25Count] = ag.round2(avg);
- pms["channels"]["1"][json_prop_pm25Count] = ag.round2(_pm_25_pc[0].update.avg);
- pms["channels"]["2"][json_prop_pm25Count] = ag.round2(_pm_25_pc[1].update.avg);
+ pms[json_prop_pm25Count] = ag->round2(avg);
+ pms["channels"]["1"][json_prop_pm25Count] = ag->round2(_pm_25_pc[0].update.avg);
+ pms["channels"]["2"][json_prop_pm25Count] = ag->round2(_pm_25_pc[1].update.avg);
} else if (utils::isValidPm03Count(_pm_25_pc[0].update.avg)) {
- pms[json_prop_pm25Count] = ag.round2(_pm_25_pc[0].update.avg);
- pms["channels"]["1"][json_prop_pm25Count] = ag.round2(_pm_25_pc[0].update.avg);
+ pms[json_prop_pm25Count] = ag->round2(_pm_25_pc[0].update.avg);
+ pms["channels"]["1"][json_prop_pm25Count] = ag->round2(_pm_25_pc[0].update.avg);
} else if (utils::isValidPm03Count(_pm_25_pc[1].update.avg)) {
- pms[json_prop_pm25Count] = ag.round2(_pm_25_pc[1].update.avg);
- pms["channels"]["2"][json_prop_pm25Count] = ag.round2(_pm_25_pc[1].update.avg);
+ pms[json_prop_pm25Count] = ag->round2(_pm_25_pc[1].update.avg);
+ pms["channels"]["2"][json_prop_pm25Count] = ag->round2(_pm_25_pc[1].update.avg);
}
// NOTE: No need for particle count 5.0 and 10. When allCh is true, basically monitor using
@@ -1025,40 +1025,40 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
utils::isValidTemperature(_temperature[1].update.avg)) {
float temperature = (_temperature[0].update.avg + _temperature[1].update.avg) / 2.0f;
- pms[json_prop_temp] = ag.round2(temperature);
- pms["channels"]["1"][json_prop_temp] = ag.round2(_temperature[0].update.avg);
- pms["channels"]["2"][json_prop_temp] = ag.round2(_temperature[1].update.avg);
+ pms[json_prop_temp] = ag->round2(temperature);
+ pms["channels"]["1"][json_prop_temp] = ag->round2(_temperature[0].update.avg);
+ pms["channels"]["2"][json_prop_temp] = ag->round2(_temperature[1].update.avg);
if (compensate) {
// Compensate both temperature channel
- float temp = ag.pms5003t_1.compensateTemp(temperature);
- float temp1 = ag.pms5003t_1.compensateTemp(_temperature[0].update.avg);
- float temp2 = ag.pms5003t_2.compensateTemp(_temperature[1].update.avg);
- pms[json_prop_tempCompensated] = ag.round2(temp);
- pms["channels"]["1"][json_prop_tempCompensated] = ag.round2(temp1);
- pms["channels"]["2"][json_prop_tempCompensated] = ag.round2(temp2);
+ float temp = ag->pms5003t_1.compensateTemp(temperature);
+ float temp1 = ag->pms5003t_1.compensateTemp(_temperature[0].update.avg);
+ float temp2 = ag->pms5003t_2.compensateTemp(_temperature[1].update.avg);
+ pms[json_prop_tempCompensated] = ag->round2(temp);
+ pms["channels"]["1"][json_prop_tempCompensated] = ag->round2(temp1);
+ pms["channels"]["2"][json_prop_tempCompensated] = ag->round2(temp2);
}
} else if (utils::isValidTemperature(_temperature[0].update.avg)) {
- pms[json_prop_temp] = ag.round2(_temperature[0].update.avg);
- pms["channels"]["1"][json_prop_temp] = ag.round2(_temperature[0].update.avg);
+ pms[json_prop_temp] = ag->round2(_temperature[0].update.avg);
+ pms["channels"]["1"][json_prop_temp] = ag->round2(_temperature[0].update.avg);
if (compensate) {
// Compensate channel 1
- float temp1 = ag.pms5003t_1.compensateTemp(_temperature[0].update.avg);
- pms[json_prop_tempCompensated] = ag.round2(temp1);
- pms["channels"]["1"][json_prop_tempCompensated] = ag.round2(temp1);
+ float temp1 = ag->pms5003t_1.compensateTemp(_temperature[0].update.avg);
+ pms[json_prop_tempCompensated] = ag->round2(temp1);
+ pms["channels"]["1"][json_prop_tempCompensated] = ag->round2(temp1);
}
} else if (utils::isValidTemperature(_temperature[1].update.avg)) {
- pms[json_prop_temp] = ag.round2(_temperature[1].update.avg);
- pms["channels"]["2"][json_prop_temp] = ag.round2(_temperature[1].update.avg);
+ pms[json_prop_temp] = ag->round2(_temperature[1].update.avg);
+ pms["channels"]["2"][json_prop_temp] = ag->round2(_temperature[1].update.avg);
if (compensate) {
// Compensate channel 2
- float temp2 = ag.pms5003t_2.compensateTemp(_temperature[1].update.avg);
- pms[json_prop_tempCompensated] = ag.round2(temp2);
- pms["channels"]["2"][json_prop_tempCompensated] = ag.round2(temp2);
+ float temp2 = ag->pms5003t_2.compensateTemp(_temperature[1].update.avg);
+ pms[json_prop_tempCompensated] = ag->round2(temp2);
+ pms["channels"]["2"][json_prop_tempCompensated] = ag->round2(temp2);
}
}
@@ -1066,40 +1066,40 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
if (utils::isValidHumidity(_humidity[0].update.avg) &&
utils::isValidHumidity(_humidity[1].update.avg)) {
float humidity = (_humidity[0].update.avg + _humidity[1].update.avg) / 2.0f;
- pms[json_prop_rhum] = ag.round2(humidity);
- pms["channels"]["1"][json_prop_rhum] = ag.round2(_humidity[0].update.avg);
- pms["channels"]["2"][json_prop_rhum] = ag.round2(_humidity[1].update.avg);
+ pms[json_prop_rhum] = ag->round2(humidity);
+ pms["channels"]["1"][json_prop_rhum] = ag->round2(_humidity[0].update.avg);
+ pms["channels"]["2"][json_prop_rhum] = ag->round2(_humidity[1].update.avg);
if (compensate) {
// Compensate both humidity channel
- float hum = ag.pms5003t_1.compensateHum(humidity);
- float hum1 = ag.pms5003t_1.compensateHum(_humidity[0].update.avg);
- float hum2 = ag.pms5003t_2.compensateHum(_humidity[1].update.avg);
- pms[json_prop_rhumCompensated] = ag.round2(hum);
- pms["channels"]["1"][json_prop_rhumCompensated] = ag.round2(hum1);
- pms["channels"]["2"][json_prop_rhumCompensated] = ag.round2(hum2);
+ float hum = ag->pms5003t_1.compensateHum(humidity);
+ float hum1 = ag->pms5003t_1.compensateHum(_humidity[0].update.avg);
+ float hum2 = ag->pms5003t_2.compensateHum(_humidity[1].update.avg);
+ pms[json_prop_rhumCompensated] = ag->round2(hum);
+ pms["channels"]["1"][json_prop_rhumCompensated] = ag->round2(hum1);
+ pms["channels"]["2"][json_prop_rhumCompensated] = ag->round2(hum2);
}
} else if (utils::isValidHumidity(_humidity[0].update.avg)) {
- pms[json_prop_rhum] = ag.round2(_humidity[0].update.avg);
- pms["channels"]["1"][json_prop_rhum] = ag.round2(_humidity[0].update.avg);
+ pms[json_prop_rhum] = ag->round2(_humidity[0].update.avg);
+ pms["channels"]["1"][json_prop_rhum] = ag->round2(_humidity[0].update.avg);
if (compensate) {
// Compensate humidity channel 1
- float hum1 = ag.pms5003t_1.compensateHum(_humidity[0].update.avg);
- pms[json_prop_rhumCompensated] = ag.round2(hum1);
- pms["channels"]["1"][json_prop_rhumCompensated] = ag.round2(hum1);
+ float hum1 = ag->pms5003t_1.compensateHum(_humidity[0].update.avg);
+ pms[json_prop_rhumCompensated] = ag->round2(hum1);
+ pms["channels"]["1"][json_prop_rhumCompensated] = ag->round2(hum1);
}
} else if (utils::isValidHumidity(_humidity[1].update.avg)) {
- pms[json_prop_rhum] = ag.round2(_humidity[1].update.avg);
- pms["channels"]["2"][json_prop_rhum] = ag.round2(_humidity[1].update.avg);
+ pms[json_prop_rhum] = ag->round2(_humidity[1].update.avg);
+ pms["channels"]["2"][json_prop_rhum] = ag->round2(_humidity[1].update.avg);
if (compensate) {
// Compensate humidity channel 2
- float hum2 = ag.pms5003t_2.compensateHum(_humidity[1].update.avg);
- pms[json_prop_rhumCompensated] = ag.round2(hum2);
- pms["channels"]["2"][json_prop_rhumCompensated] = ag.round2(hum2);
+ float hum2 = ag->pms5003t_2.compensateHum(_humidity[1].update.avg);
+ pms[json_prop_rhumCompensated] = ag->round2(hum2);
+ pms["channels"]["2"][json_prop_rhumCompensated] = ag->round2(hum2);
}
}
@@ -1110,22 +1110,22 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem
float pm25_comp2 = utils::getInvalidPmValue();
if (utils::isValidPm(_pm_25[0].update.avg) &&
utils::isValidHumidity(_humidity[0].update.avg)) {
- pm25_comp1 = ag.pms5003t_1.compensate(_pm_25[0].update.avg, _humidity[0].update.avg);
- pms["channels"]["1"][json_prop_pm25Compensated] = ag.round2(pm25_comp1);
+ pm25_comp1 = ag->pms5003t_1.compensate(_pm_25[0].update.avg, _humidity[0].update.avg);
+ pms["channels"]["1"][json_prop_pm25Compensated] = ag->round2(pm25_comp1);
}
if (utils::isValidPm(_pm_25[1].update.avg) &&
utils::isValidHumidity(_humidity[1].update.avg)) {
- pm25_comp2 = ag.pms5003t_2.compensate(_pm_25[1].update.avg, _humidity[1].update.avg);
- pms["channels"]["2"][json_prop_pm25Compensated] = ag.round2(pm25_comp2);
+ pm25_comp2 = ag->pms5003t_2.compensate(_pm_25[1].update.avg, _humidity[1].update.avg);
+ pms["channels"]["2"][json_prop_pm25Compensated] = ag->round2(pm25_comp2);
}
/// Get average or one of the channel compensated value if only one channel is valid
if (utils::isValidPm(pm25_comp1) && utils::isValidPm(pm25_comp2)) {
- pms[json_prop_pm25Compensated] = ag.round2((pm25_comp1 + pm25_comp2) / 2.0f);
+ pms[json_prop_pm25Compensated] = ag->round2((pm25_comp1 + pm25_comp2) / 2.0f);
} else if (utils::isValidPm(pm25_comp1)) {
- pms[json_prop_pm25Compensated] = ag.round2(pm25_comp1);
+ pms[json_prop_pm25Compensated] = ag->round2(pm25_comp1);
} else if (utils::isValidPm(pm25_comp2)) {
- pms[json_prop_pm25Compensated] = ag.round2(pm25_comp2);
+ pms[json_prop_pm25Compensated] = ag->round2(pm25_comp2);
}
}
}
diff --git a/src/AgValue.h b/src/AgValue.h
index 7402e1d..c5bd5e0 100644
--- a/src/AgValue.h
+++ b/src/AgValue.h
@@ -34,9 +34,11 @@ private:
};
public:
- Measurements();
+ Measurements(Configuration &config);
~Measurements() {}
+ void setAirGradient(AirGradient *ag);
+
// Enumeration for every AG measurements
enum MeasurementType {
Temperature,
@@ -123,27 +125,23 @@ public:
*/
float getAverage(MeasurementType type, int ch = 1);
- float getCorrectedTempHum(AirGradient &ag, Configuration &config, MeasurementType type,
- int ch = 1, bool forceCorrection = false);
+ float getCorrectedTempHum(MeasurementType type, int ch = 1, bool forceCorrection = false);
/**
* @brief Get the Corrected PM25 object based on the correction algorithm from configuration
- *
+ *
* If correction is not enabled, then will return the raw value (either average or last value)
*
- * @param ag AirGradient instance
- * @param config Configuration instance
* @param useAvg Use moving average value if true, otherwise use latest value
* @param ch MeasurementType channel
* @return float Corrected PM2.5 value
*/
- float getCorrectedPM25(AirGradient &ag, Configuration &config, bool useAvg = false, int ch = 1);
+ float getCorrectedPM25(bool useAvg = false, int ch = 1);
/**
* build json payload for every measurements
*/
- String toString(bool localServer, AgFirmwareMode fwMode, int rssi, AirGradient &ag,
- Configuration &config);
+ String toString(bool localServer, AgFirmwareMode fwMode, int rssi);
/**
* Set to true if want to debug every update value
@@ -158,6 +156,9 @@ public:
#endif
private:
+ Configuration &config;
+ AirGradient *ag;
+
// Some declared as an array (channel), because FW_MODE_O_1PPx has two PMS5003T
FloatValue _temperature[2];
FloatValue _humidity[2];
@@ -216,10 +217,9 @@ private:
*/
void validateChannel(int ch);
- JSONVar buildOutdoor(bool localServer, AgFirmwareMode fwMode, AirGradient &ag,
- Configuration &config);
- JSONVar buildIndoor(bool localServer, AirGradient &ag, Configuration &config);
- JSONVar buildPMS(AirGradient &ag, int ch, bool allCh, bool withTempHum, bool compensate);
+ JSONVar buildOutdoor(bool localServer, AgFirmwareMode fwMode);
+ JSONVar buildIndoor(bool localServer);
+ JSONVar buildPMS(int ch, bool allCh, bool withTempHum, bool compensate);
};
#endif /** _AG_VALUE_H_ */
From af16c1c06033bb4a196f17b83ff1f55c1629cdbb Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Fri, 24 Jan 2025 09:56:01 +0700
Subject: [PATCH 07/36] Apply temphum correction
---
examples/OneOpenAir/OpenMetrics.cpp | 12 ++++---
src/AgOledDisplay.cpp | 8 ++---
src/AgValue.cpp | 49 ++++++++++++++++-------------
src/AgValue.h | 10 ++++++
4 files changed, 50 insertions(+), 29 deletions(-)
diff --git a/examples/OneOpenAir/OpenMetrics.cpp b/examples/OneOpenAir/OpenMetrics.cpp
index 753f9c7..393025c 100644
--- a/examples/OneOpenAir/OpenMetrics.cpp
+++ b/examples/OneOpenAir/OpenMetrics.cpp
@@ -137,11 +137,15 @@ String OpenMetrics::getPayload(void) {
/** Get temperature and humidity compensated */
if (ag->isOne()) {
- atmpCompensated = _temp;
- ahumCompensated = _hum;
+ atmpCompensated = round(measure.getCorrectedTempHum(Measurements::Temperature));
+ ahumCompensated = round(measure.getCorrectedTempHum(Measurements::Humidity));
} else {
- atmpCompensated = ag->pms5003t_1.compensateTemp(_temp);
- ahumCompensated = ag->pms5003t_1.compensateHum(_hum);
+ atmpCompensated = round((measure.getCorrectedTempHum(Measurements::Temperature, 1) +
+ measure.getCorrectedTempHum(Measurements::Temperature, 2)) /
+ 2.0f);
+ ahumCompensated = round((measure.getCorrectedTempHum(Measurements::Humidity, 1) +
+ measure.getCorrectedTempHum(Measurements::Humidity, 2)) /
+ 2.0f);
}
// Add measurements that valid to the metrics
diff --git a/src/AgOledDisplay.cpp b/src/AgOledDisplay.cpp
index bccab18..840d24f 100644
--- a/src/AgOledDisplay.cpp
+++ b/src/AgOledDisplay.cpp
@@ -12,7 +12,7 @@
*/
void OledDisplay::showTempHum(bool hasStatus, char *buf, int buf_size) {
/** Temperature */
- float temp = value.getAverage(Measurements::Temperature);
+ float temp = value.getCorrectedTempHum(Measurements::Temperature, 1);
if (utils::isValidTemperature(temp)) {
float t = 0.0f;
if (config.isTemperatureUnitInF()) {
@@ -44,7 +44,7 @@ void OledDisplay::showTempHum(bool hasStatus, char *buf, int buf_size) {
DISP()->drawUTF8(1, 10, buf);
/** Show humidity */
- int rhum = round(value.getAverage(Measurements::Humidity));
+ int rhum = round(value.getCorrectedTempHum(Measurements::Humidity, 1));
if (utils::isValidHumidity(rhum)) {
snprintf(buf, buf_size, "%d%%", rhum);
} else {
@@ -389,7 +389,7 @@ void OledDisplay::showDashboard(const char *status) {
ag->display.setText(strBuf);
/** Set temperature and humidity */
- float temp = value.getAverage(Measurements::Temperature);
+ float temp = value.getCorrectedTempHum(Measurements::Temperature, 1);
if (utils::isValidTemperature(temp)) {
if (config.isTemperatureUnitInF()) {
snprintf(strBuf, sizeof(strBuf), "T:%0.1f F", utils::degreeC_To_F(temp));
@@ -407,7 +407,7 @@ void OledDisplay::showDashboard(const char *status) {
ag->display.setCursor(0, 24);
ag->display.setText(strBuf);
- int rhum = round(value.getAverage(Measurements::Humidity));
+ int rhum = round(value.getCorrectedTempHum(Measurements::Humidity, 1));
if (utils::isValidHumidity(rhum)) {
snprintf(strBuf, sizeof(strBuf), "H:%d %%", rhum);
} else {
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index e265c89..c6be2e8 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -551,9 +551,12 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
switch (type) {
case Temperature: {
rawValue = _temperature[ch].update.avg;
-
Configuration::TempHumCorrection tmp = config.getTempCorrection();
- if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
+
+ // Apply 'standard' correction if its defined or correction forced
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024) {
+ return ag->pms5003t_1.compensateTemp(rawValue);
+ } else if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE && forceCorrection) {
return ag->pms5003t_1.compensateTemp(rawValue);
}
@@ -564,9 +567,12 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
}
case Humidity: {
rawValue = _humidity[ch].update.avg;
-
Configuration::TempHumCorrection tmp = config.getHumCorrection();
- if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024 || forceCorrection) {
+
+ // Apply 'standard' correction if its defined or correction forced
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024) {
+ return ag->pms5003t_1.compensateHum(rawValue);
+ } else if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE && forceCorrection) {
return ag->pms5003t_1.compensateHum(rawValue);
}
@@ -589,6 +595,7 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
// Custom correction constants
float corrected = (rawValue * correction.scalingFactor) + correction.intercept;
+ Serial.println("Custom correction applied");
return corrected;
}
@@ -747,14 +754,14 @@ JSONVar Measurements::buildIndoor(bool localServer) {
if (utils::isValidTemperature(_temperature[0].update.avg)) {
indoor[json_prop_temp] = ag->round2(_temperature[0].update.avg);
if (localServer) {
- indoor[json_prop_tempCompensated] = ag->round2(_temperature[0].update.avg);
+ indoor[json_prop_tempCompensated] = ag->round2(getCorrectedTempHum(Temperature));
}
}
// Add humidity
if (utils::isValidHumidity(_humidity[0].update.avg)) {
indoor[json_prop_rhum] = ag->round2(_humidity[0].update.avg);
if (localServer) {
- indoor[json_prop_rhumCompensated] = ag->round2(_humidity[0].update.avg);
+ indoor[json_prop_rhumCompensated] = ag->round2(getCorrectedTempHum(Humidity));
}
}
}
@@ -834,7 +841,7 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
pms[json_prop_temp] = ag->round2(_temperature[ch].update.avg);
// Compensate temperature when flag is set
if (compensate) {
- _vc = ag->pms5003t_1.compensateTemp(_temperature[ch].update.avg);
+ _vc = getCorrectedTempHum(Temperature, ch, true);
if (utils::isValidTemperature(_vc)) {
pms[json_prop_tempCompensated] = ag->round2(_vc);
}
@@ -845,8 +852,8 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
pms[json_prop_rhum] = ag->round2(_humidity[ch].update.avg);
// Compensate relative humidity when flag is set
if (compensate) {
- _vc = ag->pms5003t_1.compensateHum(_humidity[ch].update.avg);
- if (utils::isValidTemperature(_vc)) {
+ _vc = getCorrectedTempHum(Humidity, ch, true);
+ if (utils::isValidHumidity(_vc)) {
pms[json_prop_rhumCompensated] = ag->round2(_vc);
}
}
@@ -1031,10 +1038,10 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate both temperature channel
- float temp = ag->pms5003t_1.compensateTemp(temperature);
- float temp1 = ag->pms5003t_1.compensateTemp(_temperature[0].update.avg);
- float temp2 = ag->pms5003t_2.compensateTemp(_temperature[1].update.avg);
- pms[json_prop_tempCompensated] = ag->round2(temp);
+ float temp1 = getCorrectedTempHum(Temperature, 1, true);
+ float temp2 = getCorrectedTempHum(Temperature, 2, true);
+ float tempAverage = (temp1 + temp2) / 2.0f;
+ pms[json_prop_tempCompensated] = ag->round2(tempAverage);
pms["channels"]["1"][json_prop_tempCompensated] = ag->round2(temp1);
pms["channels"]["2"][json_prop_tempCompensated] = ag->round2(temp2);
}
@@ -1045,7 +1052,7 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate channel 1
- float temp1 = ag->pms5003t_1.compensateTemp(_temperature[0].update.avg);
+ float temp1 = getCorrectedTempHum(Temperature, 1, true);
pms[json_prop_tempCompensated] = ag->round2(temp1);
pms["channels"]["1"][json_prop_tempCompensated] = ag->round2(temp1);
}
@@ -1056,7 +1063,7 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate channel 2
- float temp2 = ag->pms5003t_2.compensateTemp(_temperature[1].update.avg);
+ float temp2 = getCorrectedTempHum(Temperature, 2, true);
pms[json_prop_tempCompensated] = ag->round2(temp2);
pms["channels"]["2"][json_prop_tempCompensated] = ag->round2(temp2);
}
@@ -1072,10 +1079,10 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate both humidity channel
- float hum = ag->pms5003t_1.compensateHum(humidity);
- float hum1 = ag->pms5003t_1.compensateHum(_humidity[0].update.avg);
- float hum2 = ag->pms5003t_2.compensateHum(_humidity[1].update.avg);
- pms[json_prop_rhumCompensated] = ag->round2(hum);
+ float hum1 = getCorrectedTempHum(Humidity, 1, true);
+ float hum2 = getCorrectedTempHum(Humidity, 2, true);
+ float humAverage = (hum1 + hum2) / 2.0f;
+ pms[json_prop_rhumCompensated] = ag->round2(humAverage);
pms["channels"]["1"][json_prop_rhumCompensated] = ag->round2(hum1);
pms["channels"]["2"][json_prop_rhumCompensated] = ag->round2(hum2);
}
@@ -1086,7 +1093,7 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate humidity channel 1
- float hum1 = ag->pms5003t_1.compensateHum(_humidity[0].update.avg);
+ float hum1 = getCorrectedTempHum(Humidity, 1, true);
pms[json_prop_rhumCompensated] = ag->round2(hum1);
pms["channels"]["1"][json_prop_rhumCompensated] = ag->round2(hum1);
}
@@ -1097,7 +1104,7 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
if (compensate) {
// Compensate humidity channel 2
- float hum2 = ag->pms5003t_2.compensateHum(_humidity[1].update.avg);
+ float hum2 = getCorrectedTempHum(Humidity, 2, true);
pms[json_prop_rhumCompensated] = ag->round2(hum2);
pms["channels"]["2"][json_prop_rhumCompensated] = ag->round2(hum2);
}
diff --git a/src/AgValue.h b/src/AgValue.h
index c5bd5e0..db5508e 100644
--- a/src/AgValue.h
+++ b/src/AgValue.h
@@ -125,6 +125,16 @@ public:
*/
float getAverage(MeasurementType type, int ch = 1);
+ /**
+ * @brief Get Temperature or Humidity correction value
+ * Only if correction is applied from configuration or forceCorrection is True
+ *
+ * @param type measurement type either Temperature or Humidity
+ * @param ch target type value channel
+ * @param forceCorrection force using correction even though config correction is not applied, but
+ * not for CUSTOM
+ * @return correction value
+ */
float getCorrectedTempHum(MeasurementType type, int ch = 1, bool forceCorrection = false);
/**
From a28931493aa4f73d8cf336fea30a57d0140e47aa Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Fri, 24 Jan 2025 18:03:13 +0700
Subject: [PATCH 08/36] Add docs about how to set correction from local server
---
docs/local-server.md | 56 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 47 insertions(+), 9 deletions(-)
diff --git a/docs/local-server.md b/docs/local-server.md
index f56d7f1..06dcdf1 100644
--- a/docs/local-server.md
+++ b/docs/local-server.md
@@ -2,7 +2,7 @@
From [firmware version 3.0.10](firmwares) onwards, the AirGradient ONE and Open Air monitors have below API available.
-#### Discovery
+### Discovery
The monitors run a mDNS discovery. So within the same network, the monitor can be accessed through:
@@ -11,7 +11,7 @@ http://airgradient_{{serialnumber}}.local
The following requests are possible:
-#### Get Current Air Quality (GET)
+### Get Current Air Quality (GET)
With the path "/measures/current" you can get the current air quality data.
@@ -80,7 +80,7 @@ You get the following response:
Compensated values apply correction algorithms to make the sensor values more accurate. Temperature and relative humidity correction is only applied on the outdoor monitor Open Air but the properties _compensated will still be send also for the indoor monitor AirGradient ONE.
-#### Get Configuration Parameters (GET)
+### Get Configuration Parameters (GET)
"/config" path returns the current configuration of the monitor.
@@ -111,7 +111,7 @@ Compensated values apply correction algorithms to make the sensor values more ac
}
```
-#### Set Configuration Parameters (PUT)
+### Set Configuration Parameters (PUT)
Configuration parameters can be changed with a PUT request to the monitor, e.g.
@@ -131,11 +131,11 @@ Example to set monitor to Celsius
``` -d "{\"param\":\"value\"}" ```
-#### Avoiding Conflicts with Configuration on AirGradient Server
+### Avoiding Conflicts with Configuration on AirGradient Server
If the monitor is set up on the AirGradient dashboard, it will also receive the configuration parameters from there. In case you do not want this, please set `configurationControl` to `local`. In case you set it to `cloud` and want to change it to `local`, you need to make a factory reset.
-#### Configuration Parameters (GET/PUT)
+### Configuration Parameters (GET/PUT)
| Properties | Description | Type | Accepted Values | Example |
|-----------------------------------|:-----------------------------------------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|
@@ -160,9 +160,9 @@ If the monitor is set up on the AirGradient dashboard, it will also receive the
-#### Corrections
+### Corrections
-The `corrections` object allows configuring PM2.5 correction algorithms and parameters locally. This affects both the display and local server response values.
+The `corrections` object allows configuring PM2.5, Temperature and Humidity correction algorithms and parameters locally. This affects both the display, local server response and open metrics values.
Example correction configuration:
@@ -176,11 +176,29 @@ Example correction configuration:
"scalingFactor": 0,
"useEpa2021": false
}
- }
+ },
+ "atmp": {
+ "correctionAlgorithm": "
");
WIFI()->addParameter(&disableCloudInfo);
WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT);
From c8f0e6a0d2688e676e06fe52b39384a0d4595ac3 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sat, 25 Jan 2025 04:08:17 +0700
Subject: [PATCH 13/36] Update diy samples That accomodate ApiClient changes
Fix apiClient begin on OneOpenAir
---
examples/BASIC/BASIC.ino | 27 ++++++++++++++-----
.../DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 27 ++++++++++++++-----
.../DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 27 ++++++++++++++-----
examples/OneOpenAir/OneOpenAir.ino | 7 +++--
4 files changed, 68 insertions(+), 20 deletions(-)
diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino
index 97105fb..eccbcc5 100644
--- a/examples/BASIC/BASIC.ino
+++ b/examples/BASIC/BASIC.ino
@@ -149,7 +149,10 @@ void setup() {
initMqtt();
sendDataToAg();
- apiClient.fetchServerConfiguration();
+ if (configuration.getConfigurationControl() !=
+ ConfigurationControl::ConfigurationControlLocal) {
+ apiClient.fetchServerConfiguration();
+ }
configSchedule.update();
if (apiClient.isFetchConfigureFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
@@ -415,6 +418,14 @@ static void failedHandler(String msg) {
}
static void configurationUpdateSchedule(void) {
+ if (configuration.isOfflineMode() ||
+ configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
+ Serial.println("Ignore fetch server configuration. Either mode is offline "
+ "or configurationControl set to local");
+ apiClient.resetFetchConfigureState();
+ return;
+ }
+
if (apiClient.fetchServerConfiguration()) {
configUpdateHandle();
}
@@ -521,17 +532,21 @@ static void sendDataToServer(void) {
int bootCount = measurements.bootCount() + 1;
measurements.setBootCount(bootCount);
- /** Ignore send data to server if postToAirGradient disabled */
- if (configuration.isPostDataToAirGradient() == false ||
- configuration.isOfflineMode()) {
+ if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
+ Serial.println("Ignore send data to server. Either mode is offline "
+ "or post data to server disabled");
+ return;
+ }
+
+ if (wifiConnector.isConnected() == false) {
+ Serial.println("WiFi not connected, skip post data to server");
return;
}
String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), ag, configuration);
if (apiClient.postToServer(syncData)) {
Serial.println();
- Serial.println(
- "Online mode and isPostToAirGradient = true: watchdog reset");
+ Serial.println("Online mode and isPostToAirGradient = true");
Serial.println();
}
}
diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
index bd19b86..509a8c5 100644
--- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
+++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
@@ -149,7 +149,10 @@ void setup() {
initMqtt();
sendDataToAg();
- apiClient.fetchServerConfiguration();
+ if (configuration.getConfigurationControl() !=
+ ConfigurationControl::ConfigurationControlLocal) {
+ apiClient.fetchServerConfiguration();
+ }
configSchedule.update();
if (apiClient.isFetchConfigureFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
@@ -467,6 +470,14 @@ static void failedHandler(String msg) {
}
static void configurationUpdateSchedule(void) {
+ if (configuration.isOfflineMode() ||
+ configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
+ Serial.println("Ignore fetch server configuration. Either mode is offline "
+ "or configurationControl set to local");
+ apiClient.resetFetchConfigureState();
+ return;
+ }
+
if (apiClient.fetchServerConfiguration()) {
configUpdateHandle();
}
@@ -573,17 +584,21 @@ static void sendDataToServer(void) {
int bootCount = measurements.bootCount() + 1;
measurements.setBootCount(bootCount);
- /** Ignore send data to server if postToAirGradient disabled */
- if (configuration.isPostDataToAirGradient() == false ||
- configuration.isOfflineMode()) {
+ if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
+ Serial.println("Ignore send data to server. Either mode is offline "
+ "or post data to server disabled");
+ return;
+ }
+
+ if (wifiConnector.isConnected() == false) {
+ Serial.println("WiFi not connected, skip post data to server");
return;
}
String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), ag, configuration);
if (apiClient.postToServer(syncData)) {
Serial.println();
- Serial.println(
- "Online mode and isPostToAirGradient = true: watchdog reset");
+ Serial.println("Online mode and isPostToAirGradient = true");
Serial.println();
}
}
diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
index f29c2cf..08f0551 100644
--- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
+++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
@@ -176,7 +176,10 @@ void setup() {
initMqtt();
sendDataToAg();
- apiClient.fetchServerConfiguration();
+ if (configuration.getConfigurationControl() !=
+ ConfigurationControl::ConfigurationControlLocal) {
+ apiClient.fetchServerConfiguration();
+ }
configSchedule.update();
if (apiClient.isFetchConfigureFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
@@ -507,6 +510,14 @@ static void failedHandler(String msg) {
}
static void configurationUpdateSchedule(void) {
+ if (configuration.isOfflineMode() ||
+ configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
+ Serial.println("Ignore fetch server configuration. Either mode is offline "
+ "or configurationControl set to local");
+ apiClient.resetFetchConfigureState();
+ return;
+ }
+
if (apiClient.fetchServerConfiguration()) {
configUpdateHandle();
}
@@ -614,17 +625,21 @@ static void sendDataToServer(void) {
int bootCount = measurements.bootCount() + 1;
measurements.setBootCount(bootCount);
- /** Ignore send data to server if postToAirGradient disabled */
- if (configuration.isPostDataToAirGradient() == false ||
- configuration.isOfflineMode()) {
+ if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
+ Serial.println("Ignore send data to server. Either mode is offline "
+ "or post data to server disabled");
+ return;
+ }
+
+ if (wifiConnector.isConnected() == false) {
+ Serial.println("WiFi not connected, skip post data to server");
return;
}
String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(), ag, configuration);
if (apiClient.postToServer(syncData)) {
Serial.println();
- Serial.println(
- "Online mode and isPostToAirGradient = true: watchdog reset");
+ Serial.println("Online mode and isPostToAirGradient = true");
Serial.println();
}
}
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index e51f933..82d941f 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -861,7 +861,7 @@ void initiateNetwork() {
// Initiate local network configuration
mdnsInit();
localServer.begin();
- // Apply mqtt connection
+ // Apply mqtt connection if configured
initMqtt();
// Ignore the rest if cloud connection to AirGradient is disabled
@@ -869,7 +869,10 @@ void initiateNetwork() {
return;
}
- // Send ping to aigradient server
+ // Initialize api client
+ apiClient.begin();
+
+ // Send ping to airgradient server
sendDataToAg();
// OTA check
From f0c4df42b70b06ae08efc89d20df80adc8db9599 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sun, 26 Jan 2025 13:02:42 +0700
Subject: [PATCH 14/36] Fix wording on local-server
---
docs/local-server.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/local-server.md b/docs/local-server.md
index 07e6dd3..5e5f233 100644
--- a/docs/local-server.md
+++ b/docs/local-server.md
@@ -160,8 +160,8 @@ If the monitor is set up on the AirGradient dashboard, it will also receive the
**Notes**
-- `offlineMode` : device will disable all network operation, and only show measurements on display and ledbar; Read-Only; change can be apply using reset button on boot.
-- `disableCloudConnection` : disable every request to airgradient server, means feature like post data to airgradient dashboard, configure from cloud and firmware update are disabled. This configuration override `configurationControl` and `postDataToAirGradient`; Read-Only; change can be apply from wifi setup webpage.
+- `offlineMode` : device will disable all network operation, and only show measurements on display and ledbar; Read-Only; Change can be apply using reset button on boot.
+- `disableCloudConnection` : disable every request to AirGradient server, means features like post data to AirGradient server, configuration from AirGradient server and automatic firmware updates are disabled. This configuration overrides `configurationControl` and `postDataToAirGradient`; Read-Only; Change can be apply from wifi setup webpage.
#### Corrections
From 3e48a562e7ac33f7518612a1e63d50fe0565bc37 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sun, 26 Jan 2025 22:50:17 +0700
Subject: [PATCH 15/36] Change comment of sendDataToAg function call
---
examples/OneOpenAir/OneOpenAir.ino | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 82d941f..18e9887 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -872,7 +872,7 @@ void initiateNetwork() {
// Initialize api client
apiClient.begin();
- // Send ping to airgradient server
+ // Check and process if AirGradient server is reachable
sendDataToAg();
// OTA check
From 0e41b2d630dc5367b1fc96db0e54ee42ac232941 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 30 Jan 2025 10:01:15 +0700
Subject: [PATCH 16/36] Rename function from initiateNetwork to
initializeNetwork
---
examples/OneOpenAir/OneOpenAir.ino | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 18e9887..df247bf 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -96,7 +96,7 @@ static bool ledBarButtonTest = false;
static String fwNewVersion;
static void boardInit(void);
-static void initiateNetwork(void);
+static void initializeNetwork(void);
static void failedHandler(String msg);
static void configurationUpdateSchedule(void);
static void updateDisplayAndLedBar(void);
@@ -209,9 +209,9 @@ void setup() {
connectToWifi = true;
}
- // Initiate networking configuration
+ // Initialize networking configuration
if (connectToWifi) {
- initiateNetwork();
+ initializeNetwork();
}
/** Set offline mode without saving, cause wifi is not configured */
@@ -838,8 +838,7 @@ static void failedHandler(String msg) {
}
}
-void initiateNetwork() {
-
+void initializeNetwork() {
if (!wifiConnector.connect()) {
Serial.println("Cannot initiate wifi connection");
return;
From 84a358291b29eda16b268a14f12b549f97b708a4 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 30 Jan 2025 14:23:39 +0700
Subject: [PATCH 17/36] Rename function from configure to configuration
---
examples/BASIC/BASIC.ino | 6 +++---
examples/BASIC/OpenMetrics.cpp | 2 +-
examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 6 +++---
examples/DiyProIndoorV3_3/OpenMetrics.cpp | 2 +-
examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 6 +++---
examples/DiyProIndoorV4_2/OpenMetrics.cpp | 2 +-
examples/OneOpenAir/OneOpenAir.ino | 6 +++---
examples/OneOpenAir/OpenMetrics.cpp | 2 +-
src/AgApiClient.cpp | 6 +++---
src/AgApiClient.h | 4 ++--
10 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino
index eccbcc5..cf65775 100644
--- a/examples/BASIC/BASIC.ino
+++ b/examples/BASIC/BASIC.ino
@@ -154,7 +154,7 @@ void setup() {
apiClient.fetchServerConfiguration();
}
configSchedule.update();
- if (apiClient.isFetchConfigureFailed()) {
+ if (apiClient.isFetchConfigurationFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
stateMachine.displayHandle(
@@ -422,7 +422,7 @@ static void configurationUpdateSchedule(void) {
configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
Serial.println("Ignore fetch server configuration. Either mode is offline "
"or configurationControl set to local");
- apiClient.resetFetchConfigureState();
+ apiClient.resetFetchConfigurationStatus();
return;
}
@@ -483,7 +483,7 @@ static void appDispHandler(void) {
if (configuration.isOfflineMode() == false) {
if (wifiConnector.isConnected() == false) {
state = AgStateMachineWiFiLost;
- } else if (apiClient.isFetchConfigureFailed()) {
+ } else if (apiClient.isFetchConfigurationFailed()) {
state = AgStateMachineSensorConfigFailed;
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
diff --git a/examples/BASIC/OpenMetrics.cpp b/examples/BASIC/OpenMetrics.cpp
index c8395c0..9b92fbe 100644
--- a/examples/BASIC/OpenMetrics.cpp
+++ b/examples/BASIC/OpenMetrics.cpp
@@ -43,7 +43,7 @@ String OpenMetrics::getPayload(void) {
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
- add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
+ add_metric_point("", apiClient.isFetchConfigurationFailed() ? "0" : "1");
add_metric(
"post_ok",
diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
index 509a8c5..171d69d 100644
--- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
+++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
@@ -154,7 +154,7 @@ void setup() {
apiClient.fetchServerConfiguration();
}
configSchedule.update();
- if (apiClient.isFetchConfigureFailed()) {
+ if (apiClient.isFetchConfigurationFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
stateMachine.displayHandle(
@@ -474,7 +474,7 @@ static void configurationUpdateSchedule(void) {
configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
Serial.println("Ignore fetch server configuration. Either mode is offline "
"or configurationControl set to local");
- apiClient.resetFetchConfigureState();
+ apiClient.resetFetchConfigurationStatus();
return;
}
@@ -535,7 +535,7 @@ static void appDispHandler(void) {
if (configuration.isOfflineMode() == false) {
if (wifiConnector.isConnected() == false) {
state = AgStateMachineWiFiLost;
- } else if (apiClient.isFetchConfigureFailed()) {
+ } else if (apiClient.isFetchConfigurationFailed()) {
state = AgStateMachineSensorConfigFailed;
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
diff --git a/examples/DiyProIndoorV3_3/OpenMetrics.cpp b/examples/DiyProIndoorV3_3/OpenMetrics.cpp
index 8ec9d2f..dadb8b1 100644
--- a/examples/DiyProIndoorV3_3/OpenMetrics.cpp
+++ b/examples/DiyProIndoorV3_3/OpenMetrics.cpp
@@ -43,7 +43,7 @@ String OpenMetrics::getPayload(void) {
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
- add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
+ add_metric_point("", apiClient.isFetchConfigurationFailed() ? "0" : "1");
add_metric(
"post_ok",
diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
index 08f0551..f837481 100644
--- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
+++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
@@ -181,7 +181,7 @@ void setup() {
apiClient.fetchServerConfiguration();
}
configSchedule.update();
- if (apiClient.isFetchConfigureFailed()) {
+ if (apiClient.isFetchConfigurationFailed()) {
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
stateMachine.displayHandle(
@@ -514,7 +514,7 @@ static void configurationUpdateSchedule(void) {
configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
Serial.println("Ignore fetch server configuration. Either mode is offline "
"or configurationControl set to local");
- apiClient.resetFetchConfigureState();
+ apiClient.resetFetchConfigurationStatus();
return;
}
@@ -575,7 +575,7 @@ static void appDispHandler(void) {
if (configuration.isOfflineMode() == false) {
if (wifiConnector.isConnected() == false) {
state = AgStateMachineWiFiLost;
- } else if (apiClient.isFetchConfigureFailed()) {
+ } else if (apiClient.isFetchConfigurationFailed()) {
state = AgStateMachineSensorConfigFailed;
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
diff --git a/examples/DiyProIndoorV4_2/OpenMetrics.cpp b/examples/DiyProIndoorV4_2/OpenMetrics.cpp
index c8395c0..9b92fbe 100644
--- a/examples/DiyProIndoorV4_2/OpenMetrics.cpp
+++ b/examples/DiyProIndoorV4_2/OpenMetrics.cpp
@@ -43,7 +43,7 @@ String OpenMetrics::getPayload(void) {
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
- add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
+ add_metric_point("", apiClient.isFetchConfigurationFailed() ? "0" : "1");
add_metric(
"post_ok",
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index df247bf..9dff24e 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -884,7 +884,7 @@ void initializeNetwork() {
apiClient.fetchServerConfiguration();
configSchedule.update();
- if (apiClient.isFetchConfigureFailed()) {
+ if (apiClient.isFetchConfigurationFailed()) {
if (ag->isOne()) {
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
@@ -905,7 +905,7 @@ static void configurationUpdateSchedule(void) {
configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
Serial.println("Ignore fetch server configuration. Either mode is offline or cloud connection "
"disabled or configurationControl set to local");
- apiClient.resetFetchConfigureState();
+ apiClient.resetFetchConfigurationStatus();
return;
}
@@ -1019,7 +1019,7 @@ static void updateDisplayAndLedBar(void) {
}
AgStateMachineState state = AgStateMachineNormal;
- if (apiClient.isFetchConfigureFailed()) {
+ if (apiClient.isFetchConfigurationFailed()) {
state = AgStateMachineSensorConfigFailed;
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
diff --git a/examples/OneOpenAir/OpenMetrics.cpp b/examples/OneOpenAir/OpenMetrics.cpp
index fa59444..e366ea4 100644
--- a/examples/OneOpenAir/OpenMetrics.cpp
+++ b/examples/OneOpenAir/OpenMetrics.cpp
@@ -43,7 +43,7 @@ String OpenMetrics::getPayload(void) {
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
- add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
+ add_metric_point("", apiClient.isFetchConfigurationFailed() ? "0" : "1");
add_metric(
"post_ok",
diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp
index 8984d1d..5869566 100644
--- a/src/AgApiClient.cpp
+++ b/src/AgApiClient.cpp
@@ -153,12 +153,12 @@ bool AgApiClient::postToServer(String data) {
* @return true Success
* @return false Failure
*/
-bool AgApiClient::isFetchConfigureFailed(void) { return getConfigFailed; }
+bool AgApiClient::isFetchConfigurationFailed(void) { return getConfigFailed; }
/**
- * @brief Reset getConfigFailed state to false
+ * @brief Reset status of get configuration from AirGradient cloud
*/
-void AgApiClient::resetFetchConfigureState(void) { getConfigFailed = false; }
+void AgApiClient::resetFetchConfigurationStatus(void) { getConfigFailed = false; }
/**
* @brief Get failed status when post data to AirGradient cloud
diff --git a/src/AgApiClient.h b/src/AgApiClient.h
index edb30c5..7ee8734 100644
--- a/src/AgApiClient.h
+++ b/src/AgApiClient.h
@@ -40,8 +40,8 @@ public:
void begin(void);
bool fetchServerConfiguration(void);
bool postToServer(String data);
- bool isFetchConfigureFailed(void);
- void resetFetchConfigureState(void);
+ bool isFetchConfigurationFailed(void);
+ void resetFetchConfigurationStatus(void);
bool isPostToServerFailed(void);
bool isNotAvailableOnDashboard(void);
void setAirGradient(AirGradient *ag);
From b75e40b8000f51792986f23142b02df4330906f8 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 30 Jan 2025 15:09:27 +0700
Subject: [PATCH 18/36] Rename variable for readability
---
src/AgConfigure.cpp | 98 ++++++++++++++++++++++-----------------------
1 file changed, 49 insertions(+), 49 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 25d0f5d..9267141 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -1039,20 +1039,20 @@ void Configuration::toConfig(const char *buf) {
}
bool changed = false;
- bool isInvalid = false;
+ bool isConfigFieldInvalid = false;
/** Validate country */
if (JSON.typeof_(jconfig[jprop_country]) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
String country = jconfig[jprop_country];
if (country.length() != 2) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_country] = jprop_country_default;
changed = true;
logInfo("toConfig: country changed");
@@ -1060,17 +1060,17 @@ void Configuration::toConfig(const char *buf) {
/** validate: PM standard */
if (JSON.typeof_(jconfig[jprop_pmStandard]) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
String standard = jconfig[jprop_pmStandard];
if (standard != getPMStandardString(true) &&
standard != getPMStandardString(false)) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_pmStandard] = jprop_pmStandard_default;
changed = true;
logInfo("toConfig: pmStandard changed");
@@ -1078,18 +1078,18 @@ void Configuration::toConfig(const char *buf) {
/** validate led bar mode */
if (JSON.typeof_(jconfig[jprop_ledBarMode]) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
String mode = jconfig[jprop_ledBarMode];
if (mode != getLedBarModeName(LedBarMode::LedBarModeCO2) &&
mode != getLedBarModeName(LedBarMode::LedBarModeOff) &&
mode != getLedBarModeName(LedBarMode::LedBarModePm)) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_ledBarMode] = jprop_ledBarMode_default;
changed = true;
logInfo("toConfig: ledBarMode changed");
@@ -1097,11 +1097,11 @@ void Configuration::toConfig(const char *buf) {
/** validate abcday */
if (JSON.typeof_(jconfig[jprop_abcDays]) != "number") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_abcDays] = jprop_abcDays_default;
changed = true;
logInfo("toConfig: abcDays changed");
@@ -1109,16 +1109,16 @@ void Configuration::toConfig(const char *buf) {
/** validate tvoc learning offset */
if (JSON.typeof_(jconfig[jprop_tvocLearningOffset]) != "number") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
int value = jconfig[jprop_tvocLearningOffset];
if (value < 0) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_tvocLearningOffset] = jprop_tvocLearningOffset_default;
changed = true;
logInfo("toConfig: tvocLearningOffset changed");
@@ -1126,16 +1126,16 @@ void Configuration::toConfig(const char *buf) {
/** validate nox learning offset */
if (JSON.typeof_(jconfig[jprop_noxLearningOffset]) != "number") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
int value = jconfig[jprop_noxLearningOffset];
if (value < 0) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_noxLearningOffset] = jprop_noxLearningOffset_default;
changed = true;
logInfo("toConfig: noxLearningOffset changed");
@@ -1143,11 +1143,11 @@ void Configuration::toConfig(const char *buf) {
/** validate mqtt broker */
if (JSON.typeof_(jconfig[jprop_mqttBrokerUrl]) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
changed = true;
jconfig[jprop_mqttBrokerUrl] = jprop_mqttBrokerUrl_default;
logInfo("toConfig: mqttBroker changed");
@@ -1155,16 +1155,16 @@ void Configuration::toConfig(const char *buf) {
/** Validate temperature unit */
if (JSON.typeof_(jconfig[jprop_temperatureUnit]) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
String unit = jconfig[jprop_temperatureUnit];
if (unit != "c" && unit != "f") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_temperatureUnit] = jprop_temperatureUnit_default;
changed = true;
logInfo("toConfig: temperatureUnit changed");
@@ -1172,11 +1172,11 @@ void Configuration::toConfig(const char *buf) {
/** validate disableCloudConnection configuration */
if (JSON.typeof_(jconfig[jprop_disableCloudConnection]) != "boolean") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_disableCloudConnection] = jprop_disableCloudConnection_default;
changed = true;
logInfo("toConfig: disableCloudConnection changed");
@@ -1184,7 +1184,7 @@ void Configuration::toConfig(const char *buf) {
/** validate configuration control */
if (JSON.typeof_(jprop_configurationControl) != "string") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
String ctrl = jconfig[jprop_configurationControl];
if (ctrl != String(CONFIGURATION_CONTROL_NAME
@@ -1193,12 +1193,12 @@ void Configuration::toConfig(const char *buf) {
[ConfigurationControl::ConfigurationControlLocal]) &&
ctrl != String(CONFIGURATION_CONTROL_NAME
[ConfigurationControl::ConfigurationControlCloud])) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_configurationControl] =jprop_configurationControl_default;
changed = true;
logInfo("toConfig: configurationControl changed");
@@ -1206,11 +1206,11 @@ void Configuration::toConfig(const char *buf) {
/** Validate post to airgradient cloud */
if (JSON.typeof_(jconfig[jprop_postDataToAirGradient]) != "boolean") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_postDataToAirGradient] = jprop_postDataToAirGradient_default;
changed = true;
logInfo("toConfig: postToAirGradient changed");
@@ -1218,16 +1218,16 @@ void Configuration::toConfig(const char *buf) {
/** validate led bar brightness */
if (JSON.typeof_(jconfig[jprop_ledBarBrightness]) != "number") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
int value = jconfig[jprop_ledBarBrightness];
if (value < 0 || value > 100) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_ledBarBrightness] = jprop_ledBarBrightness_default;
changed = true;
logInfo("toConfig: ledBarBrightness changed");
@@ -1235,16 +1235,16 @@ void Configuration::toConfig(const char *buf) {
/** Validate display brightness */
if (JSON.typeof_(jconfig[jprop_displayBrightness]) != "number") {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
int value = jconfig[jprop_displayBrightness];
if (value < 0 || value > 100) {
- isInvalid = true;
+ isConfigFieldInvalid = true;
} else {
- isInvalid = false;
+ isConfigFieldInvalid = false;
}
}
- if (isInvalid) {
+ if (isConfigFieldInvalid) {
jconfig[jprop_displayBrightness] = jprop_displayBrightness_default;
changed = true;
logInfo("toConfig: displayBrightness changed");
From 154f3ecf8a853ea95429343c155567d4c0435723 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sat, 1 Feb 2025 13:52:12 +0700
Subject: [PATCH 19/36] Fix display 0 measurements on boot
---
examples/OneOpenAir/OneOpenAir.ino | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index ee4b680..9030ee8 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -268,15 +268,17 @@ void setup() {
oledDisplay.setBrightness(configuration.getDisplayBrightness());
}
- // Update display and led bar after finishing setup to show dashboard
- updateDisplayAndLedBar();
+ // Reset display and post schedulers to make sure measurements value already available
+ dispLedSchedule.update();
+ agApiPostSchedule.update();
}
void loop() {
- /** Handle schedule */
+ /** Run schedulers */
dispLedSchedule.run();
configSchedule.run();
agApiPostSchedule.run();
+ watchdogFeedSchedule.run();
if (configuration.hasSensorS8) {
co2Schedule.run();
@@ -310,15 +312,13 @@ void loop() {
}
}
- watchdogFeedSchedule.run();
-
/** Check for handle WiFi reconnect */
wifiConnector.handle();
/** factory reset handle */
factoryConfigReset();
- /** check that local configura changed then do some action */
+ /** check that local configuration changed then do some action */
configUpdateHandle();
/** Firmware check for update handle */
From 1839664137502146d0229565fc8b94089fb19dac Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Sat, 1 Feb 2025 14:20:54 +0700
Subject: [PATCH 20/36] Extend connect to server timeout Default 5s from
HTTPClient
---
src/AgApiClient.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp
index 8de2596..b2dbf1f 100644
--- a/src/AgApiClient.cpp
+++ b/src/AgApiClient.cpp
@@ -59,6 +59,7 @@ bool AgApiClient::fetchServerConfiguration(void) {
#else
HTTPClient client;
client.setTimeout(timeoutMs);
+ client.setConnectTimeout(timeoutMs);
if (apiRootChanged) {
// If apiRoot is changed, assume not using https
if (client.begin(uri) == false) {
@@ -134,6 +135,7 @@ bool AgApiClient::postToServer(String data) {
#else
HTTPClient client;
client.setTimeout(timeoutMs);
+ client.setConnectTimeout(timeoutMs);
if (apiRootChanged) {
// If apiRoot is changed, assume not using https
if (client.begin(uri) == false) {
From d2ee3a5d244b13ce08cdebc4044bed59a90765bd Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Mon, 3 Feb 2025 01:28:42 +0700
Subject: [PATCH 21/36] Set default value for each measurements value to
invalid
---
examples/OneOpenAir/OneOpenAir.ino | 3 +--
src/AgValue.cpp | 39 ++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 9030ee8..47be2ff 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -268,8 +268,7 @@ void setup() {
oledDisplay.setBrightness(configuration.getDisplayBrightness());
}
- // Reset display and post schedulers to make sure measurements value already available
- dispLedSchedule.update();
+ // Reset post schedulers to make sure measurements value already available
agApiPostSchedule.update();
}
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index 1a46ece..544744c 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -31,6 +31,45 @@ Measurements::Measurements() {
#ifndef ESP8266
_resetReason = (int)ESP_RST_UNKNOWN;
#endif
+
+ /* Set invalid value for each measurements as default value when initialized*/
+ _temperature[0].update.avg = utils::getInvalidTemperature();
+ _temperature[1].update.avg = utils::getInvalidTemperature();
+ _humidity[0].update.avg = utils::getInvalidHumidity();
+ _humidity[1].update.avg = utils::getInvalidHumidity();
+ _co2.update.avg = utils::getInvalidCO2();
+ _tvoc.update.avg = utils::getInvalidVOC();
+ _tvoc_raw.update.avg = utils::getInvalidVOC();
+ _nox.update.avg = utils::getInvalidNOx();
+ _nox_raw.update.avg = utils::getInvalidNOx();
+
+ _pm_03_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_03_pc[1].update.avg = utils::getInvalidPmValue();
+ _pm_05_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_05_pc[1].update.avg = utils::getInvalidPmValue();
+ _pm_5_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_5_pc[1].update.avg = utils::getInvalidPmValue();
+
+ _pm_01[0].update.avg = utils::getInvalidPmValue();
+ _pm_01_sp[0].update.avg = utils::getInvalidPmValue();
+ _pm_01_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_01[1].update.avg = utils::getInvalidPmValue();
+ _pm_01_sp[1].update.avg = utils::getInvalidPmValue();
+ _pm_01_pc[1].update.avg = utils::getInvalidPmValue();
+
+ _pm_25[0].update.avg = utils::getInvalidPmValue();
+ _pm_25_sp[0].update.avg = utils::getInvalidPmValue();
+ _pm_25_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_25[1].update.avg = utils::getInvalidPmValue();
+ _pm_25_sp[1].update.avg = utils::getInvalidPmValue();
+ _pm_25_pc[1].update.avg = utils::getInvalidPmValue();
+
+ _pm_10[0].update.avg = utils::getInvalidPmValue();
+ _pm_10_sp[0].update.avg = utils::getInvalidPmValue();
+ _pm_10_pc[0].update.avg = utils::getInvalidPmValue();
+ _pm_10[1].update.avg = utils::getInvalidPmValue();
+ _pm_10_sp[1].update.avg = utils::getInvalidPmValue();
+ _pm_10_pc[1].update.avg = utils::getInvalidPmValue();
}
void Measurements::maxPeriod(MeasurementType type, int max) {
From 85ba13de129207ac65616eec5445b826b82e636b Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 01:18:46 +0700
Subject: [PATCH 22/36] Set default ag client timeout to 15s
---
src/AgApiClient.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/AgApiClient.h b/src/AgApiClient.h
index 9f39ceb..8e52e76 100644
--- a/src/AgApiClient.h
+++ b/src/AgApiClient.h
@@ -31,7 +31,7 @@ private:
bool getConfigFailed;
bool postToServerFailed;
bool notAvailableOnDashboard = false; // Device not setup on Airgradient cloud dashboard.
- uint16_t timeoutMs = 10000; // Default set to 10s
+ uint16_t timeoutMs = 15000; // Default set to 15s
public:
AgApiClient(Stream &stream, Configuration &config);
From 03f1b969c24f7d2ab762f52dbcdbddff4d6d935a Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 01:24:59 +0700
Subject: [PATCH 23/36] Add comment describe two timeout functions call
---
src/AgApiClient.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp
index b2dbf1f..6eedcc9 100644
--- a/src/AgApiClient.cpp
+++ b/src/AgApiClient.cpp
@@ -58,8 +58,8 @@ bool AgApiClient::fetchServerConfiguration(void) {
}
#else
HTTPClient client;
- client.setTimeout(timeoutMs);
- client.setConnectTimeout(timeoutMs);
+ client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server
+ client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server
if (apiRootChanged) {
// If apiRoot is changed, assume not using https
if (client.begin(uri) == false) {
@@ -134,8 +134,8 @@ bool AgApiClient::postToServer(String data) {
}
#else
HTTPClient client;
- client.setTimeout(timeoutMs);
- client.setConnectTimeout(timeoutMs);
+ client.setConnectTimeout(timeoutMs); // Set timeout when establishing connection to server
+ client.setTimeout(timeoutMs); // Timeout when waiting for response from AG server
if (apiRootChanged) {
// If apiRoot is changed, assume not using https
if (client.begin(uri) == false) {
From afd498074baa1d1b94673f4ff85e457a8a577e04 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 10:43:56 +0700
Subject: [PATCH 24/36] Fix grammar error
---
docs/local-server.md | 2 +-
examples/BASIC/BASIC.ino | 2 +-
examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 2 +-
examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 2 +-
examples/OneOpenAir/OneOpenAir.ino | 2 +-
src/AgWiFiConnector.cpp | 4 ++--
6 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs/local-server.md b/docs/local-server.md
index 5e5f233..b79020b 100644
--- a/docs/local-server.md
+++ b/docs/local-server.md
@@ -160,7 +160,7 @@ If the monitor is set up on the AirGradient dashboard, it will also receive the
**Notes**
-- `offlineMode` : device will disable all network operation, and only show measurements on display and ledbar; Read-Only; Change can be apply using reset button on boot.
+- `offlineMode` : the device will disable all network operation, and only show measurements on the display and ledbar; Read-Only; Change can be apply using reset button on boot.
- `disableCloudConnection` : disable every request to AirGradient server, means features like post data to AirGradient server, configuration from AirGradient server and automatic firmware updates are disabled. This configuration overrides `configurationControl` and `postDataToAirGradient`; Read-Only; Change can be apply from wifi setup webpage.
#### Corrections
diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino
index cf65775..94a7fe0 100644
--- a/examples/BASIC/BASIC.ino
+++ b/examples/BASIC/BASIC.ino
@@ -539,7 +539,7 @@ static void sendDataToServer(void) {
}
if (wifiConnector.isConnected() == false) {
- Serial.println("WiFi not connected, skip post data to server");
+ Serial.println("WiFi not connected, skipping data transmission to AG server");
return;
}
diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
index 171d69d..4969af8 100644
--- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
+++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
@@ -591,7 +591,7 @@ static void sendDataToServer(void) {
}
if (wifiConnector.isConnected() == false) {
- Serial.println("WiFi not connected, skip post data to server");
+ Serial.println("WiFi not connected, skipping data transmission to AG server");
return;
}
diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
index f837481..e3db76e 100644
--- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
+++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
@@ -632,7 +632,7 @@ static void sendDataToServer(void) {
}
if (wifiConnector.isConnected() == false) {
- Serial.println("WiFi not connected, skip post data to server");
+ Serial.println("WiFi not connected, skipping data transmission to AG server");
return;
}
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index f797ed6..976c6ac 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -1194,7 +1194,7 @@ static void sendDataToServer(void) {
}
if (wifiConnector.isConnected() == false) {
- Serial.println("WiFi not connected, skip post data to server");
+ Serial.println("WiFi not connected, skipping data transmission to AG server");
return;
}
diff --git a/src/AgWiFiConnector.cpp b/src/AgWiFiConnector.cpp
index ec10975..a8e2c7f 100644
--- a/src/AgWiFiConnector.cpp
+++ b/src/AgWiFiConnector.cpp
@@ -87,8 +87,8 @@ bool WifiConnector::connect(void) {
WiFiManagerParameter disableCloudInfo(
"
Prevent connection to the AirGradient Server. Important: Only enable "
"it if you are sure you don't want to use any AirGradient cloud "
- "features. As a result you will not receive automatic firmware updates "
- "configure from cloud and your data will not reach the AirGradient dashboard.
");
+ "features. As a result you will not receive automatic firmware updates, "
+ "configuration settings from cloud and the measure data will not reach the AirGradient dashboard.");
WIFI()->addParameter(&disableCloudInfo);
WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT);
From 4b09b9852450faf3e90b2d37f4dae317787cf09d Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 10:57:02 +0700
Subject: [PATCH 25/36] Fix variable naming ahum to rhum
---
examples/BASIC/OpenMetrics.cpp | 8 ++++----
examples/DiyProIndoorV3_3/OpenMetrics.cpp | 8 ++++----
examples/DiyProIndoorV4_2/OpenMetrics.cpp | 8 ++++----
examples/OneOpenAir/OpenMetrics.cpp | 10 +++++-----
4 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/examples/BASIC/OpenMetrics.cpp b/examples/BASIC/OpenMetrics.cpp
index 9ceddcb..baa91d1 100644
--- a/examples/BASIC/OpenMetrics.cpp
+++ b/examples/BASIC/OpenMetrics.cpp
@@ -66,7 +66,7 @@ String OpenMetrics::getPayload(void) {
int pm03PCount = utils::getInvalidPmValue();
int co2 = utils::getInvalidCO2();
int atmpCompensated = utils::getInvalidTemperature();
- int ahumCompensated = utils::getInvalidHumidity();
+ int rhumCompensated = utils::getInvalidHumidity();
int tvoc = utils::getInvalidVOC();
int tvocRaw = utils::getInvalidVOC();
int nox = utils::getInvalidNOx();
@@ -76,7 +76,7 @@ String OpenMetrics::getPayload(void) {
_temp = measure.getFloat(Measurements::Temperature);
_hum = measure.getFloat(Measurements::Humidity);
atmpCompensated = _temp;
- ahumCompensated = _hum;
+ rhumCompensated = _hum;
}
if (config.hasSensorPMS1) {
@@ -191,12 +191,12 @@ String OpenMetrics::getPayload(void) {
"gauge", "percent");
add_metric_point("", String(_hum));
}
- if (utils::isValidHumidity(ahumCompensated)) {
+ if (utils::isValidHumidity(rhumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",
"gauge", "percent");
- add_metric_point("", String(ahumCompensated));
+ add_metric_point("", String(rhumCompensated));
}
response += "# EOF\n";
diff --git a/examples/DiyProIndoorV3_3/OpenMetrics.cpp b/examples/DiyProIndoorV3_3/OpenMetrics.cpp
index 5984c0d..6abfb2f 100644
--- a/examples/DiyProIndoorV3_3/OpenMetrics.cpp
+++ b/examples/DiyProIndoorV3_3/OpenMetrics.cpp
@@ -66,7 +66,7 @@ String OpenMetrics::getPayload(void) {
int pm03PCount = utils::getInvalidPmValue();
int co2 = utils::getInvalidCO2();
int atmpCompensated = utils::getInvalidTemperature();
- int ahumCompensated = utils::getInvalidHumidity();
+ int rhumCompensated = utils::getInvalidHumidity();
int tvoc = utils::getInvalidVOC();
int tvocRaw = utils::getInvalidVOC();
int nox = utils::getInvalidNOx();
@@ -76,7 +76,7 @@ String OpenMetrics::getPayload(void) {
_temp = measure.getFloat(Measurements::Temperature);
_hum = measure.getFloat(Measurements::Humidity);
atmpCompensated = _temp;
- ahumCompensated = _hum;
+ rhumCompensated = _hum;
}
if (config.hasSensorPMS1) {
@@ -192,12 +192,12 @@ String OpenMetrics::getPayload(void) {
"gauge", "percent");
add_metric_point("", String(_hum));
}
- if (utils::isValidHumidity(ahumCompensated)) {
+ if (utils::isValidHumidity(rhumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",
"gauge", "percent");
- add_metric_point("", String(ahumCompensated));
+ add_metric_point("", String(rhumCompensated));
}
response += "# EOF\n";
diff --git a/examples/DiyProIndoorV4_2/OpenMetrics.cpp b/examples/DiyProIndoorV4_2/OpenMetrics.cpp
index 9ceddcb..baa91d1 100644
--- a/examples/DiyProIndoorV4_2/OpenMetrics.cpp
+++ b/examples/DiyProIndoorV4_2/OpenMetrics.cpp
@@ -66,7 +66,7 @@ String OpenMetrics::getPayload(void) {
int pm03PCount = utils::getInvalidPmValue();
int co2 = utils::getInvalidCO2();
int atmpCompensated = utils::getInvalidTemperature();
- int ahumCompensated = utils::getInvalidHumidity();
+ int rhumCompensated = utils::getInvalidHumidity();
int tvoc = utils::getInvalidVOC();
int tvocRaw = utils::getInvalidVOC();
int nox = utils::getInvalidNOx();
@@ -76,7 +76,7 @@ String OpenMetrics::getPayload(void) {
_temp = measure.getFloat(Measurements::Temperature);
_hum = measure.getFloat(Measurements::Humidity);
atmpCompensated = _temp;
- ahumCompensated = _hum;
+ rhumCompensated = _hum;
}
if (config.hasSensorPMS1) {
@@ -191,12 +191,12 @@ String OpenMetrics::getPayload(void) {
"gauge", "percent");
add_metric_point("", String(_hum));
}
- if (utils::isValidHumidity(ahumCompensated)) {
+ if (utils::isValidHumidity(rhumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",
"gauge", "percent");
- add_metric_point("", String(ahumCompensated));
+ add_metric_point("", String(rhumCompensated));
}
response += "# EOF\n";
diff --git a/examples/OneOpenAir/OpenMetrics.cpp b/examples/OneOpenAir/OpenMetrics.cpp
index 393025c..0ad038b 100644
--- a/examples/OneOpenAir/OpenMetrics.cpp
+++ b/examples/OneOpenAir/OpenMetrics.cpp
@@ -66,7 +66,7 @@ String OpenMetrics::getPayload(void) {
int pm03PCount = utils::getInvalidPmValue();
int co2 = utils::getInvalidCO2();
int atmpCompensated = utils::getInvalidTemperature();
- int ahumCompensated = utils::getInvalidHumidity();
+ int rhumCompensated = utils::getInvalidHumidity();
int tvoc = utils::getInvalidVOC();
int tvocRaw = utils::getInvalidVOC();
int nox = utils::getInvalidNOx();
@@ -138,12 +138,12 @@ String OpenMetrics::getPayload(void) {
/** Get temperature and humidity compensated */
if (ag->isOne()) {
atmpCompensated = round(measure.getCorrectedTempHum(Measurements::Temperature));
- ahumCompensated = round(measure.getCorrectedTempHum(Measurements::Humidity));
+ rhumCompensated = round(measure.getCorrectedTempHum(Measurements::Humidity));
} else {
atmpCompensated = round((measure.getCorrectedTempHum(Measurements::Temperature, 1) +
measure.getCorrectedTempHum(Measurements::Temperature, 2)) /
2.0f);
- ahumCompensated = round((measure.getCorrectedTempHum(Measurements::Humidity, 1) +
+ rhumCompensated = round((measure.getCorrectedTempHum(Measurements::Humidity, 1) +
measure.getCorrectedTempHum(Measurements::Humidity, 2)) /
2.0f);
}
@@ -238,11 +238,11 @@ String OpenMetrics::getPayload(void) {
"gauge", "percent");
add_metric_point("", String(_hum));
}
- if (utils::isValidHumidity(ahumCompensated)) {
+ if (utils::isValidHumidity(rhumCompensated)) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the AirGradient SHT / PMS sensor",
"gauge", "percent");
- add_metric_point("", String(ahumCompensated));
+ add_metric_point("", String(rhumCompensated));
}
response += "# EOF\n";
From 15869be234482a5f3a965ab1b3b62d7f71b795e2 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 11:05:36 +0700
Subject: [PATCH 26/36] Rename prefix temp hum correction enum member
---
src/AgConfigure.cpp | 20 ++++++++++----------
src/AgValue.cpp | 12 ++++++------
src/App/AppDef.h | 8 ++++----
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 63e5e8f..5fa8d3c 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -34,10 +34,10 @@ const char *PM_CORRECTION_ALGORITHM_NAMES[] = {
};
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",
+ [COR_ALGO_TEMP_HUM_UNKNOWN] = "-", // This is only to pass "non-trivial designated initializers" error
+ [COR_ALGO_TEMP_HUM_NONE] = "none",
+ [COR_ALGO_TEMP_HUM_AG_PMS5003T_2024] = "ag_pms5003t_2024",
+ [COR_ALGO_TEMP_HUM_SLR_CUSTOM] = "custom",
};
#define JSON_PROP_NAME(name) jprop_##name
@@ -128,8 +128,8 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
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;
+ const int enumSize = static_cast(COR_ALGO_TEMP_HUM_SLR_CUSTOM);
+ TempHumCorrectionAlgorithm result = COR_ALGO_TEMP_HUM_UNKNOWN;
// Loop through enum values
for (size_t enumVal = 0; enumVal <= enumSize; enumVal++) {
@@ -251,7 +251,7 @@ bool Configuration::updateTempHumCorrection(JSONVar &json, TempHumCorrection &ta
String algorithm = correctionTarget["correctionAlgorithm"];
TempHumCorrectionAlgorithm algo = matchTempHumAlgorithm(algorithm);
- if (algo == CA_TH_UNKNOWN) {
+ if (algo == COR_ALGO_TEMP_HUM_UNKNOWN) {
logInfo("Uknown temp/hum algorithm");
return false;
}
@@ -259,7 +259,7 @@ bool Configuration::updateTempHumCorrection(JSONVar &json, TempHumCorrection &ta
// 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 (algo == COR_ALGO_TEMP_HUM_NONE || algo == COR_ALGO_TEMP_HUM_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;
@@ -1376,7 +1376,7 @@ void Configuration::toConfig(const char *buf) {
// Temperature correction
/// Set default first before parsing local config
- tempCorrection.algorithm = CA_TH_NONE;
+ tempCorrection.algorithm = COR_ALGO_TEMP_HUM_NONE;
tempCorrection.intercept = 0;
tempCorrection.scalingFactor = 0;
/// Load correction from saved config
@@ -1384,7 +1384,7 @@ void Configuration::toConfig(const char *buf) {
// Relative humidity correction
/// Set default first before parsing local config
- rhumCorrection.algorithm = CA_TH_NONE;
+ rhumCorrection.algorithm = COR_ALGO_TEMP_HUM_NONE;
rhumCorrection.intercept = 0;
rhumCorrection.scalingFactor = 0;
/// Load correction from saved config
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index c6be2e8..c7b2272 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -554,9 +554,9 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
Configuration::TempHumCorrection tmp = config.getTempCorrection();
// Apply 'standard' correction if its defined or correction forced
- if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024) {
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_AG_PMS5003T_2024) {
return ag->pms5003t_1.compensateTemp(rawValue);
- } else if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE && forceCorrection) {
+ } else if (tmp.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_NONE && forceCorrection) {
return ag->pms5003t_1.compensateTemp(rawValue);
}
@@ -570,9 +570,9 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
Configuration::TempHumCorrection tmp = config.getHumCorrection();
// Apply 'standard' correction if its defined or correction forced
- if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_AG_PMS5003T_2024) {
+ if (tmp.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_AG_PMS5003T_2024) {
return ag->pms5003t_1.compensateHum(rawValue);
- } else if (tmp.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE && forceCorrection) {
+ } else if (tmp.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_NONE && forceCorrection) {
return ag->pms5003t_1.compensateHum(rawValue);
}
@@ -588,8 +588,8 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
}
// Use raw if correction not defined
- if (correction.algorithm == TempHumCorrectionAlgorithm::CA_TH_NONE ||
- correction.algorithm == TempHumCorrectionAlgorithm::CA_TH_UNKNOWN) {
+ if (correction.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_NONE ||
+ correction.algorithm == TempHumCorrectionAlgorithm::COR_ALGO_TEMP_HUM_UNKNOWN) {
return rawValue;
}
diff --git a/src/App/AppDef.h b/src/App/AppDef.h
index 9a03a71..20b8b01 100644
--- a/src/App/AppDef.h
+++ b/src/App/AppDef.h
@@ -108,10 +108,10 @@ enum PMCorrectionAlgorithm {
// 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
+ COR_ALGO_TEMP_HUM_UNKNOWN, // Unknown algorithm
+ COR_ALGO_TEMP_HUM_NONE, // No PM correction
+ COR_ALGO_TEMP_HUM_AG_PMS5003T_2024,
+ COR_ALGO_TEMP_HUM_SLR_CUSTOM
};
enum AgFirmwareMode {
From 29d701780a5389e3af53893db5905c687f37fd11 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 11:37:16 +0700
Subject: [PATCH 27/36] Improve logging
---
examples/BASIC/BASIC.ino | 2 +-
examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 2 +-
examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 2 +-
examples/OneOpenAir/OneOpenAir.ino | 8 ++++----
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino
index 94a7fe0..6b4e476 100644
--- a/examples/BASIC/BASIC.ino
+++ b/examples/BASIC/BASIC.ino
@@ -533,7 +533,7 @@ static void sendDataToServer(void) {
measurements.setBootCount(bootCount);
if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
- Serial.println("Ignore send data to server. Either mode is offline "
+ Serial.println("Skipping transmission of data to AG server. Either mode is offline "
"or post data to server disabled");
return;
}
diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
index 4969af8..53b0ac8 100644
--- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
+++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino
@@ -585,7 +585,7 @@ static void sendDataToServer(void) {
measurements.setBootCount(bootCount);
if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
- Serial.println("Ignore send data to server. Either mode is offline "
+ Serial.println("Skipping transmission of data to AG server. Either mode is offline "
"or post data to server disabled");
return;
}
diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
index e3db76e..bd485aa 100644
--- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
+++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino
@@ -626,7 +626,7 @@ static void sendDataToServer(void) {
measurements.setBootCount(bootCount);
if (configuration.isOfflineMode() || !configuration.isPostDataToAirGradient()) {
- Serial.println("Ignore send data to server. Either mode is offline "
+ Serial.println("Skipping transmission of data to AG server. Either mode is offline "
"or post data to server disabled");
return;
}
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 976c6ac..d3c66f4 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -464,9 +464,9 @@ static bool sgp41Init(void) {
return false;
}
-static void firmwareCheckForUpdate(void) {
+static void checkForFirmwareUpdate(void) {
Serial.println();
- Serial.print("firmwareCheckForUpdate: ");
+ Serial.print("checkForFirmwareUpdate: ");
if (configuration.isOfflineMode() || configuration.isCloudConnectionDisabled()) {
Serial.println("mode is offline or cloud connection disabled, ignored");
@@ -870,7 +870,7 @@ void initializeNetwork() {
// Initialize api client
apiClient.begin();
- // Check and process if AirGradient server is reachable
+ // Send data for the first time to airgradient at boot
sendDataToAg();
// OTA check
@@ -1188,7 +1188,7 @@ static void sendDataToServer(void) {
if (configuration.isOfflineMode() || configuration.isCloudConnectionDisabled() ||
!configuration.isPostDataToAirGradient()) {
- Serial.println("Ignore send data to server. Either mode is offline or cloud connection is "
+ Serial.println("Skipping transmission of data to AG server. Either mode is offline or cloud connection is "
"disabled or post data to server disabled");
return;
}
From bd9dbec663e231ca0aa0c86a0ca8f17cfc6bd2de Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 13:46:10 +0700
Subject: [PATCH 28/36] Rename functions
---
examples/OneOpenAir/OneOpenAir.ino | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index d3c66f4..4714765 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -112,7 +112,7 @@ static void factoryConfigReset(void);
static void wdgFeedUpdate(void);
static void ledBarEnabledUpdate(void);
static bool sgp41Init(void);
-static void firmwareCheckForUpdate(void);
+static void checkForFirmwareUpdate(void);
static void otaHandlerCallback(OtaHandler::OtaState state, String mesasge);
static void displayExecuteOta(OtaHandler::OtaState state, String msg, int processing);
static int calculateMaxPeriod(int updateInterval);
@@ -127,7 +127,7 @@ AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, updatePm);
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate);
-AgSchedule checkForUpdateSchedule(FIRMWARE_CHECK_FOR_UPDATE_MS, firmwareCheckForUpdate);
+AgSchedule checkForUpdateSchedule(FIRMWARE_CHECK_FOR_UPDATE_MS, checkForFirmwareUpdate);
void setup() {
/** Serial for print debug message */
@@ -877,7 +877,7 @@ void initializeNetwork() {
#ifdef ESP8266
// ota not supported
#else
- firmwareCheckForUpdate();
+ checkForFirmwareUpdate();
checkForUpdateSchedule.update();
#endif
From 830f652bf95d171a78f2980aad311f34cda54312 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 13:52:38 +0700
Subject: [PATCH 29/36] Remove unnecessary todo
---
src/AgConfigure.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 5fa8d3c..eb4f838 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -143,7 +143,6 @@ TempHumCorrectionAlgorithm Configuration::matchTempHumAlgorithm(String algorithm
bool Configuration::updatePmCorrection(JSONVar &json) {
if (!json.hasOwnProperty("corrections")) {
- // TODO: need to response message?
Serial.println("corrections not found");
return false;
}
@@ -232,7 +231,6 @@ bool Configuration::updatePmCorrection(JSONVar &json) {
bool Configuration::updateTempHumCorrection(JSONVar &json, TempHumCorrection &target,
const char *correctionName) {
if (!json.hasOwnProperty(jprop_corrections)) {
- // TODO: need to response message?
return false;
}
From 0e26aa1b5d04a0d2e9962a1f3a0dc6df0f33243d Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Wed, 5 Feb 2025 14:06:33 +0700
Subject: [PATCH 30/36] Improve comments
---
examples/OneOpenAir/OneOpenAir.ino | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 4714765..ca411b1 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -870,7 +870,7 @@ void initializeNetwork() {
// Initialize api client
apiClient.begin();
- // Send data for the first time to airgradient at boot
+ // Send data for the first time to AG server at boot
sendDataToAg();
// OTA check
From 38aebeb50affcc72d379676248ace487b4481923 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 6 Feb 2025 12:49:41 +0700
Subject: [PATCH 31/36] Reformat pm correction enum naming
---
src/AgConfigure.cpp | 36 ++++++++++++++++++------------------
src/AgValue.cpp | 6 +++---
src/App/AppDef.h | 18 +++++++++---------
3 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index ccf1f76..08595d3 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -22,15 +22,15 @@ const char *LED_BAR_MODE_NAMES[] = {
};
const char *PM_CORRECTION_ALGORITHM_NAMES[] = {
- [Unknown] = "-", // This is only to pass "non-trivial designated initializers" error
- [None] = "none",
- [EPA_2021] = "epa_2021",
- [SLR_PMS5003_20220802] = "slr_PMS5003_20220802",
- [SLR_PMS5003_20220803] = "slr_PMS5003_20220803",
- [SLR_PMS5003_20220824] = "slr_PMS5003_20220824",
- [SLR_PMS5003_20231030] = "slr_PMS5003_20231030",
- [SLR_PMS5003_20231218] = "slr_PMS5003_20231218",
- [SLR_PMS5003_20240104] = "slr_PMS5003_20240104",
+ [COR_ALGO_PM_UNKNOWN] = "-", // This is only to pass "non-trivial designated initializers" error
+ [COR_ALGO_PM_NONE] = "none",
+ [COR_ALGO_PM_EPA_2021] = "epa_2021",
+ [COR_ALGO_PM_PMS5003_20220802] = "slr_PMS5003_20220802",
+ [COR_ALGO_PM_PMS5003_20220803] = "slr_PMS5003_20220803",
+ [COR_ALGO_PM_PMS5003_20220824] = "slr_PMS5003_20220824",
+ [COR_ALGO_PM_PMS5003_20231030] = "slr_PMS5003_20231030",
+ [COR_ALGO_PM_PMS5003_20231218] = "slr_PMS5003_20231218",
+ [COR_ALGO_PM_PMS5003_20240104] = "slr_PMS5003_20240104",
};
const char *TEMP_HUM_CORRECTION_ALGORITHM_NAMES[] = {
@@ -115,8 +115,8 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
// If the input string matches an algorithm name, return the corresponding enum value
// Else return Unknown
- const size_t enumSize = SLR_PMS5003_20240104 + 1; // Get the actual size of the enum
- PMCorrectionAlgorithm result = PMCorrectionAlgorithm::Unknown;
+ const size_t enumSize = COR_ALGO_PM_PMS5003_20240104 + 1; // Get the actual size of the enum
+ PMCorrectionAlgorithm result = COR_ALGO_PM_UNKNOWN;;
// Loop through enum values
for (size_t enumVal = 0; enumVal < enumSize; enumVal++) {
@@ -166,7 +166,7 @@ bool Configuration::updatePmCorrection(JSONVar &json) {
// Check algorithm
String algorithm = pm02["correctionAlgorithm"];
PMCorrectionAlgorithm algo = matchPmAlgorithm(algorithm);
- if (algo == Unknown) {
+ if (algo == COR_ALGO_PM_UNKNOWN) {
logInfo("Unknown algorithm");
return false;
}
@@ -174,7 +174,7 @@ bool Configuration::updatePmCorrection(JSONVar &json) {
// If algo is None or EPA_2021, no need to check slr
// But first check if pmCorrection different from algo
- if (algo == None || algo == EPA_2021) {
+ if (algo == COR_ALGO_PM_NONE || algo == COR_ALGO_PM_EPA_2021) {
if (pmCorrection.algorithm != algo) {
// Deep copy corrections from root to jconfig, so it will be saved later
jconfig[jprop_corrections]["pm02"]["correctionAlgorithm"] = algorithm;
@@ -397,8 +397,8 @@ void Configuration::defaultConfig(void) {
jconfig[jprop_offlineMode] = jprop_offlineMode_default;
jconfig[jprop_monitorDisplayCompensatedValues] = jprop_monitorDisplayCompensatedValues_default;
- // PM2.5 correction
- pmCorrection.algorithm = None;
+ // PM2.5 default correction
+ pmCorrection.algorithm = COR_ALGO_PM_NONE;
pmCorrection.changed = false;
pmCorrection.intercept = 0;
pmCorrection.scalingFactor = 1;
@@ -1380,7 +1380,7 @@ void Configuration::toConfig(const char *buf) {
// PM2.5 correction
/// Set default first before parsing local config
- pmCorrection.algorithm = PMCorrectionAlgorithm::None;
+ pmCorrection.algorithm = COR_ALGO_PM_NONE;
pmCorrection.intercept = 0;
pmCorrection.scalingFactor = 0;
pmCorrection.useEPA = false;
@@ -1526,8 +1526,8 @@ bool Configuration::isPMCorrectionChanged(void) {
*/
bool Configuration::isPMCorrectionEnabled(void) {
PMCorrection pmCorrection = getPMCorrection();
- if (pmCorrection.algorithm == PMCorrectionAlgorithm::None ||
- pmCorrection.algorithm == PMCorrectionAlgorithm::Unknown) {
+ if (pmCorrection.algorithm == COR_ALGO_PM_NONE ||
+ pmCorrection.algorithm == COR_ALGO_PM_UNKNOWN) {
return false;
}
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index fac0802..35e21d5 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -658,12 +658,12 @@ float Measurements::getCorrectedPM25(bool useAvg, int ch) {
Configuration::PMCorrection pmCorrection = config.getPMCorrection();
switch (pmCorrection.algorithm) {
- case PMCorrectionAlgorithm::Unknown:
- case PMCorrectionAlgorithm::None:
+ case PMCorrectionAlgorithm::COR_ALGO_PM_UNKNOWN:
+ case PMCorrectionAlgorithm::COR_ALGO_PM_NONE:
// If correction is Unknown, then default is None
corrected = pm25;
break;
- case PMCorrectionAlgorithm::EPA_2021:
+ case PMCorrectionAlgorithm::COR_ALGO_PM_EPA_2021:
corrected = ag->pms5003.compensate(pm25, humidity);
break;
default: {
diff --git a/src/App/AppDef.h b/src/App/AppDef.h
index 20b8b01..f18970e 100644
--- a/src/App/AppDef.h
+++ b/src/App/AppDef.h
@@ -95,15 +95,15 @@ enum ConfigurationControl {
};
enum PMCorrectionAlgorithm {
- Unknown, // Unknown algorithm
- None, // No PM correction
- EPA_2021,
- SLR_PMS5003_20220802,
- SLR_PMS5003_20220803,
- SLR_PMS5003_20220824,
- SLR_PMS5003_20231030,
- SLR_PMS5003_20231218,
- SLR_PMS5003_20240104,
+ COR_ALGO_PM_UNKNOWN, // Unknown algorithm
+ COR_ALGO_PM_NONE, // No PM correction
+ COR_ALGO_PM_EPA_2021,
+ COR_ALGO_PM_PMS5003_20220802,
+ COR_ALGO_PM_PMS5003_20220803,
+ COR_ALGO_PM_PMS5003_20220824,
+ COR_ALGO_PM_PMS5003_20231030,
+ COR_ALGO_PM_PMS5003_20231218,
+ COR_ALGO_PM_PMS5003_20240104,
};
// Don't change the order of the enum
From 17d2e62b1538de9f9e03c6765d23df5da89dd79a Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 6 Feb 2025 15:38:36 +0700
Subject: [PATCH 32/36] Remove delayed oled display
---
examples/OneOpenAir/OneOpenAir.ino | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index 2296c52..f88c441 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -613,7 +613,7 @@ static void sendDataToAg() {
}
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnectFailed);
}
- delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
+
stateMachine.handleLeds(AgStateMachineNormal);
}
From 1c42ff083dd724e7bed4c159a00446daafdcdb7b Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 6 Feb 2025 15:58:15 +0700
Subject: [PATCH 33/36] Make PM correction applied for all model
---
src/AgConfigure.cpp | 1 -
src/AgValue.cpp | 112 +++++++++++++++++++++-----------------------
src/AgValue.h | 3 +-
3 files changed, 55 insertions(+), 61 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 08595d3..6e0f724 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -238,7 +238,6 @@ bool Configuration::updateTempHumCorrection(JSONVar &json, TempHumCorrection &ta
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;
}
diff --git a/src/AgValue.cpp b/src/AgValue.cpp
index 35e21d5..0bed140 100644
--- a/src/AgValue.cpp
+++ b/src/AgValue.cpp
@@ -639,7 +639,7 @@ float Measurements::getCorrectedTempHum(MeasurementType type, int ch, bool force
return corrected;
}
-float Measurements::getCorrectedPM25(bool useAvg, int ch) {
+float Measurements::getCorrectedPM25(bool useAvg, int ch, bool forceCorrection) {
float pm25;
float corrected;
float humidity;
@@ -659,10 +659,16 @@ float Measurements::getCorrectedPM25(bool useAvg, int ch) {
Configuration::PMCorrection pmCorrection = config.getPMCorrection();
switch (pmCorrection.algorithm) {
case PMCorrectionAlgorithm::COR_ALGO_PM_UNKNOWN:
- case PMCorrectionAlgorithm::COR_ALGO_PM_NONE:
- // If correction is Unknown, then default is None
- corrected = pm25;
+ case PMCorrectionAlgorithm::COR_ALGO_PM_NONE: {
+ // If correction is Unknown or None, then default is None
+ // Unless forceCorrection enabled
+ if (forceCorrection) {
+ corrected = ag->pms5003.compensate(pm25, humidity);
+ } else {
+ corrected = pm25;
+ }
break;
+ }
case PMCorrectionAlgorithm::COR_ALGO_PM_EPA_2021:
corrected = ag->pms5003.compensate(pm25, humidity);
break;
@@ -780,8 +786,8 @@ JSONVar Measurements::buildIndoor(bool localServer) {
// buildPMS params:
/// PMS channel 1 (indoor only have 1 PMS; hence allCh false)
/// Not include temperature and humidity from PMS sensor
- /// Not include compensated calculation
- indoor = buildPMS(1, false, false, false);
+ /// Include compensated calculation
+ indoor = buildPMS(1, false, false, true);
if (!localServer) {
// Indoor is using PMS5003
indoor[json_prop_pmFirmware] = this->pms5003FirmwareVersion(ag->pms5003.getFirmwareVersion());
@@ -805,15 +811,6 @@ JSONVar Measurements::buildIndoor(bool localServer) {
}
}
- // Add pm25 compensated value only if PM2.5 and humidity value is valid
- if (config.hasSensorPMS1 && utils::isValidPm(_pm_25[0].update.avg)) {
- if (config.hasSensorSHT && utils::isValidHumidity(_humidity[0].update.avg)) {
- // Correction using moving average value
- float tmp = getCorrectedPM25(true);
- indoor[json_prop_pm25Compensated] = ag->round2(tmp);
- }
- }
-
return indoor;
}
@@ -826,58 +823,58 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
validateChannel(ch);
// Follow array indexing just for get address of the value type
- ch = ch - 1;
+ int chIndex = ch - 1;
- if (utils::isValidPm(_pm_01[ch].update.avg)) {
- pms[json_prop_pm01Ae] = ag->round2(_pm_01[ch].update.avg);
+ if (utils::isValidPm(_pm_01[chIndex].update.avg)) {
+ pms[json_prop_pm01Ae] = ag->round2(_pm_01[chIndex].update.avg);
}
- if (utils::isValidPm(_pm_25[ch].update.avg)) {
- pms[json_prop_pm25Ae] = ag->round2(_pm_25[ch].update.avg);
+ if (utils::isValidPm(_pm_25[chIndex].update.avg)) {
+ pms[json_prop_pm25Ae] = ag->round2(_pm_25[chIndex].update.avg);
}
- if (utils::isValidPm(_pm_10[ch].update.avg)) {
- pms[json_prop_pm10Ae] = ag->round2(_pm_10[ch].update.avg);
+ if (utils::isValidPm(_pm_10[chIndex].update.avg)) {
+ pms[json_prop_pm10Ae] = ag->round2(_pm_10[chIndex].update.avg);
}
- if (utils::isValidPm(_pm_01_sp[ch].update.avg)) {
- pms[json_prop_pm01Sp] = ag->round2(_pm_01_sp[ch].update.avg);
+ if (utils::isValidPm(_pm_01_sp[chIndex].update.avg)) {
+ pms[json_prop_pm01Sp] = ag->round2(_pm_01_sp[chIndex].update.avg);
}
- if (utils::isValidPm(_pm_25_sp[ch].update.avg)) {
- pms[json_prop_pm25Sp] = ag->round2(_pm_25_sp[ch].update.avg);
+ if (utils::isValidPm(_pm_25_sp[chIndex].update.avg)) {
+ pms[json_prop_pm25Sp] = ag->round2(_pm_25_sp[chIndex].update.avg);
}
- if (utils::isValidPm(_pm_10_sp[ch].update.avg)) {
- pms[json_prop_pm10Sp] = ag->round2(_pm_10_sp[ch].update.avg);
+ if (utils::isValidPm(_pm_10_sp[chIndex].update.avg)) {
+ pms[json_prop_pm10Sp] = ag->round2(_pm_10_sp[chIndex].update.avg);
}
- if (utils::isValidPm03Count(_pm_03_pc[ch].update.avg)) {
- pms[json_prop_pm03Count] = ag->round2(_pm_03_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_03_pc[chIndex].update.avg)) {
+ pms[json_prop_pm03Count] = ag->round2(_pm_03_pc[chIndex].update.avg);
}
- if (utils::isValidPm03Count(_pm_05_pc[ch].update.avg)) {
- pms[json_prop_pm05Count] = ag->round2(_pm_05_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_05_pc[chIndex].update.avg)) {
+ pms[json_prop_pm05Count] = ag->round2(_pm_05_pc[chIndex].update.avg);
}
- if (utils::isValidPm03Count(_pm_01_pc[ch].update.avg)) {
- pms[json_prop_pm1Count] = ag->round2(_pm_01_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_01_pc[chIndex].update.avg)) {
+ pms[json_prop_pm1Count] = ag->round2(_pm_01_pc[chIndex].update.avg);
}
- if (utils::isValidPm03Count(_pm_25_pc[ch].update.avg)) {
- pms[json_prop_pm25Count] = ag->round2(_pm_25_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_25_pc[chIndex].update.avg)) {
+ pms[json_prop_pm25Count] = ag->round2(_pm_25_pc[chIndex].update.avg);
}
- if (_pm_5_pc[ch].listValues.empty() == false) {
+ if (_pm_5_pc[chIndex].listValues.empty() == false) {
// Only include pm5.0 count when values available on its list
// If not, means no pm5_pc available from the sensor
- if (utils::isValidPm03Count(_pm_5_pc[ch].update.avg)) {
- pms[json_prop_pm5Count] = ag->round2(_pm_5_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_5_pc[chIndex].update.avg)) {
+ pms[json_prop_pm5Count] = ag->round2(_pm_5_pc[chIndex].update.avg);
}
}
- if (_pm_10_pc[ch].listValues.empty() == false) {
+ if (_pm_10_pc[chIndex].listValues.empty() == false) {
// Only include pm10 count when values available on its list
// If not, means no pm10_pc available from the sensor
- if (utils::isValidPm03Count(_pm_10_pc[ch].update.avg)) {
- pms[json_prop_pm10Count] = ag->round2(_pm_10_pc[ch].update.avg);
+ if (utils::isValidPm03Count(_pm_10_pc[chIndex].update.avg)) {
+ pms[json_prop_pm10Count] = ag->round2(_pm_10_pc[chIndex].update.avg);
}
}
if (withTempHum) {
float _vc;
// Set temperature if valid
- if (utils::isValidTemperature(_temperature[ch].update.avg)) {
- pms[json_prop_temp] = ag->round2(_temperature[ch].update.avg);
+ if (utils::isValidTemperature(_temperature[chIndex].update.avg)) {
+ pms[json_prop_temp] = ag->round2(_temperature[chIndex].update.avg);
// Compensate temperature when flag is set
if (compensate) {
_vc = getCorrectedTempHum(Temperature, ch, true);
@@ -887,8 +884,8 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
}
}
// Set humidity if valid
- if (utils::isValidHumidity(_humidity[ch].update.avg)) {
- pms[json_prop_rhum] = ag->round2(_humidity[ch].update.avg);
+ if (utils::isValidHumidity(_humidity[chIndex].update.avg)) {
+ pms[json_prop_rhum] = ag->round2(_humidity[chIndex].update.avg);
// Compensate relative humidity when flag is set
if (compensate) {
_vc = getCorrectedTempHum(Humidity, ch, true);
@@ -898,17 +895,14 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
}
}
- // Add pm25 compensated value only if PM2.5 and humidity value is valid
- if (compensate) {
- if (utils::isValidPm(_pm_25[ch].update.avg) &&
- utils::isValidHumidity(_humidity[ch].update.avg)) {
- // Note: the pms5003t object is not matter either for channel 1 or 2, compensate points to
- // the same base function
- float pm25 = ag->pms5003t_1.compensate(_pm_25[ch].update.avg, _humidity[ch].update.avg);
- if (utils::isValidPm(pm25)) {
- pms[json_prop_pm25Compensated] = ag->round2(pm25);
- }
- }
+ }
+
+ // Add pm25 compensated value only if PM2.5 and humidity value is valid
+ if (compensate) {
+ if (utils::isValidPm(_pm_25[chIndex].update.avg) &&
+ utils::isValidHumidity(_humidity[chIndex].update.avg)) {
+ float pm25 = getCorrectedPM25(true, ch, true);
+ pms[json_prop_pm25Compensated] = ag->round2(pm25);
}
}
@@ -1156,12 +1150,12 @@ JSONVar Measurements::buildPMS(int ch, bool allCh, bool withTempHum, bool compen
float pm25_comp2 = utils::getInvalidPmValue();
if (utils::isValidPm(_pm_25[0].update.avg) &&
utils::isValidHumidity(_humidity[0].update.avg)) {
- pm25_comp1 = ag->pms5003t_1.compensate(_pm_25[0].update.avg, _humidity[0].update.avg);
+ pm25_comp1 = getCorrectedPM25(true, 1, true);
pms["channels"]["1"][json_prop_pm25Compensated] = ag->round2(pm25_comp1);
}
if (utils::isValidPm(_pm_25[1].update.avg) &&
utils::isValidHumidity(_humidity[1].update.avg)) {
- pm25_comp2 = ag->pms5003t_2.compensate(_pm_25[1].update.avg, _humidity[1].update.avg);
+ pm25_comp2 = getCorrectedPM25(true, 2, true);
pms["channels"]["2"][json_prop_pm25Compensated] = ag->round2(pm25_comp2);
}
diff --git a/src/AgValue.h b/src/AgValue.h
index db5508e..9a3c446 100644
--- a/src/AgValue.h
+++ b/src/AgValue.h
@@ -144,9 +144,10 @@ public:
*
* @param useAvg Use moving average value if true, otherwise use latest value
* @param ch MeasurementType channel
+ * @param forceCorrection force using correction even though config correction is not applied, default to EPA
* @return float Corrected PM2.5 value
*/
- float getCorrectedPM25(bool useAvg = false, int ch = 1);
+ float getCorrectedPM25(bool useAvg = false, int ch = 1, bool forceCorrection = false);
/**
* build json payload for every measurements
From d4b4f51c3cd7b5639eef9c669a64cd9cd64e99f4 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Thu, 6 Feb 2025 17:35:01 +0700
Subject: [PATCH 34/36] Map batch PM correction as custom enum
---
src/AgConfigure.cpp | 32 +++++++++++++++++---------------
src/App/AppDef.h | 7 +------
2 files changed, 18 insertions(+), 21 deletions(-)
diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp
index 6e0f724..d2b6e81 100644
--- a/src/AgConfigure.cpp
+++ b/src/AgConfigure.cpp
@@ -25,12 +25,7 @@ const char *PM_CORRECTION_ALGORITHM_NAMES[] = {
[COR_ALGO_PM_UNKNOWN] = "-", // This is only to pass "non-trivial designated initializers" error
[COR_ALGO_PM_NONE] = "none",
[COR_ALGO_PM_EPA_2021] = "epa_2021",
- [COR_ALGO_PM_PMS5003_20220802] = "slr_PMS5003_20220802",
- [COR_ALGO_PM_PMS5003_20220803] = "slr_PMS5003_20220803",
- [COR_ALGO_PM_PMS5003_20220824] = "slr_PMS5003_20220824",
- [COR_ALGO_PM_PMS5003_20231030] = "slr_PMS5003_20231030",
- [COR_ALGO_PM_PMS5003_20231218] = "slr_PMS5003_20231218",
- [COR_ALGO_PM_PMS5003_20240104] = "slr_PMS5003_20240104",
+ [COR_ALGO_PM_SLR_CUSTOM] = "custom",
};
const char *TEMP_HUM_CORRECTION_ALGORITHM_NAMES[] = {
@@ -115,7 +110,7 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
// If the input string matches an algorithm name, return the corresponding enum value
// Else return Unknown
- const size_t enumSize = COR_ALGO_PM_PMS5003_20240104 + 1; // Get the actual size of the enum
+ const size_t enumSize = COR_ALGO_PM_SLR_CUSTOM + 1; // Get the actual size of the enum
PMCorrectionAlgorithm result = COR_ALGO_PM_UNKNOWN;;
// Loop through enum values
@@ -125,6 +120,15 @@ PMCorrectionAlgorithm Configuration::matchPmAlgorithm(String algorithm) {
}
}
+ // If string not match from enum, check if correctionAlgorithm is one of the PM batch corrections
+ if (result == COR_ALGO_PM_UNKNOWN) {
+ // Check the substring "slr_PMS5003_xxxxxxxx"
+ if (algorithm.substring(0, 11) == "slr_PMS5003") {
+ // If it is, then its a custom correction
+ result = COR_ALGO_PM_SLR_CUSTOM;
+ }
+ }
+
return result;
}
@@ -145,29 +149,27 @@ TempHumCorrectionAlgorithm Configuration::matchTempHumAlgorithm(String algorithm
bool Configuration::updatePmCorrection(JSONVar &json) {
if (!json.hasOwnProperty("corrections")) {
- Serial.println("corrections not found");
+ logInfo("corrections not found");
return false;
}
JSONVar corrections = json["corrections"];
if (!corrections.hasOwnProperty("pm02")) {
- Serial.println("pm02 not found");
+ logWarning("pm02 not found");
return false;
}
JSONVar pm02 = corrections["pm02"];
if (!pm02.hasOwnProperty("correctionAlgorithm")) {
- Serial.println("correctionAlgorithm not found");
+ logWarning("pm02 correctionAlgorithm not found");
return false;
}
- // TODO: Need to have data type check, with error message response if invalid
-
// Check algorithm
String algorithm = pm02["correctionAlgorithm"];
PMCorrectionAlgorithm algo = matchPmAlgorithm(algorithm);
if (algo == COR_ALGO_PM_UNKNOWN) {
- logInfo("Unknown algorithm");
+ logWarning("Unknown algorithm");
return false;
}
logInfo("Correction algorithm: " + algorithm);
@@ -191,7 +193,7 @@ bool Configuration::updatePmCorrection(JSONVar &json) {
// Check if pm02 has slr object
if (!pm02.hasOwnProperty("slr")) {
- Serial.println("slr not found");
+ logWarning("slr not found");
return false;
}
@@ -200,7 +202,7 @@ bool Configuration::updatePmCorrection(JSONVar &json) {
// Validate required slr properties exist
if (!slr.hasOwnProperty("intercept") || !slr.hasOwnProperty("scalingFactor") ||
!slr.hasOwnProperty("useEpa2021")) {
- Serial.println("Missing required slr properties");
+ logWarning("Missing required slr properties");
return false;
}
diff --git a/src/App/AppDef.h b/src/App/AppDef.h
index f18970e..a80032b 100644
--- a/src/App/AppDef.h
+++ b/src/App/AppDef.h
@@ -98,12 +98,7 @@ enum PMCorrectionAlgorithm {
COR_ALGO_PM_UNKNOWN, // Unknown algorithm
COR_ALGO_PM_NONE, // No PM correction
COR_ALGO_PM_EPA_2021,
- COR_ALGO_PM_PMS5003_20220802,
- COR_ALGO_PM_PMS5003_20220803,
- COR_ALGO_PM_PMS5003_20220824,
- COR_ALGO_PM_PMS5003_20231030,
- COR_ALGO_PM_PMS5003_20231218,
- COR_ALGO_PM_PMS5003_20240104,
+ COR_ALGO_PM_SLR_CUSTOM,
};
// Don't change the order of the enum
From 4c7e72b8e788397af8cc5a2f624886a9926293ab Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Fri, 7 Feb 2025 10:45:14 +0700
Subject: [PATCH 35/36] Better logging Fix notif when wifi not connect
---
examples/OneOpenAir/OneOpenAir.ino | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino
index f88c441..3202f12 100644
--- a/examples/OneOpenAir/OneOpenAir.ino
+++ b/examples/OneOpenAir/OneOpenAir.ino
@@ -908,6 +908,11 @@ static void configurationUpdateSchedule(void) {
return;
}
+ if (wifiConnector.isConnected() == false) {
+ Serial.println(" WiFi not connected, skipping fetch configuration from AG server");
+ return;
+ }
+
if (apiClient.fetchServerConfiguration()) {
configUpdateHandle();
}
@@ -1008,6 +1013,7 @@ static void updateDisplayAndLedBar(void) {
if (wifiConnector.isConnected() == false) {
stateMachine.displayHandle(AgStateMachineWiFiLost);
stateMachine.handleLeds(AgStateMachineWiFiLost);
+ return;
}
if (configuration.isCloudConnectionDisabled()) {
From 615c2389e7359193886ff3e998cb24c202ed8405 Mon Sep 17 00:00:00 2001
From: samuelbles07
Date: Fri, 7 Feb 2025 19:16:16 +0700
Subject: [PATCH 36/36] Prepare 3.2.0 alpha release
---
library.properties | 2 +-
src/AirGradient.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/library.properties b/library.properties
index e6acec0..5c34407 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=AirGradient Air Quality Sensor
-version=3.1.21
+version=3.2.0-alpha
author=AirGradient
maintainer=AirGradient
sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display.
diff --git a/src/AirGradient.h b/src/AirGradient.h
index 5c39243..386710b 100644
--- a/src/AirGradient.h
+++ b/src/AirGradient.h
@@ -15,7 +15,7 @@
#include "Main/utils.h"
#ifndef GIT_VERSION
-#define GIT_VERSION "3.1.21-snap"
+#define GIT_VERSION "3.2.0-snap"
#endif
#ifndef ESP8266