mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-07-28 16:07:16 +02:00
build CE payload include tvoc and nox index
If measures value invalid, set it to empty New schedule to print network signal
This commit is contained in:
@ -38,7 +38,6 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "EEPROM.h"
|
#include "EEPROM.h"
|
||||||
#include "ESPmDNS.h"
|
#include "ESPmDNS.h"
|
||||||
#include "Libraries/airgradient-ota/src/airgradientOta.h"
|
|
||||||
#include "LocalServer.h"
|
#include "LocalServer.h"
|
||||||
#include "MqttClient.h"
|
#include "MqttClient.h"
|
||||||
#include "OpenMetrics.h"
|
#include "OpenMetrics.h"
|
||||||
@ -54,6 +53,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|||||||
#include "Libraries/airgradient-client/src/cellularModuleA7672xx.h"
|
#include "Libraries/airgradient-client/src/cellularModuleA7672xx.h"
|
||||||
#include "Libraries/airgradient-client/src/airgradientCellularClient.h"
|
#include "Libraries/airgradient-client/src/airgradientCellularClient.h"
|
||||||
#include "Libraries/airgradient-client/src/airgradientWifiClient.h"
|
#include "Libraries/airgradient-client/src/airgradientWifiClient.h"
|
||||||
|
#include "Libraries/airgradient-ota/src/airgradientOta.h"
|
||||||
#include "Libraries/airgradient-ota/src/airgradientOtaWifi.h"
|
#include "Libraries/airgradient-ota/src/airgradientOtaWifi.h"
|
||||||
#include "Libraries/airgradient-ota/src/airgradientOtaCellular.h"
|
#include "Libraries/airgradient-ota/src/airgradientOtaCellular.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
@ -147,6 +147,7 @@ static void displayExecuteOta(AirgradientOTA::OtaResult result, String msg, int
|
|||||||
static int calculateMaxPeriod(int updateInterval);
|
static int calculateMaxPeriod(int updateInterval);
|
||||||
static void setMeasurementMaxPeriod();
|
static void setMeasurementMaxPeriod();
|
||||||
static void newMeasurementCycle();
|
static void newMeasurementCycle();
|
||||||
|
static void networkSignalCheck();
|
||||||
static void networkingTask(void *args);
|
static void networkingTask(void *args);
|
||||||
|
|
||||||
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDisplayAndLedBar);
|
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDisplayAndLedBar);
|
||||||
@ -160,6 +161,7 @@ AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
|
|||||||
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
|
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);
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
/** Serial for print debug message */
|
/** Serial for print debug message */
|
||||||
@ -575,6 +577,7 @@ void otaHandlerCallback(AirgradientOTA::OtaResult result, const char *msg) {
|
|||||||
displayExecuteOta(result, fwNewVersion, 0);
|
displayExecuteOta(result, fwNewVersion, 0);
|
||||||
break;
|
break;
|
||||||
case AirgradientOTA::InProgress:
|
case AirgradientOTA::InProgress:
|
||||||
|
Serial.printf("OTA progress: %s", msg);
|
||||||
displayExecuteOta(result, "", std::stoi(msg));
|
displayExecuteOta(result, "", std::stoi(msg));
|
||||||
break;
|
break;
|
||||||
case AirgradientOTA::Failed:
|
case AirgradientOTA::Failed:
|
||||||
@ -1329,8 +1332,8 @@ void postUsingCellular() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build payload include all measurements from queue
|
// Build payload include all measurements from queue
|
||||||
String payload;
|
std::string payload;
|
||||||
payload += String(CELLULAR_MEASUREMENT_INTERVAL / 1000); // Convert to seconds
|
payload += std::to_string(CELLULAR_MEASUREMENT_INTERVAL / 1000); // Convert to seconds
|
||||||
for (int i = 0; i < queueSize; i++) {
|
for (int i = 0; i < queueSize; i++) {
|
||||||
auto mc = measurementCycleQueue.at(i);
|
auto mc = measurementCycleQueue.at(i);
|
||||||
payload += ",";
|
payload += ",";
|
||||||
@ -1341,8 +1344,7 @@ void postUsingCellular() {
|
|||||||
xSemaphoreGive(mutexMeasurementCycleQueue);
|
xSemaphoreGive(mutexMeasurementCycleQueue);
|
||||||
|
|
||||||
// Attempt to send
|
// Attempt to send
|
||||||
Serial.println(payload);
|
if (agClient->httpPostMeasures(payload) == false) {
|
||||||
if (agClient->httpPostMeasures(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");
|
||||||
return;
|
return;
|
||||||
@ -1364,7 +1366,7 @@ void sendDataToServer(void) {
|
|||||||
|
|
||||||
if (networkOption == UseWifi) {
|
if (networkOption == UseWifi) {
|
||||||
postUsingWifi();
|
postUsingWifi();
|
||||||
} else {
|
} else if (networkOption == UseCellular) {
|
||||||
postUsingCellular();
|
postUsingCellular();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1443,6 +1445,20 @@ int calculateMaxPeriod(int updateInterval) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void networkSignalCheck() {
|
||||||
|
if (networkOption == UseWifi) {
|
||||||
|
Serial.printf("WiFi RSSI %d\n", wifiConnector.RSSI());
|
||||||
|
} else if (networkOption == UseCellular) {
|
||||||
|
auto result = cell->retrieveSignal();
|
||||||
|
if (result.status != CellReturnStatus::Ok) {
|
||||||
|
// TODO: Need to do something when get signal failed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Cellular signal strength %d\n", result.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void networkingTask(void *args) {
|
void networkingTask(void *args) {
|
||||||
// OTA check on boot
|
// OTA check on boot
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -1453,7 +1469,15 @@ void networkingTask(void *args) {
|
|||||||
checkForUpdateSchedule.update();
|
checkForUpdateSchedule.update();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: Need to better define delay value
|
// Because cellular interval is longer, needs to send first measures cycle on
|
||||||
|
// boot to indicate that its online
|
||||||
|
if (networkOption == UseCellular) {
|
||||||
|
Serial.println("Prepare first measures cycle to send on boot for 20s");
|
||||||
|
delay(20000);
|
||||||
|
newMeasurementCycle();
|
||||||
|
sendDataToServer();
|
||||||
|
measurementSchedule.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Reset scheduler
|
// Reset scheduler
|
||||||
configSchedule.update();
|
configSchedule.update();
|
||||||
@ -1489,6 +1513,7 @@ void networkingTask(void *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run scheduler
|
// Run scheduler
|
||||||
|
networkSignalCheckSchedule.run();
|
||||||
configSchedule.run();
|
configSchedule.run();
|
||||||
transmissionSchedule.run();
|
transmissionSchedule.run();
|
||||||
checkForUpdateSchedule.run();
|
checkForUpdateSchedule.run();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "AirGradient.h"
|
#include "AirGradient.h"
|
||||||
#include "App/AppDef.h"
|
#include "App/AppDef.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#define json_prop_pmFirmware "firmware"
|
#define json_prop_pmFirmware "firmware"
|
||||||
#define json_prop_pm01Ae "pm01"
|
#define json_prop_pm01Ae "pm01"
|
||||||
@ -733,90 +734,104 @@ Measurements::MeasurementCycle Measurements::getMeasurementCycle() {
|
|||||||
return mc;
|
return mc;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Measurements::buildMeasurementPayload(MeasurementCycle &mc) {
|
std::string Measurements::buildMeasurementPayload(MeasurementCycle &mc) {
|
||||||
String result;
|
std::ostringstream oss;
|
||||||
|
|
||||||
int co2 = utils::getInvalidCO2();
|
|
||||||
float temp = utils::getInvalidTemperature();
|
|
||||||
float hum = utils::getInvalidHumidity();
|
|
||||||
float pm01 = utils::getInvalidPmValue();
|
|
||||||
float pm25 = utils::getInvalidPmValue();
|
|
||||||
float pm10 = utils::getInvalidPmValue();
|
|
||||||
int nox = utils::getInvalidNOx();
|
|
||||||
int pm003Count = utils::getInvalidPmValue();
|
|
||||||
|
|
||||||
// CO2
|
// CO2
|
||||||
if (utils::isValidCO2(mc.co2)) {
|
if (utils::isValidCO2(mc.co2)) {
|
||||||
co2 = std::round(mc.co2);
|
oss << std::round(mc.co2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOx
|
oss << ",";
|
||||||
if (utils::isValidNOx(mc.nox)) {
|
|
||||||
nox = std::round(mc.nox);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Temperature
|
// Temperature
|
||||||
if (utils::isValidTemperature(mc.temperature[0]) && utils::isValidTemperature(mc.temperature[1])) {
|
if (utils::isValidTemperature(mc.temperature[0]) && utils::isValidTemperature(mc.temperature[1])) {
|
||||||
temp = ag->round2((mc.temperature[0] + mc.temperature[1]) / 2.0f);
|
float temp = (mc.temperature[0] + mc.temperature[1]) / 2.0f;
|
||||||
|
oss << std::round(temp * 10);
|
||||||
} else if (utils::isValidTemperature(mc.temperature[0])) {
|
} else if (utils::isValidTemperature(mc.temperature[0])) {
|
||||||
temp = ag->round2(mc.temperature[0]);
|
oss << std::round(mc.temperature[0] * 10);
|
||||||
} else if (utils::isValidTemperature(mc.temperature[1])) {
|
} else if (utils::isValidTemperature(mc.temperature[1])) {
|
||||||
temp = ag->round2(mc.temperature[1]);
|
oss << std::round(mc.temperature[1] * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
// Humidity
|
// Humidity
|
||||||
if (utils::isValidHumidity(mc.humidity[0]) && utils::isValidHumidity(mc.humidity[1])) {
|
if (utils::isValidHumidity(mc.humidity[0]) && utils::isValidHumidity(mc.humidity[1])) {
|
||||||
hum = ag->round2((mc.humidity[0] + mc.humidity[1]) / 2.0f);
|
float hum = (mc.humidity[0] + mc.humidity[1]) / 2.0f;
|
||||||
|
oss << std::round(hum * 10);
|
||||||
} else if (utils::isValidHumidity(mc.humidity[0])) {
|
} else if (utils::isValidHumidity(mc.humidity[0])) {
|
||||||
hum = ag->round2(mc.humidity[0]);
|
oss << std::round(mc.humidity[0] * 10);
|
||||||
} else if (utils::isValidHumidity(mc.humidity[1])) {
|
} else if (utils::isValidHumidity(mc.humidity[1])) {
|
||||||
hum = ag->round2(mc.humidity[1]);
|
oss << std::round(mc.humidity[1] * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
/// 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])) {
|
||||||
pm01 = ag->round2((mc.pm_01[0] + mc.pm_01[1]) / 2.0f);
|
float pm01 = (mc.pm_01[0] + mc.pm_01[1]) / 2.0f;
|
||||||
|
oss << std::round(pm01 * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_01[0])) {
|
} else if (utils::isValidPm(mc.pm_01[0])) {
|
||||||
pm01 = ag->round2(mc.pm_01[0]);
|
oss << std::round(mc.pm_01[0] * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_01[1])) {
|
} else if (utils::isValidPm(mc.pm_01[1])) {
|
||||||
pm01 = ag->round2(mc.pm_01[1]);
|
oss << std::round(mc.pm_01[1] * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
/// 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])) {
|
||||||
pm25 = ag->round2((mc.pm_25[0] + mc.pm_25[1]) / 2.0f);
|
float pm25 = (mc.pm_25[0] + mc.pm_25[1]) / 2.0f;
|
||||||
|
oss << std::round(pm25 * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_25[0])) {
|
} else if (utils::isValidPm(mc.pm_25[0])) {
|
||||||
pm25 = ag->round2(mc.pm_25[0]);
|
oss << std::round(mc.pm_25[0] * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_25[1])) {
|
} else if (utils::isValidPm(mc.pm_25[1])) {
|
||||||
pm25 = ag->round2(mc.pm_25[1]);
|
oss << std::round(mc.pm_25[1] * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
/// 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])) {
|
||||||
pm10 = ag->round2((mc.pm_10[0] + mc.pm_10[1]) / 2.0f);
|
float pm10 = (mc.pm_10[0] + mc.pm_10[1]) / 2.0f;
|
||||||
|
oss << std::round(pm10 * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_10[0])) {
|
} else if (utils::isValidPm(mc.pm_10[0])) {
|
||||||
pm10 = ag->round2(mc.pm_10[0]);
|
oss << std::round(mc.pm_10[0] * 10);
|
||||||
} else if (utils::isValidPm(mc.pm_10[1])) {
|
} else if (utils::isValidPm(mc.pm_10[1])) {
|
||||||
pm10 = ag->round2(mc.pm_10[1]);
|
oss << std::round(mc.pm_10[1] * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
|
// NOx
|
||||||
|
if (utils::isValidNOx(mc.nox)) {
|
||||||
|
oss << std::round(mc.nox);
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
|
// TVOC
|
||||||
|
if (utils::isValidVOC(mc.tvoc)) {
|
||||||
|
oss << std::round(mc.tvoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << ",";
|
||||||
|
|
||||||
/// PM 0.3 particle count
|
/// PM 0.3 particle count
|
||||||
if (utils::isValidPm03Count(mc.pm_03_pc[0]) && utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
if (utils::isValidPm03Count(mc.pm_03_pc[0]) && utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
||||||
pm003Count = std::round((mc.pm_03_pc[0] + mc.pm_03_pc[1]) / 2.0f);
|
oss << std::round((mc.pm_03_pc[0] + mc.pm_03_pc[1]) / 2.0f);
|
||||||
} else if (utils::isValidPm03Count(mc.pm_03_pc[0])) {
|
} else if (utils::isValidPm03Count(mc.pm_03_pc[0])) {
|
||||||
pm003Count = std::round(mc.pm_03_pc[0]);
|
oss << std::round(mc.pm_03_pc[0]);
|
||||||
} else if (utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
} else if (utils::isValidPm03Count(mc.pm_03_pc[1])) {
|
||||||
pm003Count = std::round(mc.pm_03_pc[1]);
|
oss << std::round(mc.pm_03_pc[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
char datapoint[128] = {0};
|
// char datapoint[128] = {0};
|
||||||
Serial.printf(datapoint, 128, "%d,%.0f,%.0f,%.0f,%.0f,%.0f,%d,%d\n", co2,
|
// snprintf(datapoint, 128, "%d,%.0f,%.0f,%.0f,%.0f,%.0f,%d,%d,%d", co2, temp * 10,
|
||||||
temp * 10, hum * 10, pm01 * 10, pm25 * 10, pm10 * 10, nox,
|
// hum * 10, pm01 * 10, pm25 * 10, pm10 * 10, tvoc, nox, pm003Count);
|
||||||
pm003Count);
|
|
||||||
snprintf(datapoint, 128, "%d,%.0f,%.0f,%.0f,%.0f,%.0f,%d,%d", co2, temp * 10,
|
|
||||||
hum * 10, pm01 * 10, pm25 * 10, pm10 * 10, nox, pm003Count);
|
|
||||||
|
|
||||||
return String(datapoint);
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ public:
|
|||||||
|
|
||||||
MeasurementCycle getMeasurementCycle();
|
MeasurementCycle getMeasurementCycle();
|
||||||
|
|
||||||
String buildMeasurementPayload(MeasurementCycle &mc);
|
std::string buildMeasurementPayload(MeasurementCycle &mc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to true if want to debug every update value
|
* Set to true if want to debug every update value
|
||||||
|
Reference in New Issue
Block a user