2024-03-23 16:58:17 +07:00
|
|
|
/*
|
2024-03-24 08:51:14 +07:00
|
|
|
This is the combined firmware code for AirGradient ONE and AirGradient Open Air
|
|
|
|
open-source hardware Air Quality Monitor with ESP32-C3 Microcontroller.
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
It is an air quality monitor for PM2.5, CO2, TVOCs, NOx, Temperature and
|
|
|
|
Humidity with a small display, an RGB led bar and can send data over Wifi.
|
|
|
|
|
|
|
|
Open source air quality monitors and kits are available:
|
|
|
|
Indoor Monitor: https://www.airgradient.com/indoor/
|
|
|
|
Outdoor Monitor: https://www.airgradient.com/outdoor/
|
|
|
|
|
2024-03-24 08:51:14 +07:00
|
|
|
Build Instructions: AirGradient ONE:
|
|
|
|
https://www.airgradient.com/documentation/one-v9/ Build Instructions:
|
|
|
|
AirGradient Open Air:
|
|
|
|
https://www.airgradient.com/documentation/open-air-pst-kit-1-3/
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
Please make sure you have esp32 board manager installed. Tested with
|
|
|
|
version 2.0.11.
|
|
|
|
|
|
|
|
Important flashing settings:
|
|
|
|
- Set board to "ESP32C3 Dev Module"
|
|
|
|
- Enable "USB CDC On Boot"
|
|
|
|
- Flash frequency "80Mhz"
|
|
|
|
- Flash mode "QIO"
|
|
|
|
- Flash size "4MB"
|
2024-03-24 08:51:14 +07:00
|
|
|
- Partition scheme "Minimal SPIFFS (1.9MB APP with OTA/190KB SPIFFS)"
|
2024-03-23 16:58:17 +07:00
|
|
|
- JTAG adapter "Disabled"
|
|
|
|
|
|
|
|
Configuration parameters, e.g. Celsius / Fahrenheit or PM unit (US AQI vs ug/m3)
|
|
|
|
can be set through the AirGradient dashboard.
|
|
|
|
|
|
|
|
If you have any questions please visit our forum at
|
|
|
|
https://forum.airgradient.com/
|
|
|
|
|
|
|
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <HardwareSerial.h>
|
2024-04-24 20:27:45 +07:00
|
|
|
#include "AirGradient.h"
|
2024-04-23 05:59:58 +07:00
|
|
|
#include "OtaHandler.h"
|
2024-04-03 07:04:28 +07:00
|
|
|
#include "AgApiClient.h"
|
|
|
|
#include "AgConfigure.h"
|
|
|
|
#include "AgSchedule.h"
|
|
|
|
#include "AgStateMachine.h"
|
2024-04-04 10:36:59 +07:00
|
|
|
#include "AgWiFiConnector.h"
|
2024-03-23 16:58:17 +07:00
|
|
|
#include "EEPROM.h"
|
2024-04-07 16:39:01 +07:00
|
|
|
#include "ESPmDNS.h"
|
|
|
|
#include "LocalServer.h"
|
2024-04-03 07:04:28 +07:00
|
|
|
#include "MqttClient.h"
|
2024-04-07 16:39:01 +07:00
|
|
|
#include "OpenMetrics.h"
|
|
|
|
#include "WebServer.h"
|
2024-03-23 16:58:17 +07:00
|
|
|
#include <WebServer.h>
|
2024-05-07 15:00:32 +07:00
|
|
|
#include <WiFi.h>
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */
|
|
|
|
#define DISP_UPDATE_INTERVAL 2500 /** ms */
|
|
|
|
#define SERVER_CONFIG_UPDATE_INTERVAL 15000 /** ms */
|
|
|
|
#define SERVER_SYNC_INTERVAL 60000 /** ms */
|
|
|
|
#define MQTT_SYNC_INTERVAL 60000 /** ms */
|
|
|
|
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
|
|
|
|
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
|
|
|
|
#define SENSOR_CO2_UPDATE_INTERVAL 4000 /** ms */
|
|
|
|
#define SENSOR_PM_UPDATE_INTERVAL 2000 /** ms */
|
|
|
|
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 2000 /** ms */
|
|
|
|
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
|
2024-04-03 07:04:28 +07:00
|
|
|
|
2024-03-23 17:44:11 +07:00
|
|
|
/** I2C define */
|
2024-03-23 16:58:17 +07:00
|
|
|
#define I2C_SDA_PIN 7
|
|
|
|
#define I2C_SCL_PIN 6
|
|
|
|
#define OLED_I2C_ADDR 0x3C
|
|
|
|
|
2024-04-03 07:04:28 +07:00
|
|
|
static MqttClient mqttClient(Serial);
|
2024-03-23 17:44:11 +07:00
|
|
|
static TaskHandle_t mqttTask = NULL;
|
2024-04-07 16:39:01 +07:00
|
|
|
static Configuration configuration(Serial);
|
|
|
|
static AgApiClient apiClient(Serial, configuration);
|
|
|
|
static Measurements measurements;
|
2024-03-23 16:58:17 +07:00
|
|
|
static AirGradient *ag;
|
2024-04-07 16:39:01 +07:00
|
|
|
static OledDisplay oledDisplay(configuration, measurements, Serial);
|
|
|
|
static StateMachine stateMachine(oledDisplay, Serial, measurements,
|
|
|
|
configuration);
|
2024-04-22 16:31:40 +07:00
|
|
|
static WifiConnector wifiConnector(oledDisplay, Serial, stateMachine,
|
|
|
|
configuration);
|
2024-04-07 16:39:01 +07:00
|
|
|
static OpenMetrics openMetrics(measurements, configuration, wifiConnector,
|
|
|
|
apiClient);
|
2024-04-23 05:59:58 +07:00
|
|
|
static OtaHandler otaHandler;
|
2024-04-07 16:39:01 +07:00
|
|
|
static LocalServer localServer(Serial, openMetrics, measurements, configuration,
|
|
|
|
wifiConnector);
|
|
|
|
|
2024-03-23 17:44:11 +07:00
|
|
|
static int pmFailCount = 0;
|
|
|
|
static uint32_t factoryBtnPressTime = 0;
|
|
|
|
static int getCO2FailCount = 0;
|
2024-04-03 07:04:28 +07:00
|
|
|
static AgFirmwareMode fwMode = FW_MODE_I_9PSL;
|
2024-03-23 17:44:11 +07:00
|
|
|
|
2024-03-24 08:51:14 +07:00
|
|
|
static bool ledBarButtonTest = false;
|
2024-05-02 18:22:26 +07:00
|
|
|
static String fwNewVersion;
|
2024-04-05 11:45:02 +07:00
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
static void boardInit(void);
|
|
|
|
static void failedHandler(String msg);
|
2024-04-07 16:39:01 +07:00
|
|
|
static void configurationUpdateSchedule(void);
|
2024-03-23 16:58:17 +07:00
|
|
|
static void appLedHandler(void);
|
|
|
|
static void appDispHandler(void);
|
2024-04-07 16:39:01 +07:00
|
|
|
static void oledDisplayLedBarSchedule(void);
|
|
|
|
static void updateTvoc(void);
|
|
|
|
static void updatePm(void);
|
2024-03-23 16:58:17 +07:00
|
|
|
static void sendDataToServer(void);
|
|
|
|
static void tempHumUpdate(void);
|
|
|
|
static void co2Update(void);
|
2024-04-07 16:39:01 +07:00
|
|
|
static void mdnsInit(void);
|
2024-03-23 16:58:17 +07:00
|
|
|
static void createMqttTask(void);
|
2024-04-07 16:39:01 +07:00
|
|
|
static void initMqtt(void);
|
2024-03-23 16:58:17 +07:00
|
|
|
static void factoryConfigReset(void);
|
|
|
|
static void wdgFeedUpdate(void);
|
2024-04-07 16:39:01 +07:00
|
|
|
static void ledBarEnabledUpdate(void);
|
2024-04-22 16:31:40 +07:00
|
|
|
static bool sgp41Init(void);
|
2024-05-03 17:27:05 +07:00
|
|
|
static void otaHandlerCallback(OtaState state, String mesasge);
|
|
|
|
static void displayExecuteOta(OtaState state, String msg,
|
|
|
|
int processing);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, oledDisplayLedBarSchedule);
|
2024-03-23 16:58:17 +07:00
|
|
|
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL,
|
2024-04-07 16:39:01 +07:00
|
|
|
configurationUpdateSchedule);
|
|
|
|
AgSchedule agApiPostSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
|
2024-03-23 16:58:17 +07:00
|
|
|
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
|
2024-04-07 16:39:01 +07:00
|
|
|
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, updatePm);
|
2024-03-23 16:58:17 +07:00
|
|
|
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
|
2024-04-07 16:39:01 +07:00
|
|
|
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
|
|
|
|
AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
void setup() {
|
|
|
|
/** Serial for print debug message */
|
|
|
|
Serial.begin(115200);
|
|
|
|
delay(100); /** For bester show log */
|
2024-04-07 16:39:01 +07:00
|
|
|
|
|
|
|
/** Print device ID into log */
|
|
|
|
Serial.println("Serial nr: " + ag->deviceId());
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-03-30 19:33:03 +07:00
|
|
|
/** Initialize local configure */
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.begin();
|
2024-03-30 19:33:03 +07:00
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
/** Init I2C */
|
|
|
|
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN);
|
|
|
|
delay(1000);
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
/** Detect board type: ONE_INDOOR has OLED display, Scan the I2C address to
|
|
|
|
* identify board type */
|
2024-03-23 16:58:17 +07:00
|
|
|
Wire.beginTransmission(OLED_I2C_ADDR);
|
|
|
|
if (Wire.endTransmission() == 0x00) {
|
|
|
|
ag = new AirGradient(BoardType::ONE_INDOOR);
|
|
|
|
} else {
|
|
|
|
ag = new AirGradient(BoardType::OPEN_AIR_OUTDOOR);
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.println("Detected " + ag->getBoardName());
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Init sensor */
|
|
|
|
boardInit();
|
2024-04-25 06:49:14 +07:00
|
|
|
configuration.setAirGradient(ag);
|
2024-04-07 16:39:01 +07:00
|
|
|
oledDisplay.setAirGradient(ag);
|
|
|
|
stateMachine.setAirGradient(ag);
|
|
|
|
wifiConnector.setAirGradient(ag);
|
|
|
|
apiClient.setAirGradient(ag);
|
|
|
|
openMetrics.setAirGradient(ag);
|
|
|
|
localServer.setAirGraident(ag);
|
2024-04-04 18:35:15 +07:00
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
/** Connecting wifi */
|
2024-04-07 16:39:01 +07:00
|
|
|
bool connectToWifi = false;
|
|
|
|
if (ag->isOne()) {
|
2024-03-24 08:51:14 +07:00
|
|
|
if (ledBarButtonTest) {
|
2024-05-01 21:02:57 +07:00
|
|
|
stateMachine.executeLedBarPowerUpTest();
|
2024-05-07 15:00:32 +07:00
|
|
|
if (ag->button.getState() == PushButton::BUTTON_PRESSED) {
|
|
|
|
WiFi.begin("airgradient", "cleanair");
|
|
|
|
Serial.println("WiFi Credential reset to factory defaults");
|
|
|
|
ESP.restart();
|
|
|
|
}
|
2024-03-24 08:51:14 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
ledBarEnabledUpdate();
|
2024-03-24 08:51:14 +07:00
|
|
|
}
|
2024-05-09 14:32:42 +07:00
|
|
|
|
2024-05-13 14:43:53 +07:00
|
|
|
/** Show message confirm offline mode, should me perform if LED bar button
|
|
|
|
* test pressed */
|
|
|
|
if (ledBarButtonTest == false) {
|
|
|
|
oledDisplay.setText(
|
|
|
|
"Press now for",
|
|
|
|
configuration.isOfflineMode() ? "online mode" : "offline mode", "");
|
|
|
|
uint32_t startTime = millis();
|
|
|
|
while (true) {
|
|
|
|
if (ag->button.getState() == ag->button.BUTTON_PRESSED) {
|
|
|
|
configuration.setOfflineMode(!configuration.isOfflineMode());
|
|
|
|
|
|
|
|
oledDisplay.setText(
|
|
|
|
"Offline Mode",
|
|
|
|
configuration.isOfflineMode() ? " = True" : " = False", "");
|
|
|
|
delay(1000);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uint32_t periodMs = (uint32_t)(millis() - startTime);
|
|
|
|
if (periodMs >= 3000) {
|
|
|
|
break;
|
|
|
|
}
|
2024-05-09 14:32:42 +07:00
|
|
|
}
|
2024-05-13 14:43:53 +07:00
|
|
|
connectToWifi = !configuration.isOfflineMode();
|
|
|
|
} else {
|
|
|
|
configuration.setOfflineModeWithoutSave(true);
|
2024-05-09 14:32:42 +07:00
|
|
|
}
|
2024-03-24 08:51:14 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
connectToWifi = true;
|
2024-03-24 08:51:14 +07:00
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (connectToWifi) {
|
2024-04-04 18:35:15 +07:00
|
|
|
apiClient.begin();
|
|
|
|
|
|
|
|
if (wifiConnector.connect()) {
|
|
|
|
if (wifiConnector.isConnected()) {
|
2024-04-07 16:39:01 +07:00
|
|
|
mdnsInit();
|
|
|
|
localServer.begin();
|
|
|
|
initMqtt();
|
|
|
|
sendDataToAg();
|
2024-04-04 10:36:59 +07:00
|
|
|
|
2024-04-23 05:59:58 +07:00
|
|
|
#ifdef ESP8266
|
|
|
|
// ota not supported
|
|
|
|
#else
|
2024-05-02 10:19:49 +07:00
|
|
|
// otaHandler.updateFirmwareIfOutdated(ag->deviceId());
|
2024-04-23 05:59:58 +07:00
|
|
|
#endif
|
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
apiClient.fetchServerConfiguration();
|
2024-04-08 10:15:45 +07:00
|
|
|
configSchedule.update();
|
2024-04-04 18:35:15 +07:00
|
|
|
if (apiClient.isFetchConfigureFailed()) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
stateMachine.displayHandle(
|
|
|
|
AgStateMachineWiFiOkServerOkSensorConfigFailed);
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(
|
|
|
|
AgStateMachineWiFiOkServerOkSensorConfigFailed);
|
2024-04-04 18:35:15 +07:00
|
|
|
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
ledBarEnabledUpdate();
|
2024-04-04 10:36:59 +07:00
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-13 15:07:10 +07:00
|
|
|
/** Set offline mode without saving, cause wifi is not configured */
|
|
|
|
if (wifiConnector.hasConfigurated() == false) {
|
|
|
|
Serial.println("Set offline mode cause wifi is not configurated");
|
|
|
|
configuration.setOfflineModeWithoutSave(true);
|
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Show display Warning up */
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.setText("Warming Up", "Serial Number:", ag->deviceId().c_str());
|
2024-03-23 16:58:17 +07:00
|
|
|
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
2024-05-13 10:34:06 +07:00
|
|
|
|
|
|
|
Serial.println("Display brightness: " + String(configuration.getDisplayBrightness()));
|
|
|
|
oledDisplay.setBrightness(configuration.getDisplayBrightness());
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
appLedHandler();
|
2024-04-07 16:39:01 +07:00
|
|
|
appDispHandler();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void loop() {
|
|
|
|
/** Handle schedule */
|
|
|
|
dispLedSchedule.run();
|
|
|
|
configSchedule.run();
|
2024-04-07 16:39:01 +07:00
|
|
|
agApiPostSchedule.run();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorS8) {
|
2024-03-23 16:58:17 +07:00
|
|
|
co2Schedule.run();
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS1 || configuration.hasSensorPMS2) {
|
2024-03-23 16:58:17 +07:00
|
|
|
pmsSchedule.run();
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
if (configuration.hasSensorSHT) {
|
2024-03-23 16:58:17 +07:00
|
|
|
tempHumSchedule.run();
|
|
|
|
}
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorSGP) {
|
2024-03-23 16:58:17 +07:00
|
|
|
tvocSchedule.run();
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
if (configuration.hasSensorPMS1) {
|
2024-03-23 16:58:17 +07:00
|
|
|
ag->pms5003.handle();
|
|
|
|
}
|
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS1) {
|
2024-03-23 16:58:17 +07:00
|
|
|
ag->pms5003t_1.handle();
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS2) {
|
2024-03-23 16:58:17 +07:00
|
|
|
ag->pms5003t_2.handle();
|
|
|
|
}
|
|
|
|
}
|
2024-03-30 19:33:03 +07:00
|
|
|
|
2024-05-09 14:32:42 +07:00
|
|
|
/** Auto reset watchdog timer if offline mode or postDataToAirGradient */
|
|
|
|
if (configuration.isOfflineMode() ||
|
|
|
|
(configuration.isPostDataToAirGradient() == false)) {
|
2024-04-07 16:39:01 +07:00
|
|
|
watchdogFeedSchedule.run();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
2024-04-05 11:45:02 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
/** Check for handle WiFi reconnect */
|
|
|
|
wifiConnector.handle();
|
2024-04-04 10:36:59 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
/** factory reset handle */
|
|
|
|
factoryConfigReset();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
/** check that local configura changed then do some action */
|
|
|
|
configUpdateHandle();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void co2Update(void) {
|
|
|
|
int value = ag->s8.getCo2();
|
|
|
|
if (value >= 0) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.CO2 = value;
|
2024-03-23 16:58:17 +07:00
|
|
|
getCO2FailCount = 0;
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
getCO2FailCount++;
|
|
|
|
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
|
|
|
|
if (getCO2FailCount >= 3) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.CO2 = -1;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void mdnsInit(void) {
|
|
|
|
if (!MDNS.begin(localServer.getHostname().c_str())) {
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("Init mDNS failed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MDNS.addService("_airgradient", "_tcp", 80);
|
2024-04-03 07:04:28 +07:00
|
|
|
MDNS.addServiceTxt("_airgradient", "_tcp", "model",
|
|
|
|
AgFirmwareModeName(fwMode));
|
2024-04-04 10:36:59 +07:00
|
|
|
MDNS.addServiceTxt("_airgradient", "_tcp", "serialno", ag->deviceId());
|
2024-03-23 16:58:17 +07:00
|
|
|
MDNS.addServiceTxt("_airgradient", "_tcp", "fw_ver", ag->getVersion());
|
|
|
|
MDNS.addServiceTxt("_airgradient", "_tcp", "vendor", "AirGradient");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void createMqttTask(void) {
|
|
|
|
if (mqttTask) {
|
|
|
|
vTaskDelete(mqttTask);
|
|
|
|
mqttTask = NULL;
|
2024-04-04 18:35:15 +07:00
|
|
|
Serial.println("Delete old MQTT task");
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
Serial.println("Create new MQTT task");
|
2024-03-23 16:58:17 +07:00
|
|
|
xTaskCreate(
|
|
|
|
[](void *param) {
|
|
|
|
for (;;) {
|
|
|
|
delay(MQTT_SYNC_INTERVAL);
|
|
|
|
|
|
|
|
/** Send data */
|
2024-04-03 07:04:28 +07:00
|
|
|
if (mqttClient.isConnected()) {
|
2024-04-07 16:39:01 +07:00
|
|
|
String payload = measurements.toString(
|
2024-04-21 16:33:55 +07:00
|
|
|
true, fwMode, wifiConnector.RSSI(), ag, &configuration);
|
2024-04-04 10:36:59 +07:00
|
|
|
String topic = "airgradient/readings/" + ag->deviceId();
|
2024-04-04 18:35:15 +07:00
|
|
|
|
|
|
|
if (mqttClient.publish(topic.c_str(), payload.c_str(),
|
|
|
|
payload.length())) {
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("MQTT sync success");
|
|
|
|
} else {
|
|
|
|
Serial.println("MQTT sync failure");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-04-04 18:35:15 +07:00
|
|
|
"mqtt-task", 1024 * 4, NULL, 6, &mqttTask);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
if (mqttTask == NULL) {
|
|
|
|
Serial.println("Creat mqttTask failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void initMqtt(void) {
|
|
|
|
if (mqttClient.begin(configuration.getMqttBrokerUri())) {
|
|
|
|
Serial.println("Connect to MQTT broker successful");
|
|
|
|
createMqttTask();
|
|
|
|
} else {
|
|
|
|
Serial.println("Connect to MQTT broker failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
static void factoryConfigReset(void) {
|
|
|
|
if (ag->button.getState() == ag->button.BUTTON_PRESSED) {
|
|
|
|
if (factoryBtnPressTime == 0) {
|
|
|
|
factoryBtnPressTime = millis();
|
|
|
|
} else {
|
|
|
|
uint32_t ms = (uint32_t)(millis() - factoryBtnPressTime);
|
|
|
|
if (ms >= 2000) {
|
|
|
|
// Show display message: For factory keep for x seconds
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.setText("Factory reset", "keep pressed", "for 8 sec");
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
Serial.println("Factory reset, keep pressed for 8 sec");
|
|
|
|
}
|
|
|
|
|
|
|
|
int count = 7;
|
|
|
|
while (ag->button.getState() == ag->button.BUTTON_PRESSED) {
|
|
|
|
delay(1000);
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-04 10:36:59 +07:00
|
|
|
String str = "for " + String(count) + " sec";
|
2024-04-07 16:39:01 +07:00
|
|
|
oledDisplay.setText("Factory reset", "keep pressed", str.c_str());
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
Serial.printf("Factory reset, keep pressed for %d sec\r\n", count);
|
|
|
|
}
|
|
|
|
count--;
|
|
|
|
if (count == 0) {
|
|
|
|
/** Stop MQTT task first */
|
|
|
|
if (mqttTask) {
|
|
|
|
vTaskDelete(mqttTask);
|
|
|
|
mqttTask = NULL;
|
|
|
|
}
|
|
|
|
|
2024-05-13 11:47:37 +07:00
|
|
|
/** Reset WIFI */
|
|
|
|
WiFi.disconnect(true, true);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Reset local config */
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.reset();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.setText("Factory reset", "successful", "");
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
Serial.println("Factory reset successful");
|
|
|
|
}
|
|
|
|
delay(3000);
|
|
|
|
ESP.restart();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Show current content cause reset ignore */
|
|
|
|
factoryBtnPressTime = 0;
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
appDispHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (factoryBtnPressTime != 0) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
/** Restore last display content */
|
|
|
|
appDispHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
factoryBtnPressTime = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wdgFeedUpdate(void) {
|
|
|
|
ag->watchdog.reset();
|
|
|
|
Serial.println();
|
2024-05-13 11:18:08 +07:00
|
|
|
Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset");
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void ledBarEnabledUpdate(void) {
|
|
|
|
if (ag->isOne()) {
|
2024-05-13 10:34:06 +07:00
|
|
|
int brightness = configuration.getLedBarBrightness();
|
|
|
|
Serial.println("LED bar brightness: " + String(brightness));
|
|
|
|
if ((brightness == 0) || (configuration.getLedBarMode() == LedBarModeOff)) {
|
|
|
|
ag->ledBar.setEnable(false);
|
|
|
|
} else {
|
|
|
|
ag->ledBar.setBrighness(brightness);
|
|
|
|
ag->ledBar.setEnable(configuration.getLedBarMode() != LedBarModeOff);
|
|
|
|
}
|
2024-05-17 11:52:22 +07:00
|
|
|
ag->ledBar.show();
|
2024-04-07 16:39:01 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 16:31:40 +07:00
|
|
|
static bool sgp41Init(void) {
|
|
|
|
ag->sgp41.setNoxLearningOffset(configuration.getNoxLearningOffset());
|
|
|
|
ag->sgp41.setTvocLearningOffset(configuration.getTvocLearningOffset());
|
|
|
|
if (ag->sgp41.begin(Wire)) {
|
|
|
|
Serial.println("Init SGP41 success");
|
|
|
|
configuration.hasSensorSGP = true;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
Serial.println("Init SGP41 failuire");
|
|
|
|
configuration.hasSensorSGP = false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-03 17:27:05 +07:00
|
|
|
static void otaHandlerCallback(OtaState state, String mesasge) {
|
2024-05-02 18:22:26 +07:00
|
|
|
switch (state) {
|
2024-05-03 17:27:05 +07:00
|
|
|
case OtaState::OTA_STATE_BEGIN:
|
|
|
|
displayExecuteOta(state, fwNewVersion, 0);
|
2024-05-02 18:22:26 +07:00
|
|
|
break;
|
2024-05-03 17:27:05 +07:00
|
|
|
case OtaState::OTA_STATE_FAIL:
|
|
|
|
displayExecuteOta(state, "", 0);
|
2024-05-02 18:22:26 +07:00
|
|
|
break;
|
2024-05-03 17:27:05 +07:00
|
|
|
case OtaState::OTA_STATE_PROCESSING:
|
|
|
|
displayExecuteOta(state, "", mesasge.toInt());
|
2024-05-02 18:22:26 +07:00
|
|
|
break;
|
2024-05-03 17:27:05 +07:00
|
|
|
case OtaState::OTA_STATE_SUCCESS:
|
|
|
|
displayExecuteOta(state, "", mesasge.toInt());
|
2024-05-02 18:22:26 +07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-03 17:27:05 +07:00
|
|
|
static void displayExecuteOta(OtaState state, String msg, int processing) {
|
|
|
|
switch (state) {
|
|
|
|
case OtaState::OTA_STATE_BEGIN: {
|
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.showNewFirmwareVersion(msg);
|
|
|
|
} else {
|
|
|
|
Serial.println("New firmware: " + msg);
|
|
|
|
}
|
|
|
|
delay(2500);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OtaState::OTA_STATE_FAIL: {
|
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.showNewFirmwareFailed();
|
|
|
|
} else {
|
|
|
|
Serial.println("Error: Firmware update: failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
delay(2500);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OtaState::OTA_STATE_PROCESSING: {
|
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.showNewFirmwareUpdating(String(processing));
|
|
|
|
} else {
|
|
|
|
Serial.println("Firmware update: " + String(processing) + String("%"));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OtaState::OTA_STATE_SUCCESS: {
|
2024-05-08 12:31:54 +07:00
|
|
|
int i = 6;
|
|
|
|
while(i != 0) {
|
|
|
|
i = i - 1;
|
|
|
|
Serial.println("OTA update performed, restarting ...");
|
|
|
|
int i = 6;
|
|
|
|
while (i != 0) {
|
|
|
|
i = i - 1;
|
|
|
|
if (ag->isOne()) {
|
|
|
|
oledDisplay.showNewFirmwareSuccess(String(i));
|
|
|
|
} else {
|
|
|
|
Serial.println("Rebooting... " + String(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
delay(1000);
|
|
|
|
}
|
|
|
|
esp_restart();
|
2024-05-03 17:27:05 +07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void sendDataToAg() {
|
|
|
|
/** Change oledDisplay and led state */
|
|
|
|
if (ag->isOne()) {
|
|
|
|
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnecting);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnecting);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Task handle led connecting animation */
|
|
|
|
xTaskCreate(
|
|
|
|
[](void *obj) {
|
|
|
|
for (;;) {
|
2024-04-04 10:36:59 +07:00
|
|
|
// ledSmHandler();
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds();
|
|
|
|
if (stateMachine.getLedState() !=
|
|
|
|
AgStateMachineWiFiOkServerConnecting) {
|
2024-03-23 16:58:17 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
delay(LED_BAR_ANIMATION_PERIOD);
|
|
|
|
}
|
|
|
|
vTaskDelete(NULL);
|
|
|
|
},
|
|
|
|
"task_led", 2048, NULL, 5, NULL);
|
|
|
|
|
|
|
|
delay(1500);
|
2024-04-11 09:29:29 +07:00
|
|
|
if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnected);
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnectFailed);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnectFailed);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(AgStateMachineNormal);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void dispSensorNotFound(String ss) {
|
2024-04-04 10:36:59 +07:00
|
|
|
ss = ss + " not found";
|
2024-04-07 16:39:01 +07:00
|
|
|
oledDisplay.setText("Sensor init", "Error:", ss.c_str());
|
2024-03-23 16:58:17 +07:00
|
|
|
delay(2000);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void oneIndoorInit(void) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS2 = false;
|
2024-03-23 17:44:11 +07:00
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
/** Display init */
|
2024-04-07 16:39:01 +07:00
|
|
|
oledDisplay.begin();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Show boot display */
|
|
|
|
Serial.println("Firmware Version: " + ag->getVersion());
|
2024-04-22 19:52:13 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
oledDisplay.setText("AirGradient ONE",
|
|
|
|
"FW Version: ", ag->getVersion().c_str());
|
2024-03-23 16:58:17 +07:00
|
|
|
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
|
|
|
|
|
|
|
|
ag->ledBar.begin();
|
|
|
|
ag->button.begin();
|
|
|
|
ag->watchdog.begin();
|
|
|
|
|
|
|
|
/** Init sensor SGP41 */
|
2024-04-22 16:31:40 +07:00
|
|
|
if (sgp41Init() == false) {
|
2024-03-23 16:58:17 +07:00
|
|
|
dispSensorNotFound("SGP41");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** INit SHT */
|
|
|
|
if (ag->sht.begin(Wire) == false) {
|
|
|
|
Serial.println("SHTx sensor not found");
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorSHT = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
dispSensorNotFound("SHT");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Init S8 CO2 sensor */
|
|
|
|
if (ag->s8.begin(Serial1) == false) {
|
|
|
|
Serial.println("CO2 S8 sensor not found");
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorS8 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
dispSensorNotFound("S8");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Init PMS5003 */
|
|
|
|
if (ag->pms5003.begin(Serial0) == false) {
|
|
|
|
Serial.println("PMS sensor not found");
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS1 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
dispSensorNotFound("PMS");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Run LED test on start up */
|
2024-05-09 14:32:42 +07:00
|
|
|
oledDisplay.setText("Press now for", "LED test", "");
|
2024-03-24 08:51:14 +07:00
|
|
|
ledBarButtonTest = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
uint32_t stime = millis();
|
|
|
|
while (true) {
|
|
|
|
if (ag->button.getState() == ag->button.BUTTON_PRESSED) {
|
2024-03-24 08:51:14 +07:00
|
|
|
ledBarButtonTest = true;
|
2024-03-23 16:58:17 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
delay(1);
|
|
|
|
uint32_t ms = (uint32_t)(millis() - stime);
|
|
|
|
if (ms >= 3000) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void openAirInit(void) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorSHT = false;
|
2024-03-23 17:44:11 +07:00
|
|
|
|
2024-03-23 16:58:17 +07:00
|
|
|
fwMode = FW_MODE_O_1PST;
|
|
|
|
Serial.println("Firmware Version: " + ag->getVersion());
|
|
|
|
|
|
|
|
ag->watchdog.begin();
|
|
|
|
ag->button.begin();
|
|
|
|
ag->statusLed.begin();
|
|
|
|
|
|
|
|
/** detect sensor: PMS5003, PMS5003T, SGP41 and S8 */
|
|
|
|
/**
|
|
|
|
* Serial1 and Serial0 is use for connect S8 and PM sensor or both PM
|
|
|
|
*/
|
|
|
|
bool serial1Available = true;
|
|
|
|
bool serial0Available = true;
|
|
|
|
|
|
|
|
if (ag->s8.begin(Serial1) == false) {
|
|
|
|
Serial1.end();
|
|
|
|
delay(200);
|
|
|
|
Serial.println("Can not detect S8 on Serial1, try on Serial0");
|
|
|
|
/** Check on other port */
|
|
|
|
if (ag->s8.begin(Serial0) == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorS8 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
Serial.println("CO2 S8 sensor not found");
|
|
|
|
Serial.println("Can not detect S8 run mode 'PPT'");
|
|
|
|
fwMode = FW_MODE_O_1PPT;
|
|
|
|
|
|
|
|
Serial0.end();
|
|
|
|
delay(200);
|
|
|
|
} else {
|
|
|
|
Serial.println("Found S8 on Serial0");
|
|
|
|
serial0Available = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Serial.println("Found S8 on Serial1");
|
|
|
|
serial1Available = false;
|
|
|
|
}
|
|
|
|
|
2024-04-22 16:31:40 +07:00
|
|
|
if (sgp41Init() == false) {
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("SGP sensor not found");
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorS8 == false) {
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("Can not detect SGP run mode 'O-1PP'");
|
2024-03-23 17:44:11 +07:00
|
|
|
fwMode = FW_MODE_O_1PP;
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
Serial.println("Can not detect SGP run mode 'O-1PS'");
|
2024-04-13 20:50:11 +07:00
|
|
|
fwMode = FW_MODE_O_1PS;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Try to find the PMS on other difference port with S8 */
|
|
|
|
if (fwMode == FW_MODE_O_1PST) {
|
|
|
|
bool pmInitSuccess = false;
|
|
|
|
if (serial0Available) {
|
|
|
|
if (ag->pms5003t_1.begin(Serial0) == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS1 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("PMS1 sensor not found");
|
|
|
|
} else {
|
|
|
|
serial0Available = false;
|
|
|
|
pmInitSuccess = true;
|
|
|
|
Serial.println("Found PMS 1 on Serial0");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pmInitSuccess == false) {
|
|
|
|
if (serial1Available) {
|
|
|
|
if (ag->pms5003t_1.begin(Serial1) == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS1 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("PMS1 sensor not found");
|
|
|
|
} else {
|
|
|
|
serial1Available = false;
|
|
|
|
Serial.println("Found PMS 1 on Serial1");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS2 = false; // Disable PM2
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
if (ag->pms5003t_1.begin(Serial0) == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS1 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("PMS1 sensor not found");
|
|
|
|
} else {
|
|
|
|
Serial.println("Found PMS 1 on Serial0");
|
|
|
|
}
|
|
|
|
if (ag->pms5003t_2.begin(Serial1) == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
configuration.hasSensorPMS2 = false;
|
2024-03-23 16:58:17 +07:00
|
|
|
Serial.println("PMS2 sensor not found");
|
|
|
|
} else {
|
|
|
|
Serial.println("Found PMS 2 on Serial1");
|
|
|
|
}
|
2024-04-13 21:07:20 +07:00
|
|
|
|
|
|
|
if (fwMode == FW_MODE_O_1PP) {
|
|
|
|
int count = (configuration.hasSensorPMS1 ? 1 : 0) +
|
|
|
|
(configuration.hasSensorPMS2 ? 1 : 0);
|
|
|
|
if (count == 1) {
|
|
|
|
fwMode = FW_MODE_O_1P;
|
|
|
|
}
|
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/** update the PMS poll period base on fw mode and sensor available */
|
|
|
|
if (fwMode != FW_MODE_O_1PST) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS1 && configuration.hasSensorPMS2) {
|
2024-03-23 16:58:17 +07:00
|
|
|
pmsSchedule.setPeriod(2000);
|
|
|
|
}
|
|
|
|
}
|
2024-04-03 07:04:28 +07:00
|
|
|
Serial.printf("Firmware Mode: %s\r\n", AgFirmwareModeName(fwMode));
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void boardInit(void) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
oneIndoorInit();
|
|
|
|
} else {
|
|
|
|
openAirInit();
|
|
|
|
}
|
2024-04-22 16:31:40 +07:00
|
|
|
|
|
|
|
/** Set S8 CO2 abc days period */
|
|
|
|
if (configuration.hasSensorS8) {
|
|
|
|
if (ag->s8.setAbcPeriod(configuration.getCO2CalibrationAbcDays() * 24)) {
|
|
|
|
Serial.println("Set S8 AbcDays successful");
|
|
|
|
} else {
|
|
|
|
Serial.println("Set S8 AbcDays failure");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-13 20:39:05 +07:00
|
|
|
localServer.setFwMode(fwMode);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void failedHandler(String msg) {
|
|
|
|
while (true) {
|
|
|
|
Serial.println(msg);
|
|
|
|
vTaskDelay(1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void configurationUpdateSchedule(void) {
|
2024-04-04 18:35:15 +07:00
|
|
|
if (apiClient.fetchServerConfiguration()) {
|
2024-03-30 19:33:03 +07:00
|
|
|
configUpdateHandle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void configUpdateHandle() {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.isUpdated() == false) {
|
|
|
|
return;
|
2024-03-30 19:33:03 +07:00
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.executeCo2Calibration();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
String mqttUri = configuration.getMqttBrokerUri();
|
2024-04-04 18:35:15 +07:00
|
|
|
if (mqttClient.isCurrentUri(mqttUri) == false) {
|
2024-04-03 07:04:28 +07:00
|
|
|
mqttClient.end();
|
2024-04-07 16:39:01 +07:00
|
|
|
initMqtt();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-05-13 19:00:34 +07:00
|
|
|
if (configuration.hasSensorSGP) {
|
|
|
|
if (configuration.noxLearnOffsetChanged() ||
|
|
|
|
configuration.tvocLearnOffsetChanged()) {
|
|
|
|
ag->sgp41.end();
|
|
|
|
|
|
|
|
int oldTvocOffset = ag->sgp41.getTvocLearningOffset();
|
|
|
|
int oldNoxOffset = ag->sgp41.getNoxLearningOffset();
|
|
|
|
bool result = sgp41Init();
|
|
|
|
const char *resultStr = "successful";
|
|
|
|
if (!result) {
|
|
|
|
resultStr = "failure";
|
|
|
|
}
|
|
|
|
if (oldTvocOffset != configuration.getTvocLearningOffset()) {
|
|
|
|
Serial.printf("Setting tvocLearningOffset from %d to %d hours %s\r\n",
|
|
|
|
oldTvocOffset, configuration.getTvocLearningOffset(),
|
|
|
|
resultStr);
|
|
|
|
}
|
|
|
|
if (oldNoxOffset != configuration.getNoxLearningOffset()) {
|
|
|
|
Serial.printf("Setting noxLearningOffset from %d to %d hours %s\r\n",
|
|
|
|
oldNoxOffset, configuration.getNoxLearningOffset(),
|
|
|
|
resultStr);
|
|
|
|
}
|
2024-04-14 21:30:56 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-13 19:00:34 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
if (configuration.isLedBarBrightnessChanged()) {
|
2024-05-17 11:52:22 +07:00
|
|
|
if (configuration.getLedBarBrightness() == 0) {
|
|
|
|
ag->ledBar.setEnable(false);
|
|
|
|
} else {
|
|
|
|
if (configuration.getLedBarMode() != LedBarMode::LedBarModeOff) {
|
|
|
|
ag->ledBar.setEnable(true);
|
|
|
|
}
|
|
|
|
ag->ledBar.setBrighness(configuration.getLedBarBrightness());
|
|
|
|
}
|
|
|
|
ag->ledBar.show();
|
|
|
|
Serial.println("Set 'ledBarBrightness' brightness: " +
|
2024-05-13 19:00:34 +07:00
|
|
|
String(configuration.getLedBarBrightness()));
|
|
|
|
}
|
2024-05-17 11:52:22 +07:00
|
|
|
|
|
|
|
if (configuration.isLedBarModeChanged()) {
|
|
|
|
Serial.println("Set 'ledBarMode' " + String(configuration.getLedBarMode()));
|
|
|
|
Serial.println("Get 'ledBarBrightness' " + String(configuration.getLedBarBrightness()));
|
|
|
|
if (configuration.getLedBarBrightness() == 0) {
|
|
|
|
ag->ledBar.setEnable(false);
|
|
|
|
} else {
|
|
|
|
if(configuration.getLedBarMode() == LedBarMode::LedBarModeOff) {
|
|
|
|
ag->ledBar.setEnable(false);
|
|
|
|
} else {
|
|
|
|
ag->ledBar.setEnable(true);
|
|
|
|
ag->ledBar.setBrighness(configuration.getLedBarBrightness());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ag->ledBar.show();
|
|
|
|
}
|
|
|
|
|
2024-05-13 19:00:34 +07:00
|
|
|
if (configuration.isDisplayBrightnessChanged()) {
|
|
|
|
oledDisplay.setBrightness(configuration.getDisplayBrightness());
|
|
|
|
Serial.println("Set 'DisplayBrightness' brightness: " +
|
|
|
|
String(configuration.getDisplayBrightness()));
|
|
|
|
}
|
2024-05-17 11:52:22 +07:00
|
|
|
|
|
|
|
stateMachine.executeLedBarTest();
|
2024-05-01 21:25:35 +07:00
|
|
|
}
|
|
|
|
|
2024-05-02 18:22:26 +07:00
|
|
|
fwNewVersion = configuration.newFirmwareVersion();
|
|
|
|
if (fwNewVersion.length()) {
|
2024-05-15 17:09:06 +07:00
|
|
|
bool doOta = false;
|
|
|
|
if (measurements.otaBootCount == 0) {
|
|
|
|
doOta = true;
|
|
|
|
Serial.println("First OTA");
|
2024-05-02 18:22:26 +07:00
|
|
|
} else {
|
2024-05-15 17:09:06 +07:00
|
|
|
if ((measurements.bootCount - measurements.otaBootCount) >= 30) {
|
|
|
|
doOta = true;
|
|
|
|
} else {
|
|
|
|
Serial.println(
|
|
|
|
"OTA ignore, try again next " +
|
|
|
|
String(30 - (measurements.bootCount - measurements.otaBootCount)) +
|
|
|
|
String(" boots"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doOta) {
|
|
|
|
measurements.otaBootCount = measurements.bootCount;
|
2024-05-02 18:22:26 +07:00
|
|
|
otaHandler.setHandlerCallback(otaHandlerCallback);
|
|
|
|
otaHandler.updateFirmwareIfOutdated(ag->deviceId());
|
|
|
|
}
|
2024-05-02 10:19:49 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
appDispHandler();
|
|
|
|
appLedHandler();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void appLedHandler(void) {
|
2024-04-04 10:36:59 +07:00
|
|
|
AgStateMachineState state = AgStateMachineNormal;
|
2024-05-15 17:11:26 +07:00
|
|
|
if (configuration.isOfflineMode() == false) {
|
|
|
|
if (wifiConnector.isConnected() == false) {
|
|
|
|
state = AgStateMachineWiFiLost;
|
|
|
|
} else if (apiClient.isFetchConfigureFailed()) {
|
|
|
|
stateMachine.displaySetAddToDashBoard();
|
|
|
|
state = AgStateMachineSensorConfigFailed;
|
|
|
|
} else if (apiClient.isPostToServerFailed()) {
|
|
|
|
state = AgStateMachineServerLost;
|
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
2024-04-04 18:35:15 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.handleLeds(state);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void appDispHandler(void) {
|
2024-04-07 16:39:01 +07:00
|
|
|
if (ag->isOne()) {
|
|
|
|
AgStateMachineState state = AgStateMachineNormal;
|
2024-04-04 18:35:15 +07:00
|
|
|
|
2024-05-13 12:02:17 +07:00
|
|
|
/** Only show display status on online mode. */
|
|
|
|
if (configuration.isOfflineMode() == false) {
|
|
|
|
if (wifiConnector.isConnected() == false) {
|
|
|
|
state = AgStateMachineWiFiLost;
|
|
|
|
} else if (apiClient.isFetchConfigureFailed()) {
|
|
|
|
state = AgStateMachineSensorConfigFailed;
|
|
|
|
} else if (apiClient.isPostToServerFailed()) {
|
|
|
|
state = AgStateMachineServerLost;
|
|
|
|
}
|
|
|
|
}
|
2024-04-07 16:39:01 +07:00
|
|
|
stateMachine.displayHandle(state);
|
|
|
|
}
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void oledDisplayLedBarSchedule(void) {
|
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
if (factoryBtnPressTime == 0) {
|
|
|
|
appDispHandler();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
appLedHandler();
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void updateTvoc(void) {
|
|
|
|
measurements.TVOC = ag->sgp41.getTvocIndex();
|
|
|
|
measurements.TVOCRaw = ag->sgp41.getTvocRaw();
|
|
|
|
measurements.NOx = ag->sgp41.getNoxIndex();
|
|
|
|
measurements.NOxRaw = ag->sgp41.getNoxRaw();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
Serial.println();
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("TVOC index: %d\r\n", measurements.TVOC);
|
|
|
|
Serial.printf("TVOC raw: %d\r\n", measurements.TVOCRaw);
|
|
|
|
Serial.printf("NOx index: %d\r\n", measurements.NOx);
|
|
|
|
Serial.printf("NOx raw: %d\r\n", measurements.NOxRaw);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
static void updatePm(void) {
|
|
|
|
if (ag->isOne()) {
|
2024-03-23 16:58:17 +07:00
|
|
|
if (ag->pms5003.isFailed() == false) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm01_1 = ag->pms5003.getPm01Ae();
|
|
|
|
measurements.pm25_1 = ag->pms5003.getPm25Ae();
|
|
|
|
measurements.pm10_1 = ag->pms5003.getPm10Ae();
|
|
|
|
measurements.pm03PCount_1 = ag->pms5003.getPm03ParticleCount();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
Serial.println();
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("PM1 ug/m3: %d\r\n", measurements.pm01_1);
|
|
|
|
Serial.printf("PM2.5 ug/m3: %d\r\n", measurements.pm25_1);
|
|
|
|
Serial.printf("PM10 ug/m3: %d\r\n", measurements.pm10_1);
|
|
|
|
Serial.printf("PM0.3 Count: %d\r\n", measurements.pm03PCount_1);
|
2024-03-23 16:58:17 +07:00
|
|
|
pmFailCount = 0;
|
|
|
|
} else {
|
|
|
|
pmFailCount++;
|
|
|
|
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
|
|
|
|
if (pmFailCount >= 3) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm01_1 = -1;
|
|
|
|
measurements.pm25_1 = -1;
|
|
|
|
measurements.pm10_1 = -1;
|
|
|
|
measurements.pm03PCount_1 = -1;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool pmsResult_1 = false;
|
|
|
|
bool pmsResult_2 = false;
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS1 && (ag->pms5003t_1.isFailed() == false)) {
|
|
|
|
measurements.pm01_1 = ag->pms5003t_1.getPm01Ae();
|
|
|
|
measurements.pm25_1 = ag->pms5003t_1.getPm25Ae();
|
|
|
|
measurements.pm10_1 = ag->pms5003t_1.getPm10Ae();
|
|
|
|
measurements.pm03PCount_1 = ag->pms5003t_1.getPm03ParticleCount();
|
|
|
|
measurements.temp_1 = ag->pms5003t_1.getTemperature();
|
|
|
|
measurements.hum_1 = ag->pms5003t_1.getRelativeHumidity();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
pmsResult_1 = true;
|
|
|
|
|
|
|
|
Serial.println();
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("[1] PM1 ug/m3: %d\r\n", measurements.pm01_1);
|
|
|
|
Serial.printf("[1] PM2.5 ug/m3: %d\r\n", measurements.pm25_1);
|
|
|
|
Serial.printf("[1] PM10 ug/m3: %d\r\n", measurements.pm10_1);
|
|
|
|
Serial.printf("[1] PM3.0 Count: %d\r\n", measurements.pm03PCount_1);
|
|
|
|
Serial.printf("[1] Temperature in C: %0.2f\r\n", measurements.temp_1);
|
|
|
|
Serial.printf("[1] Relative Humidity: %d\r\n", measurements.hum_1);
|
2024-04-21 21:03:02 +07:00
|
|
|
Serial.printf("[1] Temperature compensated in C: %0.2f\r\n",
|
|
|
|
ag->pms5003t_1.temperatureCompensated(measurements.temp_1));
|
2024-05-15 17:13:39 +07:00
|
|
|
Serial.printf("[1] Relative Humidity compensated: %f\r\n",
|
2024-04-21 21:03:02 +07:00
|
|
|
ag->pms5003t_1.humidityCompensated(measurements.hum_1));
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm01_1 = -1;
|
|
|
|
measurements.pm25_1 = -1;
|
|
|
|
measurements.pm10_1 = -1;
|
|
|
|
measurements.pm03PCount_1 = -1;
|
|
|
|
measurements.temp_1 = -1001;
|
|
|
|
measurements.hum_1 = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (configuration.hasSensorPMS2 && (ag->pms5003t_2.isFailed() == false)) {
|
|
|
|
measurements.pm01_2 = ag->pms5003t_2.getPm01Ae();
|
|
|
|
measurements.pm25_2 = ag->pms5003t_2.getPm25Ae();
|
|
|
|
measurements.pm10_2 = ag->pms5003t_2.getPm10Ae();
|
|
|
|
measurements.pm03PCount_2 = ag->pms5003t_2.getPm03ParticleCount();
|
|
|
|
measurements.temp_2 = ag->pms5003t_2.getTemperature();
|
|
|
|
measurements.hum_2 = ag->pms5003t_2.getRelativeHumidity();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
pmsResult_2 = true;
|
|
|
|
|
|
|
|
Serial.println();
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("[2] PM1 ug/m3: %d\r\n", measurements.pm01_2);
|
|
|
|
Serial.printf("[2] PM2.5 ug/m3: %d\r\n", measurements.pm25_2);
|
|
|
|
Serial.printf("[2] PM10 ug/m3: %d\r\n", measurements.pm10_2);
|
|
|
|
Serial.printf("[2] PM3.0 Count: %d\r\n", measurements.pm03PCount_2);
|
|
|
|
Serial.printf("[2] Temperature in C: %0.2f\r\n", measurements.temp_2);
|
|
|
|
Serial.printf("[2] Relative Humidity: %d\r\n", measurements.hum_2);
|
2024-04-22 16:31:40 +07:00
|
|
|
Serial.printf("[2] Temperature compensated in C: %0.2f\r\n",
|
2024-04-21 21:03:02 +07:00
|
|
|
ag->pms5003t_1.temperatureCompensated(measurements.temp_2));
|
|
|
|
Serial.printf("[2] Relative Humidity compensated: %d\r\n",
|
|
|
|
ag->pms5003t_1.humidityCompensated(measurements.hum_2));
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm01_2 = -1;
|
|
|
|
measurements.pm25_2 = -1;
|
|
|
|
measurements.pm10_2 = -1;
|
|
|
|
measurements.pm03PCount_2 = -1;
|
|
|
|
measurements.temp_2 = -1001;
|
|
|
|
measurements.hum_2 = -1;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorPMS1 && configuration.hasSensorPMS2 &&
|
|
|
|
pmsResult_1 && pmsResult_2) {
|
2024-03-23 16:58:17 +07:00
|
|
|
/** Get total of PMS1*/
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm1Value01 = measurements.pm1Value01 + measurements.pm01_1;
|
|
|
|
measurements.pm1Value25 = measurements.pm1Value25 + measurements.pm25_1;
|
|
|
|
measurements.pm1Value10 = measurements.pm1Value10 + measurements.pm10_1;
|
|
|
|
measurements.pm1PCount =
|
|
|
|
measurements.pm1PCount + measurements.pm03PCount_1;
|
|
|
|
measurements.pm1temp = measurements.pm1temp + measurements.temp_1;
|
|
|
|
measurements.pm1hum = measurements.pm1hum + measurements.hum_1;
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Get total of PMS2 */
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.pm2Value01 = measurements.pm2Value01 + measurements.pm01_2;
|
|
|
|
measurements.pm2Value25 = measurements.pm2Value25 + measurements.pm25_2;
|
|
|
|
measurements.pm2Value10 = measurements.pm2Value10 + measurements.pm10_2;
|
|
|
|
measurements.pm2PCount =
|
|
|
|
measurements.pm2PCount + measurements.pm03PCount_2;
|
|
|
|
measurements.pm2temp = measurements.pm2temp + measurements.temp_2;
|
|
|
|
measurements.pm2hum = measurements.pm2hum + measurements.hum_2;
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.countPosition++;
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
/** Get average */
|
2024-04-07 16:39:01 +07:00
|
|
|
if (measurements.countPosition == measurements.targetCount) {
|
|
|
|
measurements.pm01_1 =
|
|
|
|
measurements.pm1Value01 / measurements.targetCount;
|
|
|
|
measurements.pm25_1 =
|
|
|
|
measurements.pm1Value25 / measurements.targetCount;
|
|
|
|
measurements.pm10_1 =
|
|
|
|
measurements.pm1Value10 / measurements.targetCount;
|
|
|
|
measurements.pm03PCount_1 =
|
|
|
|
measurements.pm1PCount / measurements.targetCount;
|
|
|
|
measurements.temp_1 = measurements.pm1temp / measurements.targetCount;
|
|
|
|
measurements.hum_1 = measurements.pm1hum / measurements.targetCount;
|
|
|
|
|
|
|
|
measurements.pm01_2 =
|
|
|
|
measurements.pm2Value01 / measurements.targetCount;
|
|
|
|
measurements.pm25_2 =
|
|
|
|
measurements.pm2Value25 / measurements.targetCount;
|
|
|
|
measurements.pm10_2 =
|
|
|
|
measurements.pm2Value10 / measurements.targetCount;
|
|
|
|
measurements.pm03PCount_2 =
|
|
|
|
measurements.pm2PCount / measurements.targetCount;
|
|
|
|
measurements.temp_2 = measurements.pm2temp / measurements.targetCount;
|
|
|
|
measurements.hum_2 = measurements.pm2hum / measurements.targetCount;
|
|
|
|
|
|
|
|
measurements.countPosition = 0;
|
|
|
|
|
|
|
|
measurements.pm1Value01 = 0;
|
|
|
|
measurements.pm1Value25 = 0;
|
|
|
|
measurements.pm1Value10 = 0;
|
|
|
|
measurements.pm1PCount = 0;
|
|
|
|
measurements.pm1temp = 0;
|
|
|
|
measurements.pm1hum = 0;
|
|
|
|
measurements.pm2Value01 = 0;
|
|
|
|
measurements.pm2Value25 = 0;
|
|
|
|
measurements.pm2Value10 = 0;
|
|
|
|
measurements.pm2PCount = 0;
|
|
|
|
measurements.pm2temp = 0;
|
|
|
|
measurements.pm2hum = 0;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 18:35:15 +07:00
|
|
|
if (pmsResult_1 && pmsResult_2) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.Temperature =
|
|
|
|
(measurements.temp_1 + measurements.temp_2) / 2;
|
|
|
|
measurements.Humidity = (measurements.hum_1 + measurements.hum_2) / 2;
|
2024-04-04 18:35:15 +07:00
|
|
|
} else {
|
|
|
|
if (pmsResult_1) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.Temperature = measurements.temp_1;
|
|
|
|
measurements.Humidity = measurements.hum_1;
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
|
|
|
if (pmsResult_2) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.Temperature = measurements.temp_2;
|
|
|
|
measurements.Humidity = measurements.hum_2;
|
2024-04-04 18:35:15 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorSGP) {
|
2024-03-23 16:58:17 +07:00
|
|
|
float temp;
|
|
|
|
float hum;
|
|
|
|
if (pmsResult_1 && pmsResult_2) {
|
2024-04-07 16:39:01 +07:00
|
|
|
temp = (measurements.temp_1 + measurements.temp_2) / 2.0f;
|
|
|
|
hum = (measurements.hum_1 + measurements.hum_2) / 2.0f;
|
2024-03-23 16:58:17 +07:00
|
|
|
} else {
|
|
|
|
if (pmsResult_1) {
|
2024-04-07 16:39:01 +07:00
|
|
|
temp = measurements.temp_1;
|
|
|
|
hum = measurements.hum_1;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
if (pmsResult_2) {
|
2024-04-07 16:39:01 +07:00
|
|
|
temp = measurements.temp_2;
|
|
|
|
hum = measurements.hum_2;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ag->sgp41.setCompensationTemperatureHumidity(temp, hum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sendDataToServer(void) {
|
2024-05-13 11:18:08 +07:00
|
|
|
/** Ignore send data to server if postToAirGradient disabled */
|
2024-05-13 14:43:53 +07:00
|
|
|
if (configuration.isPostDataToAirGradient() == false || configuration.isOfflineMode()) {
|
2024-05-13 11:18:08 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(),
|
|
|
|
ag, &configuration);
|
2024-04-04 18:35:15 +07:00
|
|
|
if (apiClient.postToServer(syncData)) {
|
2024-05-13 11:18:08 +07:00
|
|
|
ag->watchdog.reset();
|
|
|
|
Serial.println();
|
|
|
|
Serial.println(
|
|
|
|
"Online mode and isPostToAirGradient = true: watchdog reset");
|
|
|
|
Serial.println();
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.bootCount++;
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tempHumUpdate(void) {
|
2024-04-08 10:29:58 +07:00
|
|
|
delay(100);
|
2024-03-23 16:58:17 +07:00
|
|
|
if (ag->sht.measure()) {
|
2024-04-07 16:39:01 +07:00
|
|
|
measurements.Temperature = ag->sht.getTemperature();
|
|
|
|
measurements.Humidity = ag->sht.getRelativeHumidity();
|
2024-03-23 16:58:17 +07:00
|
|
|
|
2024-04-07 16:39:01 +07:00
|
|
|
Serial.printf("Temperature in C: %0.2f\r\n", measurements.Temperature);
|
|
|
|
Serial.printf("Relative Humidity: %d\r\n", measurements.Humidity);
|
2024-04-21 21:03:02 +07:00
|
|
|
Serial.printf("Temperature compensated in C: %0.2f\r\n",
|
2024-04-22 16:31:40 +07:00
|
|
|
measurements.Temperature);
|
2024-04-21 21:03:02 +07:00
|
|
|
Serial.printf("Relative Humidity compensated: %d\r\n",
|
2024-04-22 16:31:40 +07:00
|
|
|
measurements.Humidity);
|
2024-03-23 16:58:17 +07:00
|
|
|
|
|
|
|
// Update compensation temperature and humidity for SGP41
|
2024-04-07 16:39:01 +07:00
|
|
|
if (configuration.hasSensorSGP) {
|
|
|
|
ag->sgp41.setCompensationTemperatureHumidity(measurements.Temperature,
|
|
|
|
measurements.Humidity);
|
2024-03-23 16:58:17 +07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Serial.println("SHT read failed");
|
|
|
|
}
|
|
|
|
}
|