mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-26 08:11:33 +02:00
Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
d8eb6b3c1a | |||
969858b5cb | |||
09b5805686 | |||
b09b753339 | |||
ddb3dba131 | |||
e780b0ace6 | |||
e82da5401e | |||
50a98acde4 | |||
7049d21a41 | |||
d5cdeaa9f3 | |||
09207c6923 | |||
0a64424196 | |||
5b38ca222b | |||
9ee35341a5 | |||
cec0514444 | |||
626a2240fa | |||
174ec6568f | |||
6b55719399 | |||
e2084f0738 | |||
5e07923690 | |||
04049439b1 | |||
c148d256d7 | |||
02849a1938 | |||
074337a96d | |||
4daa817a0b | |||
81a4502952 | |||
764e2eae38 | |||
79bf9811be | |||
9475724d0c | |||
e7603a7659 | |||
9bba89722e | |||
81945a358e |
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -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
|
||||||
|
@ -117,7 +117,7 @@ enum NetworkOption {
|
|||||||
};
|
};
|
||||||
NetworkOption networkOption;
|
NetworkOption networkOption;
|
||||||
TaskHandle_t handleNetworkTask = NULL;
|
TaskHandle_t handleNetworkTask = NULL;
|
||||||
static bool otaInProgress = false;
|
static bool firmwareUpdateInProgress = false;
|
||||||
|
|
||||||
static uint32_t factoryBtnPressTime = 0;
|
static uint32_t factoryBtnPressTime = 0;
|
||||||
static AgFirmwareMode fwMode = FW_MODE_I_9PSL;
|
static AgFirmwareMode fwMode = FW_MODE_I_9PSL;
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -318,8 +319,8 @@ void loop() {
|
|||||||
// Schedule to feed external watchdog
|
// Schedule to feed external watchdog
|
||||||
watchdogFeedSchedule.run();
|
watchdogFeedSchedule.run();
|
||||||
|
|
||||||
if (otaInProgress) {
|
if (firmwareUpdateInProgress) {
|
||||||
// OTA currently in progress, temporarily disable running sensor schedules
|
// Firmare update currently in progress, temporarily disable running sensor schedules
|
||||||
delay(10000);
|
delay(10000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -352,7 +353,7 @@ void loop() {
|
|||||||
static bool pmsConnected = false;
|
static bool pmsConnected = false;
|
||||||
if (pmsConnected != ag->pms5003.connected()) {
|
if (pmsConnected != ag->pms5003.connected()) {
|
||||||
pmsConnected = ag->pms5003.connected();
|
pmsConnected = ag->pms5003.connected();
|
||||||
Serial.printf("PMS sensor %s ", pmsConnected?"connected":"removed");
|
Serial.printf("PMS sensor %s \n", pmsConnected?"connected":"removed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -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;
|
||||||
@ -562,28 +578,25 @@ void checkForFirmwareUpdate(void) {
|
|||||||
agOta = new AirgradientOTACellular(cellularCard);
|
agOta = new AirgradientOTACellular(cellularCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicate main task that ota is performing
|
// Indicate main task that firmware update is in progress
|
||||||
Serial.println("Check for firmware update, disabling main task");
|
firmwareUpdateInProgress = true;
|
||||||
otaInProgress = true;
|
|
||||||
if (configuration.hasSensorSGP && networkOption == UseCellular) {
|
|
||||||
// Only for cellular because it can disturb i2c line
|
|
||||||
Serial.println("Disable SGP41 task for cellular OTA");
|
|
||||||
ag->sgp41.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
agOta->setHandlerCallback(otaHandlerCallback);
|
agOta->setHandlerCallback(otaHandlerCallback);
|
||||||
agOta->updateIfAvailable(ag->deviceId().c_str(), GIT_VERSION);
|
|
||||||
|
|
||||||
// Only goes to this line if OTA is not success
|
String httpDomain = configuration.getHttpDomain();
|
||||||
|
if (httpDomain != "") {
|
||||||
|
Serial.printf("httpDomain configuration available, start OTA with custom domain\n",
|
||||||
|
httpDomain.c_str());
|
||||||
|
agOta->updateIfAvailable(ag->deviceId().c_str(), GIT_VERSION, httpDomain.c_str());
|
||||||
|
} else {
|
||||||
|
agOta->updateIfAvailable(ag->deviceId().c_str(), GIT_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only goes to this line if firmware update is not success
|
||||||
// Handled by otaHandlerCallback
|
// Handled by otaHandlerCallback
|
||||||
|
|
||||||
otaInProgress = false;
|
// Indicate main task that firmware update finish
|
||||||
if (configuration.hasSensorSGP && networkOption == UseCellular) {
|
firmwareUpdateInProgress = false;
|
||||||
// Re-start SGP41 task
|
|
||||||
if (!sgp41Init()) {
|
|
||||||
Serial.println("Failed re-start SGP41 task");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete agOta;
|
delete agOta;
|
||||||
Serial.println();
|
Serial.println();
|
||||||
@ -591,14 +604,25 @@ void checkForFirmwareUpdate(void) {
|
|||||||
|
|
||||||
void otaHandlerCallback(AirgradientOTA::OtaResult result, const char *msg) {
|
void otaHandlerCallback(AirgradientOTA::OtaResult result, const char *msg) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case AirgradientOTA::Starting:
|
case AirgradientOTA::Starting: {
|
||||||
|
Serial.println("Firmware update starting...");
|
||||||
|
if (configuration.hasSensorSGP && networkOption == UseCellular) {
|
||||||
|
// Temporary pause SGP41 task while cellular firmware update is in progress
|
||||||
|
ag->sgp41.pause();
|
||||||
|
}
|
||||||
displayExecuteOta(result, fwNewVersion, 0);
|
displayExecuteOta(result, fwNewVersion, 0);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case AirgradientOTA::InProgress:
|
case AirgradientOTA::InProgress:
|
||||||
Serial.printf("OTA progress: %s\n", msg);
|
Serial.printf("OTA progress: %s\n", msg);
|
||||||
displayExecuteOta(result, "", std::stoi(msg));
|
displayExecuteOta(result, "", std::stoi(msg));
|
||||||
break;
|
break;
|
||||||
case AirgradientOTA::Failed:
|
case AirgradientOTA::Failed:
|
||||||
|
displayExecuteOta(result, "", 0);
|
||||||
|
if (configuration.hasSensorSGP && networkOption == UseCellular) {
|
||||||
|
ag->sgp41.resume();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AirgradientOTA::Skipped:
|
case AirgradientOTA::Skipped:
|
||||||
case AirgradientOTA::AlreadyUpToDate:
|
case AirgradientOTA::AlreadyUpToDate:
|
||||||
displayExecuteOta(result, "", 0);
|
displayExecuteOta(result, "", 0);
|
||||||
@ -665,7 +689,11 @@ static void displayExecuteOta(AirgradientOTA::OtaResult result, String msg, int
|
|||||||
}
|
}
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
oledDisplay.setAirGradient(0);
|
|
||||||
|
if (ag->isOne()) {
|
||||||
|
oledDisplay.setAirGradient(0);
|
||||||
|
oledDisplay.setBrightness(0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -977,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);
|
||||||
@ -1012,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();
|
||||||
@ -1047,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1057,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();
|
||||||
@ -1130,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
|
||||||
@ -1402,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1547,30 +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
|
||||||
#ifdef ESP8266
|
if (configuration.isCloudConnectionDisabled() == false) {
|
||||||
// ota not supported
|
// OTA check on boot
|
||||||
#else
|
#ifndef ESP8266
|
||||||
// because cellular it takes too long, watchdog triggered
|
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) {
|
||||||
@ -1625,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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=AirGradient Air Quality Sensor
|
name=AirGradient Air Quality Sensor
|
||||||
version=3.3.5
|
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.
|
||||||
|
@ -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 + "'";
|
||||||
}
|
}
|
||||||
|
@ -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_ */
|
||||||
|
157
src/AgValue.cpp
157
src/AgValue.cpp
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include "Main/utils.h"
|
#include "Main/utils.h"
|
||||||
|
|
||||||
#ifndef GIT_VERSION
|
#ifndef GIT_VERSION
|
||||||
#define GIT_VERSION "3.3.5-snap"
|
#define GIT_VERSION "3.3.9-snap"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
Submodule src/Libraries/airgradient-ota updated: fde4380164...c772392427
@ -131,6 +131,22 @@ void Sgp41::handle(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
void Sgp41::pause() {
|
||||||
|
onPause = true;
|
||||||
|
Serial.println("Pausing SGP41 handler task");
|
||||||
|
// Set latest value to invalid
|
||||||
|
tvocRaw = utils::getInvalidVOC();
|
||||||
|
tvoc = utils::getInvalidVOC();
|
||||||
|
noxRaw = utils::getInvalidNOx();
|
||||||
|
nox = utils::getInvalidNOx();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sgp41::resume() {
|
||||||
|
onPause = false;
|
||||||
|
Serial.println("Resuming SGP41 handler task");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle the sensor conditioning and run time udpate value, This method
|
* @brief Handle the sensor conditioning and run time udpate value, This method
|
||||||
* must not call, it's called on private task
|
* must not call, it's called on private task
|
||||||
@ -152,6 +168,11 @@ void Sgp41::_handle(void) {
|
|||||||
uint16_t srawVoc, srawNox;
|
uint16_t srawVoc, srawNox;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|
||||||
|
if (onPause) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (getRawSignal(srawVoc, srawNox)) {
|
if (getRawSignal(srawVoc, srawNox)) {
|
||||||
tvocRaw = srawVoc;
|
tvocRaw = srawVoc;
|
||||||
noxRaw = srawNox;
|
noxRaw = srawNox;
|
||||||
|
@ -18,6 +18,10 @@ public:
|
|||||||
bool begin(TwoWire &wire, Stream &stream);
|
bool begin(TwoWire &wire, Stream &stream);
|
||||||
void handle(void);
|
void handle(void);
|
||||||
#else
|
#else
|
||||||
|
/* pause _handle task to read sensor */
|
||||||
|
void pause();
|
||||||
|
/* resume _handle task to read sensor */
|
||||||
|
void resume();
|
||||||
void _handle(void);
|
void _handle(void);
|
||||||
#endif
|
#endif
|
||||||
void end(void);
|
void end(void);
|
||||||
@ -32,6 +36,7 @@ public:
|
|||||||
int getTvocLearningOffset(void);
|
int getTvocLearningOffset(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool onPause = false;
|
||||||
bool onConditioning = true;
|
bool onConditioning = true;
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
bool _isBegin = false;
|
bool _isBegin = false;
|
||||||
|
Reference in New Issue
Block a user