Compare commits

..

24 Commits

Author SHA1 Message Date
d8eb6b3c1a Prepare release 3.3.9 2025-06-18 14:25:14 +07:00
969858b5cb Merge pull request #324 from airgradienthq/fix/comms-ag-server
Post measures and fetch configuration on boot only if respective configuration is set
2025-06-10 01:29:58 +07:00
09b5805686 Apply brightness 2025-06-10 01:26:29 +07:00
b09b753339 Only send first measures on boot if postDataToAirgradient is enabled 2025-06-10 01:10:14 +07:00
ddb3dba131 Skip fetch configuration on boot when configuration control is local 2025-06-10 01:09:53 +07:00
e780b0ace6 Merge pull request #323 from airgradienthq/fix/local-config-update
Update configuration changes by callback
2025-06-09 02:21:07 +07:00
e82da5401e Add new flag for command request
Such as led bar test and co2 calibration test
2025-06-09 02:13:32 +07:00
50a98acde4 Update configuration changes to main by callback 2025-06-06 04:10:53 +07:00
7049d21a41 Prepare release 3.3.8 2025-05-14 13:09:12 +07:00
d5cdeaa9f3 Fix print average function schedule
if pms value invalid show the channel
2025-05-14 13:01:23 +07:00
09207c6923 Merge pull request #319 from airgradienthq/fix/resizing-queue
Fix resizing measurement queue after post by cellular post
2025-05-14 12:53:07 +07:00
0a64424196 add show content delay for display brightness 2025-05-14 12:39:42 +07:00
5b38ca222b Prepare release 3.3.7 2025-05-12 10:54:38 +07:00
9ee35341a5 Merge pull request #318 from airgradienthq/feat/improve-measure-logs
Improve measurements logging
2025-05-11 14:22:08 +07:00
cec0514444 print measurements on schedule 2025-05-11 14:10:51 +07:00
626a2240fa Fix resizing queue after success post
This fix should be make it more consistent
2025-05-09 15:45:53 +07:00
174ec6568f Merge pull request #313 from airgradienthq/fix/mode-cloud-disable
Fix bootloop when cloud connection is disabled
2025-05-08 01:28:07 +07:00
6b55719399 Fix cloud connection mode
Use continue instead of return to ignore the rest of transmission code
2025-05-05 17:37:28 +07:00
e2084f0738 Fix OTA request on boot when cloud Connection disabled 2025-05-05 17:36:14 +07:00
5e07923690 Merge pull request #311 from ccoley/fix/submodule-url
Fix failing to clone submodules recursively
2025-05-04 14:13:47 +07:00
04049439b1 Merge pull request #310 from airgradienthq/fix/openmetrics
Fix calling airgradient client before initialization on open metrics
2025-05-04 13:29:24 +07:00
c148d256d7 Use a relative path for submodule URL
We keep the username in the path so that forks don't need to also fork
the submodules
2025-04-30 23:25:30 -07:00
02849a1938 Fix pass agclient to openmetrics
previously, agclient initialized after setAirgradient
2025-05-01 13:38:42 +08:00
074337a96d Merge pull request #304 from airgradienthq/fix/api-root
FIX: HTTP domain configuration changes applied for OTA too
2025-04-21 13:42:26 +07:00
10 changed files with 254 additions and 50 deletions

4
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "src/Libraries/airgradient-client"] [submodule "src/Libraries/airgradient-client"]
path = src/Libraries/airgradient-client path = src/Libraries/airgradient-client
url = git@github.com:airgradienthq/airgradient-client.git url = ../../airgradienthq/airgradient-client.git
[submodule "src/Libraries/airgradient-ota"] [submodule "src/Libraries/airgradient-ota"]
path = src/Libraries/airgradient-ota path = src/Libraries/airgradient-ota
url = git@github.com:airgradienthq/airgradient-ota.git url = ../../airgradienthq/airgradient-ota.git

View File

