mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-07-28 16:07:16 +02:00
MeasurementCycle queue only applied for cellular
Cellular post measures payload different with wifi Update submodule to support different cellular post endpoint
This commit is contained in:
1592
compile_commands.json
Normal file
1592
compile_commands.json
Normal file
File diff suppressed because one or more lines are too long
@ -63,9 +63,9 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#define WIFI_SERVER_CONFIG_SYNC_INTERVAL 1 * 60000 /** ms */
|
#define WIFI_SERVER_CONFIG_SYNC_INTERVAL 1 * 60000 /** ms */
|
||||||
#define WIFI_MEASUREMENT_INTERVAL 1 * 60000 /** ms */
|
#define WIFI_MEASUREMENT_INTERVAL 1 * 60000 /** ms */
|
||||||
#define WIFI_TRANSMISSION_INTERVAL 1 * 60000 /** ms */
|
#define WIFI_TRANSMISSION_INTERVAL 1 * 60000 /** ms */
|
||||||
#define CELLULAR_SERVER_CONFIG_SYNC_INTERVAL 15 * 60000 /** ms */
|
#define CELLULAR_SERVER_CONFIG_SYNC_INTERVAL 30 * 60000 /** ms */
|
||||||
#define CELLULAR_MEASUREMENT_INTERVAL 3 * 60000 /** ms */
|
#define CELLULAR_MEASUREMENT_INTERVAL 3 * 60000 /** ms */
|
||||||
#define CELLULAR_TRANSMISSION_INTERVAL 3 * 60000 /** ms */
|
#define CELLULAR_TRANSMISSION_INTERVAL 9 * 60000 /** ms */
|
||||||
#define MQTT_SYNC_INTERVAL 60000 /** ms */
|
#define MQTT_SYNC_INTERVAL 60000 /** ms */
|
||||||
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
|
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
|
||||||
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
||||||
@ -75,6 +75,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
||||||
#define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */
|
#define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */
|
||||||
|
|
||||||
|
#define MAXIMUM_MEASUREMENT_CYCLE_QUEUE 80
|
||||||
|
|
||||||
/** I2C define */
|
/** I2C define */
|
||||||
#define I2C_SDA_PIN 7
|
#define I2C_SDA_PIN 7
|
||||||
#define I2C_SCL_PIN 6
|
#define I2C_SCL_PIN 6
|
||||||
@ -259,10 +261,19 @@ void setup() {
|
|||||||
oledDisplay.setBrightness(configuration.getDisplayBrightness());
|
oledDisplay.setBrightness(configuration.getDisplayBrightness());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (networkOption == UseCellular) {
|
||||||
|
// If using cellular re-set scheduler interval
|
||||||
|
configSchedule.setPeriod(CELLULAR_SERVER_CONFIG_SYNC_INTERVAL);
|
||||||
|
transmissionSchedule.setPeriod(CELLULAR_TRANSMISSION_INTERVAL);
|
||||||
|
measurementSchedule.setPeriod(CELLULAR_MEASUREMENT_INTERVAL);
|
||||||
|
measurementSchedule.update();
|
||||||
|
// Queue now only applied for cellular
|
||||||
// Allocate queue memory to avoid always reallocation
|
// Allocate queue memory to avoid always reallocation
|
||||||
measurementCycleQueue.reserve(10);
|
measurementCycleQueue.reserve(10);
|
||||||
// Initialize mutex to access mesurementCycleQueue
|
// Initialize mutex to access mesurementCycleQueue
|
||||||
mutexMeasurementCycleQueue = xSemaphoreCreateMutex();
|
mutexMeasurementCycleQueue = xSemaphoreCreateMutex();
|
||||||
|
}
|
||||||
|
|
||||||
// Only run network task if monitor is not in offline mode
|
// Only run network task if monitor is not in offline mode
|
||||||
if (configuration.isOfflineMode() == false) {
|
if (configuration.isOfflineMode() == false) {
|
||||||
@ -283,12 +294,6 @@ void setup() {
|
|||||||
Serial.println("Running monitor without connection to AirGradient server");
|
Serial.println("Running monitor without connection to AirGradient server");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using cellular re-set scheduler interval
|
|
||||||
if (networkOption == UseCellular) {
|
|
||||||
configSchedule.setPeriod(CELLULAR_SERVER_CONFIG_SYNC_INTERVAL);
|
|
||||||
transmissionSchedule.setPeriod(CELLULAR_TRANSMISSION_INTERVAL);
|
|
||||||
measurementSchedule.setPeriod(CELLULAR_MEASUREMENT_INTERVAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@ -304,10 +309,8 @@ void loop() {
|
|||||||
// Schedule to update display and led
|
// Schedule to update display and led
|
||||||
dispLedSchedule.run();
|
dispLedSchedule.run();
|
||||||
|
|
||||||
// No need to run measurement cycle schedule when mode is offline or connection to AG disabled
|
if (networkOption == UseCellular) {
|
||||||
if (configuration.isOfflineMode() == false ||
|
// Queue now only applied for cellular
|
||||||
configuration.isCloudConnectionDisabled() == false) {
|
|
||||||
// Schedule to take new measurement cycle
|
|
||||||
measurementSchedule.run();
|
measurementSchedule.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,10 +978,10 @@ void initializeNetwork() {
|
|||||||
if (configuration.isCloudConnectionDisabled()) {
|
if (configuration.isCloudConnectionDisabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Send data for the first time to AG server at boot
|
// Send data for the first time to AG server at boot
|
||||||
sendDataToAg();
|
sendDataToAg();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string config = agClient->httpFetchConfig(ag->getDeviceId());
|
std::string config = agClient->httpFetchConfig(ag->getDeviceId());
|
||||||
@ -1287,13 +1290,23 @@ static void updatePm(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendDataToServer(void) {
|
void postUsingWifi() {
|
||||||
if (configuration.isPostDataToAirGradient() == false) {
|
// Increment bootcount when send measurements data is scheduled
|
||||||
Serial.println("Skipping transmission of data to AG server, post data to server disabled");
|
int bootCount = measurements.bootCount() + 1;
|
||||||
agClient->resetPostMeasuresStatus();
|
measurements.setBootCount(bootCount);
|
||||||
return;
|
|
||||||
|
String payload = measurements.toString(false, fwMode, wifiConnector.RSSI());
|
||||||
|
if (agClient->httpPostMeasures(ag->getDeviceId(), payload.c_str()) == false) {
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("Online mode and isPostToAirGradient = true");
|
||||||
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log current free heap size
|
||||||
|
Serial.printf("Free heap: %u\n", ESP.getFreeHeap());
|
||||||
|
}
|
||||||
|
|
||||||
|
void postUsingCellular() {
|
||||||
// Aquire queue mutex to get queue size
|
// Aquire queue mutex to get queue size
|
||||||
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
|
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
|
||||||
|
|
||||||
@ -1305,36 +1318,44 @@ void sendDataToServer(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("Measurement cycle queue size %d\n", queueSize);
|
// Build payload include all measurements from queue
|
||||||
xSemaphoreGive(mutexMeasurementCycleQueue);
|
String payload;
|
||||||
delay(10); // Wait for a moment in case new measurement schedule wait for it
|
payload += String(CELLULAR_MEASUREMENT_INTERVAL);
|
||||||
|
for (int i = 0; i < queueSize; i++) {
|
||||||
for (int i = 1; i <= queueSize; i++) {
|
auto mc = measurementCycleQueue.at(i);
|
||||||
Serial.printf("Attempt post measurement cycle from queue %d\n", i);
|
payload += ",";
|
||||||
// Aquire queue mutex to get oldest in queue
|
payload += measurements.buildMeasurementPayload(mc);
|
||||||
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
|
}
|
||||||
|
|
||||||
// Get the oldest queue
|
|
||||||
auto mc = measurementCycleQueue.front();
|
|
||||||
|
|
||||||
// Release before actually post measures that might takes too long
|
// Release before actually post measures that might takes too long
|
||||||
xSemaphoreGive(mutexMeasurementCycleQueue);
|
xSemaphoreGive(mutexMeasurementCycleQueue);
|
||||||
|
|
||||||
String payload = measurements.buildMeasurementPayload(mc, fwMode);
|
// Attempt to send
|
||||||
|
Serial.println(payload);
|
||||||
if (agClient->httpPostMeasures(ag->getDeviceId(), payload.c_str()) == false) {
|
if (agClient->httpPostMeasures(ag->getDeviceId(), payload.c_str()) == false) {
|
||||||
// Consider network has a problem, retry in next schedule
|
// Consider network has a problem, retry in next schedule
|
||||||
Serial.println("Post measures failed, retry in next schedule");
|
Serial.println("Post measures failed, retry in next schedule");
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
Serial.println();
|
|
||||||
|
|
||||||
// Post success, remove the oldest queue
|
// Post success, remove the data that previously sent from queue
|
||||||
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
|
xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY);
|
||||||
measurementCycleQueue.erase(measurementCycleQueue.begin());
|
measurementCycleQueue.erase(measurementCycleQueue.begin(),
|
||||||
|
measurementCycleQueue.begin() + queueSize);
|
||||||
xSemaphoreGive(mutexMeasurementCycleQueue);
|
xSemaphoreGive(mutexMeasurementCycleQueue);
|
||||||
|
}
|
||||||
|
|
||||||
// Wait a moment before post next in queue
|
void sendDataToServer(void) {
|
||||||
delay(2000);
|
if (configuration.isPostDataToAirGradient() == false) {
|
||||||
|
Serial.println("Skipping transmission of data to AG server, post data to server disabled");
|
||||||
|
agClient->resetPostMeasuresStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (networkOption == UseWifi) {
|
||||||
|
postUsingWifi();
|
||||||
|
} else {
|
||||||
|
postUsingCellular();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1469,17 +1490,18 @@ void networkingTask(void *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void newMeasurementCycle() {
|
void newMeasurementCycle() {
|
||||||
// TODO: Need to check max queue
|
|
||||||
if (xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY) == pdTRUE) {
|
if (xSemaphoreTake(mutexMeasurementCycleQueue, portMAX_DELAY) == pdTRUE) {
|
||||||
|
// Make sure queue not overflow
|
||||||
|
if (measurementCycleQueue.size() >= MAXIMUM_MEASUREMENT_CYCLE_QUEUE) {
|
||||||
|
// Remove the oldest data from queue if queue reach max
|
||||||
|
measurementCycleQueue.erase(measurementCycleQueue.begin());
|
||||||
|
}
|
||||||
|
|
||||||
Measurements::MeasurementCycle mc = measurements.getMeasurementCycle();
|
Measurements::MeasurementCycle mc = measurements.getMeasurementCycle();
|
||||||
mc.wifi = wifiConnector.RSSI();
|
|
||||||
measurementCycleQueue.push_back(mc);
|
measurementCycleQueue.push_back(mc);
|
||||||
Serial.println("New measurement cycle added to queue");
|
Serial.println("New measurement cycle added to queue");
|
||||||
// Release mutex
|
// Release mutex
|
||||||
xSemaphoreGive(mutexMeasurementCycleQueue);
|
xSemaphoreGive(mutexMeasurementCycleQueue);
|
||||||
// Increment bootcount for the next measurement cycle
|
|
||||||
int bootCount = measurements.bootCount() + 1;
|
|
||||||
measurements.setBootCount(bootCount);
|
|
||||||
// Log current free heap size
|
// Log current free heap size
|
||||||
Serial.printf("Free heap: %u\n", ESP.getFreeHeap());
|
Serial.printf("Free heap: %u\n", ESP.getFreeHeap());
|
||||||
}
|
}
|
||||||
|
314
src/AgValue.cpp
314
src/AgValue.cpp
@ -2,6 +2,7 @@
|
|||||||
#include "AgConfigure.h"
|
#include "AgConfigure.h"
|
||||||
#include "AirGradient.h"
|
#include "AirGradient.h"
|
||||||
#include "App/AppDef.h"
|
#include "App/AppDef.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#define json_prop_pmFirmware "firmware"
|
#define json_prop_pmFirmware "firmware"
|
||||||
#define json_prop_pm01Ae "pm01"
|
#define json_prop_pm01Ae "pm01"
|
||||||
@ -732,291 +733,90 @@ Measurements::MeasurementCycle Measurements::getMeasurementCycle() {
|
|||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Measurements::buildMeasurementPayload(MeasurementCycle &mc, AgFirmwareMode fwMode) {
|
String Measurements::buildMeasurementPayload(MeasurementCycle &mc) {
|
||||||
JSONVar root;
|
String result;
|
||||||
|
|
||||||
/// TVOx and NOx
|
int co2 = utils::getInvalidCO2();
|
||||||
if (utils::isValidVOC(mc.tvoc)) {
|
float temp = utils::getInvalidTemperature();
|
||||||
root[json_prop_tvoc] = ag->round2(mc.tvoc);
|
float hum = utils::getInvalidHumidity();
|
||||||
}
|
float pm01 = utils::getInvalidPmValue();
|
||||||
if (utils::isValidVOC(mc.tvoc_raw)) {
|
float pm25 = utils::getInvalidPmValue();
|
||||||
root[json_prop_tvocRaw] = ag->round2(mc.tvoc_raw);
|
float pm10 = utils::getInvalidPmValue();
|
||||||
}
|
int nox = utils::getInvalidNOx();
|
||||||
if (utils::isValidNOx(mc.nox)) {
|
int pm003Count = utils::getInvalidPmValue();
|
||||||
root[json_prop_nox] = ag->round2(mc.nox);
|
|
||||||
}
|
|
||||||
if (utils::isValidNOx(mc.nox_raw)) {
|
|
||||||
root[json_prop_noxRaw] = ag->round2(mc.nox_raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CO2
|
// CO2
|
||||||
if (utils::isValidCO2(mc.co2)) {
|
if (utils::isValidCO2(mc.co2)) {
|
||||||
root[json_prop_co2] = ag->round2(mc.co2);
|
co2 = std::round(mc.co2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwMode == FW_MODE_O_1PP || fwMode == FW_MODE_O_1PPT) {
|
// NOx
|
||||||
// Have 2 PMS sensor using PM5003T
|
if (utils::isValidNOx(mc.nox)) {
|
||||||
root["channels"]["1"][json_prop_pmFirmware] =
|
nox = std::round(mc.nox);
|
||||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
}
|
||||||
root["channels"]["2"][json_prop_pmFirmware] =
|
|
||||||
pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
|
/// Temperature
|
||||||
|
if (utils::isValidTemperature(mc.temperature[0]) && utils::isValidTemperature(mc.temperature[1])) {
|
||||||
|
temp = ag->round2((mc.temperature[0] + mc.temperature[1]) / 2.0f);
|
||||||
|
} else if (utils::isValidTemperature(mc.temperature[0])) {
|
||||||
|
temp = ag->round2(mc.temperature[0]);
|
||||||
|
} else if (utils::isValidTemperature(mc.temperature[1])) {
|
||||||
|
temp = ag->round2(mc.temperature[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Humidity
|
||||||
|
if (utils::isValidHumidity(mc.humidity[0]) && utils::isValidHumidity(mc.humidity[1])) {
|
||||||
|
hum = ag->round2((mc.humidity[0] + mc.humidity[1]) / 2.0f);
|
||||||
|
} else if (utils::isValidHumidity(mc.humidity[0])) {
|
||||||
|
hum = ag->round2(mc.humidity[0]);
|
||||||
|
} else if (utils::isValidHumidity(mc.humidity[1])) {
|
||||||
|
hum = ag->round2(mc.humidity[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/// PM1.0 atmospheric environment
|
/// PM1.0 atmospheric environment
|
||||||
if (utils::isValidPm(mc.pm_01[0]) && utils::isValidPm(mc.pm_01[1])) {
|
if (utils::isValidPm(mc.pm_01[0]) && utils::isValidPm(mc.pm_01[1])) {
|
||||||
float avg = (mc.pm_01[0] + mc.pm_01[1]) / 2.0f;
|
pm01 = ag->round2((mc.pm_01[0] + mc.pm_01[1]) / 2.0f);
|
||||||
root[json_prop_pm01Ae] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm01Ae] = ag->round2(mc.pm_01[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm01Ae] = ag->round2(mc.pm_01[1]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_01[0])) {
|
} else if (utils::isValidPm(mc.pm_01[0])) {
|
||||||
root[json_prop_pm01Ae] = ag->round2(mc.pm_01[0]);
|
pm01 = ag->round2(mc.pm_01[0]);
|
||||||
root["channels"]["1"][json_prop_pm01Ae] = ag->round2(mc.pm_01[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_01[1])) {
|
} else if (utils::isValidPm(mc.pm_01[1])) {
|
||||||
root[json_prop_pm01Ae] = ag->round2(mc.pm_01[1]);
|
pm01 = ag->round2(mc.pm_01[1]);
|
||||||
root["channels"]["2"][json_prop_pm01Ae] = ag->round2(mc.pm_01[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PM2.5 atmospheric environment
|
/// PM2.5 atmospheric environment
|
||||||
if (utils::isValidPm(mc.pm_25[0]) && utils::isValidPm(mc.pm_25[1])) {
|
if (utils::isValidPm(mc.pm_25[0]) && utils::isValidPm(mc.pm_25[1])) {
|
||||||
float avg = (mc.pm_25[0] + mc.pm_25[1]) / 2.0f;
|
pm25 = ag->round2((mc.pm_25[0] + mc.pm_25[1]) / 2.0f);
|
||||||
root[json_prop_pm25Ae] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm25Ae] = ag->round2(mc.pm_25[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm25Ae] = ag->round2(mc.pm_25[1]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_25[0])) {
|
} else if (utils::isValidPm(mc.pm_25[0])) {
|
||||||
root[json_prop_pm25Ae] = ag->round2(mc.pm_25[0]);
|
pm25 = ag->round2(mc.pm_25[0]);
|
||||||
root["channels"]["1"][json_prop_pm25Ae] = ag->round2(mc.pm_25[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_25[1])) {
|
} else if (utils::isValidPm(mc.pm_25[1])) {
|
||||||
root[json_prop_pm25Ae] = ag->round2(mc.pm_25[1]);
|
pm25 = ag->round2(mc.pm_25[1]);
|
||||||
root["channels"]["2"][json_prop_pm25Ae] = ag->round2(mc.pm_25[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PM10 atmospheric environment
|
/// PM10 atmospheric environment
|
||||||
if (utils::isValidPm(mc.pm_10[0]) && utils::isValidPm(mc.pm_10[1])) {
|
if (utils::isValidPm(mc.pm_10[0]) && utils::isValidPm(mc.pm_10[1])) {
|
||||||
float avg = (mc.pm_10[0] + mc.pm_10[1]) / 2.0f;
|
pm10 = ag->round2((mc.pm_10[0] + mc.pm_10[1]) / 2.0f);
|
||||||
root[json_prop_pm10Ae] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm10Ae] = ag->round2(mc.pm_10[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm10Ae] = ag->round2(mc.pm_10[1]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_10[0])) {
|
} else if (utils::isValidPm(mc.pm_10[0])) {
|
||||||
root[json_prop_pm10Ae] = ag->round2(mc.pm_10[0]);
|
pm10 = ag->round2(mc.pm_10[0]);
|
||||||
root["channels"]["1"][json_prop_pm10Ae] = ag->round2(mc.pm_10[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_10[1])) {
|
} else if (utils::isValidPm(mc.pm_10[1])) {
|
||||||
root[json_prop_pm10Ae] = ag->round2(mc.pm_10[1]);
|
pm10 = ag->round2(mc.pm_10[1]);
|
||||||
root["channels"]["2"][json_prop_pm10Ae] = ag->round2(mc.pm_10[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PM1.0 standard particle
|
/// PM 0.3 particle count
|
||||||
if (utils::isValidPm(mc.pm_01_sp[0]) && utils::isValidPm(mc.pm_01_sp[1])) {
|
if (utils::isValidPm(mc.pm_03_pc[0]) && utils::isValidPm(mc.pm_03_pc[1])) {
|
||||||
float avg = (mc.pm_01_sp[0] + mc.pm_01_sp[1]) / 2.0f;
|
pm003Count = std::round((mc.pm_03_pc[0] + mc.pm_03_pc[1]) / 2.0f);
|
||||||
root[json_prop_pm01Sp] = ag->round2(avg);
|
} else if (utils::isValidPm(mc.pm_03_pc[0])) {
|
||||||
root["channels"]["1"][json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[0]);
|
pm003Count = std::round(mc.pm_03_pc[0]);
|
||||||
root["channels"]["2"][json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[1]);
|
} else if (utils::isValidPm(mc.pm_03_pc[1])) {
|
||||||
} else if (utils::isValidPm(mc.pm_01_sp[0])) {
|
pm003Count = std::round(mc.pm_03_pc[1]);
|
||||||
root[json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_01_sp[1])) {
|
|
||||||
root[json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PM2.5 standard particle
|
char datapoint[128] = {0};
|
||||||
if (utils::isValidPm(mc.pm_25_sp[0]) && utils::isValidPm(mc.pm_25_sp[1])) {
|
Serial.printf(datapoint, 128, "%d,%.0f,%.0f,%.0f,%.0f,%.0f,%d,%d\n", co2,
|
||||||
float avg = (mc.pm_25_sp[0] + mc.pm_25_sp[1]) / 2.0f;
|
temp * 10, hum * 10, pm01 * 10, pm25 * 10, pm10 * 10, nox,
|
||||||
root[json_prop_pm25Sp] = ag->round2(avg);
|
pm003Count);
|
||||||
root["channels"]["1"][json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[0]);
|
snprintf(datapoint, 128, "%d,%.0f,%.0f,%.0f,%.0f,%.0f,%d,%d", co2, temp * 10,
|
||||||
root["channels"]["2"][json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[1]);
|
hum * 10, pm01 * 10, pm25 * 10, pm10 * 10, nox, pm003Count);
|
||||||
} else if (utils::isValidPm(mc.pm_25_sp[0])) {
|
|
||||||
root[json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_25_sp[1])) {
|
|
||||||
root[json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PM10 standard particle
|
return String(datapoint);
|
||||||
if (utils::isValidPm(mc.pm_10_sp[0]) && utils::isValidPm(mc.pm_10_sp[1])) {
|
|
||||||
float avg = (mc.pm_10_sp[0] + mc.pm_10_sp[1]) / 2.0f;
|
|
||||||
root[json_prop_pm10Sp] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[1]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_10_sp[0])) {
|
|
||||||
root[json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[0]);
|
|
||||||
} else if (utils::isValidPm(mc.pm_10_sp[1])) {
|
|
||||||
root[json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PM003 particle count
|
|
||||||
if (utils::isValidPm03Count(mc.pm_03_pc[0]) &&
|
|
||||||
utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
|
||||||
float avg = (mc.pm_03_pc[0] + mc.pm_03_pc[1]) / 2.0f;
|
|
||||||
root[json_prop_pm03Count] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm03Count] = ag->round2(mc.pm_03_pc[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm03Count] = ag->round2(mc.pm_03_pc[1]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_03_pc[0])) {
|
|
||||||
root[json_prop_pm03Count] = ag->round2(mc.pm_03_pc[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm03Count] = ag->round2(mc.pm_03_pc[0]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
|
||||||
root[json_prop_pm03Count] = ag->round2(mc.pm_03_pc[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm03Count] = ag->round2(mc.pm_03_pc[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PM0.5 particle count
|
|
||||||
if (utils::isValidPm03Count(mc.pm_05_pc[0]) &&
|
|
||||||
utils::isValidPm03Count(mc.pm_05_pc[1])) {
|
|
||||||
float avg = (mc.pm_05_pc[0] + mc.pm_05_pc[1]) / 2.0f;
|
|
||||||
root[json_prop_pm05Count] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm05Count] = ag->round2(mc.pm_05_pc[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm05Count] = ag->round2(mc.pm_05_pc[1]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_05_pc[0])) {
|
|
||||||
root[json_prop_pm05Count] = ag->round2(mc.pm_05_pc[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm05Count] = ag->round2(mc.pm_05_pc[0]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_05_pc[1])) {
|
|
||||||
root[json_prop_pm05Count] = ag->round2(mc.pm_05_pc[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm05Count] = ag->round2(mc.pm_05_pc[1]);
|
|
||||||
}
|
|
||||||
/// PM1.0 particle count
|
|
||||||
if (utils::isValidPm03Count(mc.pm_01_pc[0]) &&
|
|
||||||
utils::isValidPm03Count(mc.pm_01_pc[1])) {
|
|
||||||
float avg = (mc.pm_01_pc[0] + mc.pm_01_pc[1]) / 2.0f;
|
|
||||||
root[json_prop_pm1Count] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm1Count] = ag->round2(mc.pm_01_pc[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm1Count] = ag->round2(mc.pm_01_pc[1]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_01_pc[0])) {
|
|
||||||
root[json_prop_pm1Count] = ag->round2(mc.pm_01_pc[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm1Count] = ag->round2(mc.pm_01_pc[0]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_01_pc[1])) {
|
|
||||||
root[json_prop_pm1Count] = ag->round2(mc.pm_01_pc[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm1Count] = ag->round2(mc.pm_01_pc[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PM2.5 particle count
|
|
||||||
if (utils::isValidPm03Count(mc.pm_25_pc[0]) &&
|
|
||||||
utils::isValidPm03Count(mc.pm_25_pc[1])) {
|
|
||||||
float avg = (mc.pm_25_pc[0] + mc.pm_25_pc[1]) / 2.0f;
|
|
||||||
root[json_prop_pm25Count] = ag->round2(avg);
|
|
||||||
root["channels"]["1"][json_prop_pm25Count] = ag->round2(mc.pm_25_pc[0]);
|
|
||||||
root["channels"]["2"][json_prop_pm25Count] = ag->round2(mc.pm_25_pc[1]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_25_pc[0])) {
|
|
||||||
root[json_prop_pm25Count] = ag->round2(mc.pm_25_pc[0]);
|
|
||||||
root["channels"]["1"][json_prop_pm25Count] = ag->round2(mc.pm_25_pc[0]);
|
|
||||||
} else if (utils::isValidPm03Count(mc.pm_25_pc[1])) {
|
|
||||||
root[json_prop_pm25Count] = ag->round2(mc.pm_25_pc[1]);
|
|
||||||
root["channels"]["2"][json_prop_pm25Count] = ag->round2(mc.pm_25_pc[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Temperature
|
|
||||||
if (utils::isValidTemperature(mc.temperature[0]) &&
|
|
||||||
utils::isValidTemperature(mc.temperature[1])) {
|
|
||||||
float temperature = (mc.temperature[0] + mc.temperature[1]) / 2.0f;
|
|
||||||
root[json_prop_temp] = ag->round2(temperature);
|
|
||||||
root["channels"]["1"][json_prop_temp] = ag->round2(mc.temperature[0]);
|
|
||||||
root["channels"]["2"][json_prop_temp] = ag->round2(mc.temperature[1]);
|
|
||||||
} else if (utils::isValidTemperature(mc.temperature[0])) {
|
|
||||||
root[json_prop_temp] = ag->round2(mc.temperature[0]);
|
|
||||||
root["channels"]["1"][json_prop_temp] = ag->round2(mc.temperature[0]);
|
|
||||||
} else if (utils::isValidTemperature(mc.temperature[1])) {
|
|
||||||
root[json_prop_temp] = ag->round2(mc.temperature[1]);
|
|
||||||
root["channels"]["2"][json_prop_temp] = ag->round2(mc.temperature[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Relative humidity
|
|
||||||
if (utils::isValidHumidity(mc.humidity[0]) &&
|
|
||||||
utils::isValidHumidity(mc.humidity[1])) {
|
|
||||||
float humidity = (mc.humidity[0] + mc.humidity[1]) / 2.0f;
|
|
||||||
root[json_prop_rhum] = ag->round2(humidity);
|
|
||||||
root["channels"]["1"][json_prop_rhum] = ag->round2(mc.humidity[0]);
|
|
||||||
root["channels"]["2"][json_prop_rhum] = ag->round2(mc.humidity[1]);
|
|
||||||
} else if (utils::isValidHumidity(mc.humidity[0])) {
|
|
||||||
root[json_prop_rhum] = ag->round2(mc.humidity[0]);
|
|
||||||
root["channels"]["1"][json_prop_rhum] = ag->round2(mc.humidity[0]);
|
|
||||||
} else if (utils::isValidHumidity(mc.humidity[1])) {
|
|
||||||
root[json_prop_rhum] = ag->round2(mc.humidity[1]);
|
|
||||||
root["channels"]["2"][json_prop_rhum] = ag->round2(mc.humidity[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Define PMS channel and add PMS firmware version
|
|
||||||
int chIndex;
|
|
||||||
if (config.hasSensorPMS1) {
|
|
||||||
chIndex = 0; // PMS connected to channel 1
|
|
||||||
if (ag->isOne() || (ag->isPro4_2()) || ag->isPro3_3() || ag->isBasic()) {
|
|
||||||
root[json_prop_pmFirmware] =
|
|
||||||
pms5003FirmwareVersion(ag->pms5003.getFirmwareVersion());
|
|
||||||
} else {
|
|
||||||
root[json_prop_pmFirmware] =
|
|
||||||
pms5003TFirmwareVersion(ag->pms5003t_1.getFirmwareVersion());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
chIndex = 1; // PMS connected to channel 2
|
|
||||||
root[json_prop_pmFirmware] =
|
|
||||||
pms5003TFirmwareVersion(ag->pms5003t_2.getFirmwareVersion());
|
|
||||||
}
|
|
||||||
// Have 1 PMS sensor
|
|
||||||
if (utils::isValidPm(mc.pm_01[chIndex])) {
|
|
||||||
root[json_prop_pm01Ae] = ag->round2(mc.pm_01[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm(mc.pm_25[chIndex])) {
|
|
||||||
root[json_prop_pm25Ae] = ag->round2(mc.pm_25[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm(mc.pm_10[chIndex])) {
|
|
||||||
root[json_prop_pm10Ae] = ag->round2(mc.pm_10[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm(mc.pm_01_sp[chIndex])) {
|
|
||||||
root[json_prop_pm01Sp] = ag->round2(mc.pm_01_sp[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm(mc.pm_25_sp[chIndex])) {
|
|
||||||
root[json_prop_pm25Sp] = ag->round2(mc.pm_25_sp[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm(mc.pm_10_sp[chIndex])) {
|
|
||||||
root[json_prop_pm10Sp] = ag->round2(mc.pm_10_sp[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_03_pc[chIndex])) {
|
|
||||||
root[json_prop_pm03Count] = ag->round2(mc.pm_03_pc[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_05_pc[chIndex])) {
|
|
||||||
root[json_prop_pm05Count] = ag->round2(mc.pm_05_pc[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_01_pc[chIndex])) {
|
|
||||||
root[json_prop_pm1Count] = ag->round2(mc.pm_01_pc[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_25_pc[chIndex])) {
|
|
||||||
root[json_prop_pm25Count] = ag->round2(mc.pm_25_pc[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_5_pc[chIndex])) {
|
|
||||||
root[json_prop_pm5Count] = ag->round2(mc.pm_5_pc[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidPm03Count(mc.pm_10_pc[chIndex])) {
|
|
||||||
root[json_prop_pm10Count] = ag->round2(mc.pm_10_pc[chIndex]);
|
|
||||||
}
|
|
||||||
// Temperature and humidity
|
|
||||||
if (config.hasSensorSHT) {
|
|
||||||
// If SHT exists, it always on channel 1
|
|
||||||
if (utils::isValidTemperature(mc.temperature[0])) {
|
|
||||||
root[json_prop_temp] = ag->round2(mc.temperature[0]);
|
|
||||||
}
|
|
||||||
if (utils::isValidHumidity(mc.humidity[0])) {
|
|
||||||
root[json_prop_rhum] = ag->round2(mc.humidity[0]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (utils::isValidTemperature(mc.temperature[chIndex])) {
|
|
||||||
root[json_prop_temp] = ag->round2(mc.temperature[chIndex]);
|
|
||||||
}
|
|
||||||
if (utils::isValidHumidity(mc.humidity[chIndex])) {
|
|
||||||
root[json_prop_rhum] = ag->round2(mc.humidity[chIndex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Others
|
|
||||||
root["boot"] = mc.bootCount;
|
|
||||||
root["bootCount"] = mc.bootCount;
|
|
||||||
root["wifi"] = mc.wifi;
|
|
||||||
root["freeHeap"] = mc.freeHeap;
|
|
||||||
root["resetReason"] = _resetReason;
|
|
||||||
|
|
||||||
String result = JSON.stringify(root);
|
|
||||||
Serial.printf("\n---- TRANSMISSION PAYLOAD\n %s \n-----\n", result.c_str());
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
float pm_5_pc[2]; // particle count 5.0
|
float pm_5_pc[2]; // particle count 5.0
|
||||||
float pm_10_pc[2]; // particle count 10
|
float pm_10_pc[2]; // particle count 10
|
||||||
int bootCount;
|
int bootCount;
|
||||||
int wifi;
|
int signal;
|
||||||
uint32_t freeHeap;
|
uint32_t freeHeap;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ public:
|
|||||||
|
|
||||||
MeasurementCycle getMeasurementCycle();
|
MeasurementCycle getMeasurementCycle();
|
||||||
|
|
||||||
String buildMeasurementPayload(MeasurementCycle &mc, AgFirmwareMode fwMode);
|
String buildMeasurementPayload(MeasurementCycle &mc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true if want to debug every update value
|
* Set to true if want to debug every update value
|
||||||
|
Submodule src/Libraries/airgradient-client updated: 486ee4f6ef...9d82c081dd
Submodule src/Libraries/airgradient-ota updated: 71a25be14f...695751a67b
Reference in New Issue
Block a user