@ -143,6 +143,7 @@ static void updatePm(void);
static void sendDataToServer(void); static void sendDataToServer(void);
static void tempHumUpdate(void); static void tempHumUpdate(void);
static void co2Update(void); static void co2Update(void);
static void printMeasurements();
static void mdnsInit(void); static void mdnsInit(void);
static void createMqttTask(void); static void createMqttTask(void);
static void initMqtt(void); static void initMqtt(void);
@ -172,6 +173,7 @@ AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate); AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate);
AgSchedule checkForUpdateSchedule(FIRMWARE_CHECK_FOR_UPDATE_MS, checkForFirmwareUpdate); AgSchedule checkForUpdateSchedule(FIRMWARE_CHECK_FOR_UPDATE_MS, checkForFirmwareUpdate);
AgSchedule networkSignalCheckSchedule(10000, networkSignalCheck); AgSchedule networkSignalCheckSchedule(10000, networkSignalCheck);
AgSchedule printMeasurementsSchedule(6000, printMeasurements);
void setup() { void setup() {
/** Serial for print debug message */ /** Serial for print debug message */
@ -191,6 +193,7 @@ void setup() {
/** Initialize local configure */ /** Initialize local configure */
configuration.begin(); configuration.begin();
configuration.setConfigurationUpdatedCallback(configUpdateHandle);
/** Init I2C */ /** Init I2C */
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
@ -210,7 +213,7 @@ void setup() {
oledDisplay.setAirGradient(ag); oledDisplay.setAirGradient(ag);
stateMachine.setAirGradient(ag); stateMachine.setAirGradient(ag);
wifiConnector.setAirGradient(ag); wifiConnector.setAirGradient(ag);
openMetrics.setAirGradient(ag, agClient); openMetrics.setAirGradient(ag);
localServer.setAirGraident(ag); localServer.setAirGraident(ag);
measurements.setAirGradient(ag); measurements.setAirGradient(ag);
@ -218,9 +221,6 @@ void setup() {
boardInit(); boardInit();
setMeasurementMaxPeriod(); setMeasurementMaxPeriod();
// Comment below line to disable debug measurement readings
measurements.setDebug(true);
bool connectToNetwork = true; bool connectToNetwork = true;
if (ag->isOne()) { // Offline mode only available for indoor monitor if (ag->isOne()) { // Offline mode only available for indoor monitor
/** Show message confirm offline mode, should me perform if LED bar button /** Show message confirm offline mode, should me perform if LED bar button
@ -271,6 +271,7 @@ void setup() {
Serial.println("Display brightness: " + String(configuration.getDisplayBrightness())); Serial.println("Display brightness: " + String(configuration.getDisplayBrightness()));
oledDisplay.setBrightness(configuration.getDisplayBrightness()); oledDisplay.setBrightness(configuration.getDisplayBrightness());
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
} }
@ -364,11 +365,17 @@ void loop() {
} }
} }
/* Run measurement schedule */
printMeasurementsSchedule.run();
/** factory reset handle */ /** factory reset handle */
factoryConfigReset(); factoryConfigReset();
/** check that local configuration changed then do some action */ if (configuration.isCommandRequested()) {
configUpdateHandle(); // Each state machine already has an independent request command check
stateMachine.executeCo2Calibration();
stateMachine.executeLedBarTest();
}
} }
static void co2Update(void) { static void co2Update(void) {
@ -385,6 +392,10 @@ static void co2Update(void) {
} }
} }
void printMeasurements() {
measurements.printCurrentAverage();
}
static void mdnsInit(void) { static void mdnsInit(void) {
if (!MDNS.begin(localServer.getHostname().c_str())) { if (!MDNS.begin(localServer.getHostname().c_str())) {
Serial.println("Init mDNS failed"); Serial.println("Init mDNS failed");
@ -555,6 +566,11 @@ static bool sgp41Init(void) {
} }
void checkForFirmwareUpdate(void) { void checkForFirmwareUpdate(void) {
if (configuration.isCloudConnectionDisabled()) {
Serial.println("Cloud connection is disabled, skip firmware update");
return;
}
AirgradientOTA *agOta; AirgradientOTA *agOta;
if (networkOption == UseWifi) { if (networkOption == UseWifi) {
agOta = new AirgradientOTAWifi; agOta = new AirgradientOTAWifi;
@ -989,6 +1005,9 @@ void initializeNetwork() {
ESP.restart(); ESP.restart();
} }
// Provide openmetrics to have access to last transmission result
openMetrics.setAirgradientClient(agClient);
if (networkOption == UseCellular) { if (networkOption == UseCellular) {
// Disabling it again // Disabling it again
agSerial->setDebug(false); agSerial->setDebug(false);
@ -1024,10 +1043,17 @@ void initializeNetwork() {
return; return;
} }
// Send data for the first time to AG server at boot // Send data for the first time to AG server at boot only if postDataToAirgradient is enabled
sendDataToAg(); if (configuration.isPostDataToAirGradient()) {
sendDataToAg();
}
} }
// Skip fetch configuration if configuration control is set to "local" only
if (configuration.getConfigurationControl() == ConfigurationControl::ConfigurationControlLocal) {
ledBarEnabledUpdate();
return;
}
std::string config = agClient->httpFetchConfig(); std::string config = agClient->httpFetchConfig();
configSchedule.update(); configSchedule.update();
@ -1059,8 +1085,8 @@ static void configurationUpdateSchedule(void) {
} }
std::string config = agClient->httpFetchConfig(); std::string config = agClient->httpFetchConfig();
if (agClient->isLastFetchConfigSucceed() && configuration.parse(config.c_str(), false)) { if (agClient->isLastFetchConfigSucceed()) {
configUpdateHandle(); configuration.parse(config.c_str(), false);
} }
} }
@ -1069,8 +1095,6 @@ static void configUpdateHandle() {
return; return;
} }
stateMachine.executeCo2Calibration();
String mqttUri = configuration.getMqttBrokerUri(); String mqttUri = configuration.getMqttBrokerUri();
if (mqttClient.isCurrentUri(mqttUri) == false) { if (mqttClient.isCurrentUri(mqttUri) == false) {
mqttClient.end(); mqttClient.end();
@ -1142,11 +1166,6 @@ static void configUpdateHandle() {
if (configuration.isDisplayBrightnessChanged()) { if (configuration.isDisplayBrightnessChanged()) {
oledDisplay.setBrightness(configuration.getDisplayBrightness()); oledDisplay.setBrightness(configuration.getDisplayBrightness());
} }
stateMachine.executeLedBarTest();
}
else if(ag->isOpenAir()) {
stateMachine.executeLedBarTest();
} }
// Update display and led bar notification based on updated configuration // Update display and led bar notification based on updated configuration
@ -1414,13 +1433,17 @@ void postUsingCellular(bool forcePost) {
// Post success, remove the data that previously sent from queue // Post success, remove the data that previously sent from queue
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY); xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
measurementCycleQueue.erase(measurementCycleQueue.begin(),
measurementCycleQueue.begin() + queueSize);
if (measurementCycleQueue.capacity() > RESERVED_MEASUREMENT_CYCLE_CAPACITY) { if (measurementCycleQueue.capacity() > RESERVED_MEASUREMENT_CYCLE_CAPACITY) {
Serial.println("measurementCycleQueue capacity more than reserved space, resizing.."); Serial.println("measurementCycleQueue capacity more than reserved space, resizing..");
measurementCycleQueue.resize(RESERVED_MEASUREMENT_CYCLE_CAPACITY); std::vector<Measurements::Measures> tmp;
tmp.reserve(RESERVED_MEASUREMENT_CYCLE_CAPACITY);
measurementCycleQueue.swap(tmp);
} else {
// If not more than the capacity, then just clear all the values
measurementCycleQueue.clear();
} }
xSemaphoreGive(mutexMeasurementCycleQueue); xSemaphoreGive(mutexMeasurementCycleQueue);
} }
@ -1559,27 +1582,29 @@ void restartIfCeClientIssueOverTwoHours() {
} }
void networkingTask(void *args) { void networkingTask(void *args) {
// OTA check on boot // If cloud connection enabled, run first transmission to server at boot
if (configuration.isCloudConnectionDisabled() == false) {
// OTA check on boot
#ifndef ESP8266 #ifndef ESP8266
checkForFirmwareUpdate(); checkForFirmwareUpdate();
checkForUpdateSchedule.update(); checkForUpdateSchedule.update();
#endif #endif
// Because cellular interval is longer, needs to send first measures cycle on // Because cellular interval is longer, needs to send first measures cycle on
// boot to indicate that its online // boot to indicate that its online
if (networkOption == UseCellular) { if (networkOption == UseCellular) {
Serial.println("Prepare first measures cycle to send on boot for 20s"); Serial.println("Prepare first measures cycle to send on boot for 20s");
delay(20000); delay(20000);
networkSignalCheck(); networkSignalCheck();
newMeasurementCycle(); newMeasurementCycle();
postUsingCellular(true); postUsingCellular(true);
measurementSchedule.update(); measurementSchedule.update();
}
// Reset scheduler
configSchedule.update();
transmissionSchedule.update();
} }
// Reset scheduler
configSchedule.update();
transmissionSchedule.update();
while (1) { while (1) {
// Handle reconnection based on mode // Handle reconnection based on mode
if (networkOption == UseWifi) { if (networkOption == UseWifi) {
@ -1634,7 +1659,7 @@ void networkingTask(void *args) {
// If connection to AirGradient server disable don't run config and transmission schedule // If connection to AirGradient server disable don't run config and transmission schedule
if (configuration.isCloudConnectionDisabled()) { if (configuration.isCloudConnectionDisabled()) {
delay(1000); delay(1000);
return; continue;
} }
// Run scheduler // Run scheduler

View File

@ -6,8 +6,11 @@ OpenMetrics::OpenMetrics(Measurements &measure, Configuration &config,
OpenMetrics::~OpenMetrics() {} OpenMetrics::~OpenMetrics() {}
void OpenMetrics::setAirGradient(AirGradient *ag, AirgradientClient *client) { void OpenMetrics::setAirGradient(AirGradient *ag) {
this->ag = ag; this->ag = ag;
}
void OpenMetrics::setAirgradientClient(AirgradientClient *client) {
this->agClient = client; this->agClient = client;
} }

View File

@ -19,7 +19,8 @@ public:
OpenMetrics(Measurements &measure, Configuration &config, OpenMetrics(Measurements &measure, Configuration &config,
WifiConnector &wifiConnector); WifiConnector &wifiConnector);
~OpenMetrics(); ~OpenMetrics();
void setAirGradient(AirGradient *ag, AirgradientClient *client); void setAirGradient(AirGradient *ag);
void setAirgradientClient(AirgradientClient *client);
const char *getApiContentType(void); const char *getApiContentType(void);
const char* getApi(void); const char* getApi(void);
String getPayload(void); String getPayload(void);

View File

@ -1,5 +1,5 @@
name=AirGradient Air Quality Sensor name=AirGradient Air Quality Sensor
version=3.3.6 version=3.3.9
author=AirGradient <support@airgradient.com> author=AirGradient <support@airgradient.com>
maintainer=AirGradient <support@airgradient.com> maintainer=AirGradient <support@airgradient.com>
sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display.

View File

@ -456,6 +456,10 @@ bool Configuration::begin(void) {
return true; return true;
} }
void Configuration::setConfigurationUpdatedCallback(ConfigurationUpdatedCallback_t callback) {
_callback = callback;
}
/** /**
* @brief Parse JSON configura string to local configure * @brief Parse JSON configura string to local configure
* *
@ -951,15 +955,18 @@ bool Configuration::parse(String data, bool isLocal) {
changed = true; changed = true;
} }
if (ledBarTestRequested || co2CalibrationRequested) {
commandRequested = true;
updated = true;
}
if (changed) { if (changed) {
updated = true; updated = true;
saveConfig(); saveConfig();
printConfig(); printConfig();
} else { _callback();
if (ledBarTestRequested || co2CalibrationRequested) {
updated = true;
}
} }
return true; return true;
} }
@ -1159,6 +1166,12 @@ bool Configuration::isUpdated(void) {
return updated; return updated;
} }
bool Configuration::isCommandRequested(void) {
bool oldState = this->commandRequested;
this->commandRequested = false;
return oldState;
}
String Configuration::jsonTypeInvalidMessage(String name, String type) { String Configuration::jsonTypeInvalidMessage(String name, String type) {
return "'" + name + "' type is invalid, expecting '" + type + "'"; return "'" + name + "' type is invalid, expecting '" + type + "'";
} }

View File

@ -28,6 +28,7 @@ private:
bool co2CalibrationRequested; bool co2CalibrationRequested;
bool ledBarTestRequested; bool ledBarTestRequested;
bool updated; bool updated;
bool commandRequested = false;
String failedMessage; String failedMessage;
bool _noxLearnOffsetChanged; bool _noxLearnOffsetChanged;
bool _tvocLearningOffsetChanged; bool _tvocLearningOffsetChanged;
@ -70,6 +71,9 @@ public:
bool hasSensorSGP = true; bool hasSensorSGP = true;
bool hasSensorSHT = true; bool hasSensorSHT = true;
typedef void (*ConfigurationUpdatedCallback_t)();
void setConfigurationUpdatedCallback(ConfigurationUpdatedCallback_t callback);
bool begin(void); bool begin(void);
bool parse(String data, bool isLocal); bool parse(String data, bool isLocal);
String toString(void); String toString(void);
@ -90,6 +94,7 @@ public:
void reset(void); void reset(void);
String getModel(void); String getModel(void);
bool isUpdated(void); bool isUpdated(void);
bool isCommandRequested(void);
String getFailedMesage(void); String getFailedMesage(void);
void setPostToAirGradient(bool enable); void setPostToAirGradient(bool enable);
bool noxLearnOffsetChanged(void); bool noxLearnOffsetChanged(void);
@ -116,6 +121,8 @@ public:
PMCorrection getPMCorrection(void); PMCorrection getPMCorrection(void);
TempHumCorrection getTempCorrection(void); TempHumCorrection getTempCorrection(void);
TempHumCorrection getHumCorrection(void); TempHumCorrection getHumCorrection(void);
private:
ConfigurationUpdatedCallback_t _callback;
}; };
#endif /** _AG_CONFIG_H_ */ #endif /** _AG_CONFIG_H_ */

View File

@ -5,7 +5,7 @@
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
#define json_prop_pmFirmware "firmware" #define json_prop_pmFirmware "firmware"
#define json_prop_pm01Ae "pm01" #define json_prop_pm01Ae "pm01"
#define json_prop_pm25Ae "pm02" #define json_prop_pm25Ae "pm02"
#define json_prop_pm10Ae "pm10" #define json_prop_pm10Ae "pm10"
@ -33,7 +33,7 @@ Measurements::Measurements(Configuration &config) : config(config) {
#ifndef ESP8266 #ifndef ESP8266
_resetReason = (int)ESP_RST_UNKNOWN; _resetReason = (int)ESP_RST_UNKNOWN;
#endif #endif
/* Set invalid value for each measurements as default value when initialized*/ /* Set invalid value for each measurements as default value when initialized*/
_temperature[0].update.avg = utils::getInvalidTemperature(); _temperature[0].update.avg = utils::getInvalidTemperature();
_temperature[1].update.avg = utils::getInvalidTemperature(); _temperature[1].update.avg = utils::getInvalidTemperature();
@ -51,7 +51,7 @@ Measurements::Measurements(Configuration &config) : config(config) {
_pm_05_pc[1].update.avg = utils::getInvalidPmValue(); _pm_05_pc[1].update.avg = utils::getInvalidPmValue();
_pm_5_pc[0].update.avg = utils::getInvalidPmValue(); _pm_5_pc[0].update.avg = utils::getInvalidPmValue();
_pm_5_pc[1].update.avg = utils::getInvalidPmValue(); _pm_5_pc[1].update.avg = utils::getInvalidPmValue();
_pm_01[0].update.avg = utils::getInvalidPmValue(); _pm_01[0].update.avg = utils::getInvalidPmValue();
_pm_01_sp[0].update.avg = utils::getInvalidPmValue(); _pm_01_sp[0].update.avg = utils::getInvalidPmValue();
_pm_01_pc[0].update.avg = utils::getInvalidPmValue(); _pm_01_pc[0].update.avg = utils::getInvalidPmValue();
@ -76,6 +76,86 @@ Measurements::Measurements(Configuration &config) : config(config) {
void Measurements::setAirGradient(AirGradient *ag) { this->ag = ag; } void Measurements::setAirGradient(AirGradient *ag) { this->ag = ag; }
void Measurements::printCurrentAverage() {
Serial.println();
if (config.hasSensorS8) {
if (utils::isValidCO2(_co2.update.avg)) {
Serial.printf("CO2 = %.2f ppm\n", _co2.update.avg);
} else {
Serial.printf("CO2 = -\n");
}
}
if (config.hasSensorSHT) {
if (utils::isValidTemperature(_temperature[0].update.avg)) {
Serial.printf("Temperature = %.2f C\n", _temperature[0].update.avg);
} else {
Serial.printf("Temperature = -\n");
}
if (utils::isValidHumidity(_humidity[0].update.avg)) {
Serial.printf("Relative Humidity = %.2f\n", _humidity[0].update.avg);
} else {
Serial.printf("Relative Humidity = -\n");
}
}
if (config.hasSensorSGP) {
if (utils::isValidVOC(_tvoc.update.avg)) {
Serial.printf("TVOC Index = %.1f\n", _tvoc.update.avg);
} else {
Serial.printf("TVOC Index = -\n");
}
if (utils::isValidVOC(_tvoc_raw.update.avg)) {
Serial.printf("TVOC Raw = %.1f\n", _tvoc_raw.update.avg);
} else {
Serial.printf("TVOC Raw = -\n");
}
if (utils::isValidNOx(_nox.update.avg)) {
Serial.printf("NOx Index = %.1f\n", _nox.update.avg);
} else {
Serial.printf("NOx Index = -\n");
}
if (utils::isValidNOx(_nox_raw.update.avg)) {
Serial.printf("NOx Raw = %.1f\n", _nox_raw.update.avg);
} else {
Serial.printf("NOx Raw = -\n");
}
}
if (config.hasSensorPMS1) {
printCurrentPMAverage(1);
if (!config.hasSensorSHT) {
if (utils::isValidTemperature(_temperature[0].update.avg)) {
Serial.printf("[1] Temperature = %.2f C\n", _temperature[0].update.avg);
} else {
Serial.printf("[1] Temperature = -\n");
}
if (utils::isValidHumidity(_humidity[0].update.avg)) {
Serial.printf("[1] Relative Humidity = %.2f\n", _humidity[0].update.avg);
} else {
Serial.printf("[1] Relative Humidity = -\n");
}
}
}
if (config.hasSensorPMS2) {
printCurrentPMAverage(2);
if (!config.hasSensorSHT) {
if (utils::isValidTemperature(_temperature[1].update.avg)) {
Serial.printf("[2] Temperature = %.2f C\n", _temperature[1].update.avg);
} else {
Serial.printf("[2] Temperature = -\n");
}
if (utils::isValidHumidity(_humidity[1].update.avg)) {
Serial.printf("[2] Relative Humidity = %.2f\n", _humidity[1].update.avg);
} else {
Serial.printf("[2] Relative Humidity = -\n");
}
}
}
Serial.println();
}
void Measurements::maxPeriod(MeasurementType type, int max) { void Measurements::maxPeriod(MeasurementType type, int max) {
switch (type) { switch (type) {
case Temperature: case Temperature:
@ -570,6 +650,77 @@ String Measurements::measurementTypeStr(MeasurementType type) {
return str; return str;
} }
void Measurements::printCurrentPMAverage(int ch) {
int idx = ch - 1;
if (utils::isValidPm(_pm_01[idx].update.avg)) {
Serial.printf("[%d] Atmospheric PM 1.0 = %.2f ug/m3\n", ch, _pm_01[idx].update.avg);
} else {
Serial.printf("[%d] Atmospheric PM 1.0 = -\n", ch);
}
if (utils::isValidPm(_pm_25[idx].update.avg)) {
Serial.printf("[%d] Atmospheric PM 2.5 = %.2f ug/m3\n", ch, _pm_25[idx].update.avg);
} else {
Serial.printf("[%d] Atmospheric PM 2.5 = -\n", ch);
}
if (utils::isValidPm(_pm_10[idx].update.avg)) {
Serial.printf("[%d] Atmospheric PM 10 = %.2f ug/m3\n", ch, _pm_10[idx].update.avg);
} else {
Serial.printf("[%d] Atmospheric PM 10 = -\n", ch);
}
if (utils::isValidPm(_pm_01_sp[idx].update.avg)) {
Serial.printf("[%d] Standard Particle PM 1.0 = %.2f ug/m3\n", ch, _pm_01_sp[idx].update.avg);
} else {
Serial.printf("[%d] Standard Particle PM 1.0 = -\n", ch);
}
if (utils::isValidPm(_pm_25_sp[idx].update.avg)) {
Serial.printf("[%d] Standard Particle PM 2.5 = %.2f ug/m3\n", ch, _pm_25_sp[idx].update.avg);
} else {
Serial.printf("[%d] Standard Particle PM 2.5 = -\n", ch);
}
if (utils::isValidPm(_pm_10_sp[idx].update.avg)) {
Serial.printf("[%d] Standard Particle PM 10 = %.2f ug/m3\n", ch, _pm_10_sp[idx].update.avg);
} else {
Serial.printf("[%d] Standard Particle PM 10 = -\n", ch);
}
if (utils::isValidPm03Count(_pm_03_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 0.3 = %.1f\n", ch, _pm_03_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 0.3 = -\n", ch);
}
if (utils::isValidPm03Count(_pm_05_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 0.5 = %.1f\n", ch, _pm_05_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 0.5 = -\n", ch);
}
if (utils::isValidPm03Count(_pm_01_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 1.0 = %.1f\n", ch, _pm_01_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 1.0 = -\n", ch);
}
if (utils::isValidPm03Count(_pm_25_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 2.5 = %.1f\n", ch, _pm_25_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 2.5 = -\n", ch);
}
if (_pm_5_pc[idx].listValues.empty() == false) {
if (utils::isValidPm03Count(_pm_5_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 5.0 = %.1f\n", ch, _pm_5_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 5.0 = -\n", ch);
}
}
if (_pm_10_pc[idx].listValues.empty() == false) {
if (utils::isValidPm03Count(_pm_10_pc[idx].update.avg)) {
Serial.printf("[%d] Particle Count 10 = %.1f\n", ch, _pm_10_pc[idx].update.avg);
} else {
Serial.printf("[%d] Particle Count 10 = -\n", ch);
}
}
}
void Measurements::validateChannel(int ch) { void Measurements::validateChannel(int ch) {
if (ch != 1 && ch != 2) { if (ch != 1 && ch != 2) {
Serial.printf("ERROR! Channel %d is undefined. Only channel 1 or 2 is the optional value!", ch); Serial.printf("ERROR! Channel %d is undefined. Only channel 1 or 2 is the optional value!", ch);

View File

@ -88,6 +88,8 @@ public:
PM10_PC, // Particle 10 count PM10_PC, // Particle 10 count
}; };
void printCurrentAverage();
/** /**
* @brief Set each MeasurementType maximum period length for moving average * @brief Set each MeasurementType maximum period length for moving average
* *
@ -258,6 +260,8 @@ private:
*/ */
void validateChannel(int ch); void validateChannel(int ch);
void printCurrentPMAverage(int ch);
JSONVar buildOutdoor(bool localServer, AgFirmwareMode fwMode); JSONVar buildOutdoor(bool localServer, AgFirmwareMode fwMode);
JSONVar buildIndoor(bool localServer); JSONVar buildIndoor(bool localServer);
JSONVar buildPMS(int ch, bool allCh, bool withTempHum, bool compensate); JSONVar buildPMS(int ch, bool allCh, bool withTempHum, bool compensate);

View File

@ -15,7 +15,7 @@
#include "Main/utils.h" #include "Main/utils.h"
#ifndef GIT_VERSION #ifndef GIT_VERSION
#define GIT_VERSION "3.3.6-snap" #define GIT_VERSION "3.3.9-snap"
#endif #endif