Merge pull request #64 from airgradienthq/feature/led-bar-color-for-pms-and-co2

Feature/led bar color for pms and co2
This commit is contained in:
Phat Nguyen
2024-02-29 09:38:13 +07:00
committed by GitHub
3 changed files with 382 additions and 45 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
.vscode
*.DS_Store *.DS_Store
build
.vscode

View File

@ -93,6 +93,7 @@ enum {
#define DISP_UPDATE_INTERVAL 5000 /** ms */ #define DISP_UPDATE_INTERVAL 5000 /** ms */
#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */ #define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */
#define SERVER_SYNC_INTERVAL 60000 /** ms */ #define SERVER_SYNC_INTERVAL 60000 /** ms */
#define MQTT_SYNC_INTERVAL 60000 /** ms */
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */ #define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */ #define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */ #define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
@ -152,6 +153,19 @@ public:
loadConfig(); loadConfig();
} }
/**
* @brief Reset local config into default value.
*
*/
void defaultReset(void) {
config.inF = false;
config.inUSAQI = false;
memset(config.models, 0, sizeof(config.models));
memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers));
config.useRGBLedBar = UseLedBarOff;
saveConfig();
}
/** /**
* @brief Get server configuration * @brief Get server configuration
* *
@ -631,6 +645,7 @@ public:
int connectionFailedCount(void) { return connectFailedCount; } int connectionFailedCount(void) { return connectFailedCount; }
}; };
AgMqtt agMqtt; AgMqtt agMqtt;
static TaskHandle_t mqttTask = NULL;
/** Create airgradient instance for 'ONE_INDOOR' board */ /** Create airgradient instance for 'ONE_INDOOR' board */
AirGradient ag(ONE_INDOOR); AirGradient ag(ONE_INDOOR);
@ -684,6 +699,8 @@ static void co2Poll(void);
static void showNr(void); static void showNr(void);
static void webServerInit(void); static void webServerInit(void);
static String getServerSyncData(bool localServer); static String getServerSyncData(bool localServer);
static void createMqttTask(void);
static void factoryConfigReset(void);
/** Init schedule */ /** Init schedule */
bool hasSensorS8 = true; bool hasSensorS8 = true;
@ -691,6 +708,7 @@ bool hasSensorPMS = true;
bool hasSensorSGP = true; bool hasSensorSGP = true;
bool hasSensorSHT = true; bool hasSensorSHT = true;
int pmFailCount = 0; int pmFailCount = 0;
uint32_t factoryBtnPressTime = 0;
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDispLedBar); AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, updateDispLedBar);
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
@ -754,6 +772,7 @@ void setup() {
/** MQTT init */ /** MQTT init */
if (agServer.getMqttBroker().isEmpty() == false) { if (agServer.getMqttBroker().isEmpty() == false) {
if (agMqtt.begin(agServer.getMqttBroker())) { if (agMqtt.begin(agServer.getMqttBroker())) {
createMqttTask();
Serial.println("MQTT client init success"); Serial.println("MQTT client init success");
} else { } else {
Serial.println("MQTT client init failure"); Serial.println("MQTT client init failure");
@ -806,6 +825,9 @@ void loop() {
/** Check for handle WiFi reconnect */ /** Check for handle WiFi reconnect */
updateWiFiConnect(); updateWiFiConnect();
/** factory reset handle */
factoryConfigReset();
} }
static void setTestColor(char color) { static void setTestColor(char color) {
@ -949,7 +971,7 @@ static String getServerSyncData(bool localServer) {
root["tvoc_raw"] = tvocRawIndex; root["tvoc_raw"] = tvocRawIndex;
} }
if (noxIndex >= 0) { if (noxIndex >= 0) {
root["noxIndex"] = noxIndex; root["nox_index"] = noxIndex;
} }
} }
if (hasSensorSHT) { if (hasSensorSHT) {
@ -965,6 +987,89 @@ static String getServerSyncData(bool localServer) {
return JSON.stringify(root); return JSON.stringify(root);
} }
static void createMqttTask(void) {
if (mqttTask) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
xTaskCreate(
[](void *param) {
for (;;) {
delay(MQTT_SYNC_INTERVAL);
/** Send data */
if (agMqtt.isConnected()) {
String syncData = getServerSyncData(false);
String topic = "airgradient/readings/" + getDevId();
if (agMqtt.publish(topic.c_str(), syncData.c_str(),
syncData.length())) {
Serial.println("Mqtt sync success");
} else {
Serial.println("Mqtt sync failure");
}
}
}
},
"mqtt-task", 1024 * 3, NULL, 6, &mqttTask);
if (mqttTask == NULL) {
Serial.println("Creat mqttTask failed");
}
}
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
// Count display.
displayShowText("For factory reset", "keep pressed", "for 8 sec");
int count = 7;
while (ag.button.getState() == ag.button.BUTTON_PRESSED) {
delay(1000);
displayShowText("For factory reset", "keep pressed",
"for " + String(count) + " sec");
count--;
// ms = (uint32_t)(millis() - factoryBtnPressTime);
if (count == 0) {
/** Stop MQTT task first */
if (mqttTask) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
/** Disconnect WIFI */
WiFi.disconnect();
wifiManager.resetSettings();
/** Reset local config */
agServer.defaultReset();
displayShowText("Factory reset", "successful", "");
delay(3000);
ESP.restart();
}
}
/** Show current content cause reset ignore */
factoryBtnPressTime = 0;
appDispHandler();
}
}
} else {
if (factoryBtnPressTime != 0) {
/** Restore last display content */
appDispHandler();
}
factoryBtnPressTime = 0;
}
}
static void sendPing() { static void sendPing() {
JSONVar root; JSONVar root;
root["wifi"] = WiFi.RSSI(); root["wifi"] = WiFi.RSSI();
@ -1287,20 +1392,80 @@ static String getNormalizedMac() {
} }
static void setRGBledCO2color(int co2Value) { static void setRGBledCO2color(int co2Value) {
if (co2Value >= 300 && co2Value < 800) { if (co2Value <= 400) {
setRGBledColor('g'); /** G; 1 */
} else if (co2Value >= 800 && co2Value < 1000) { ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
setRGBledColor('y'); } else if (co2Value <= 700) {
} else if (co2Value >= 1000 && co2Value < 1500) { /** GG; 2 */
setRGBledColor('o'); ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
} else if (co2Value >= 1500 && co2Value < 2000) { ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
setRGBledColor('r'); } else if (co2Value <= 1000) {
} else if (co2Value >= 2000 && co2Value < 3000) { /** YYY; 3 */
setRGBledColor('p'); ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
} else if (co2Value >= 3000 && co2Value < 10000) { ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
setRGBledColor('z'); ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
} else { } else if (co2Value <= 1333) {
setRGBledColor('n'); /** YYYY; 4 */
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
} else if (co2Value <= 1666) {
/** YYYYY; 5 */
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 5);
} else if (co2Value <= 2000) {
/** RRRRRR; 6 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
} else if (co2Value <= 2666) {
/** RRRRRRR; 7 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
} else if (co2Value <= 3333) {
/** RRRRRRRR; 8 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
} else if (co2Value <= 4000) {
/** RRRRRRRRR; 9 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 9);
} else { /** > 4000 */
/* PRPRPRPRP; 9 */
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 9);
} }
} }
@ -1458,8 +1623,14 @@ static void serverConfigPoll(void) {
String mqttUri = agServer.getMqttBroker(); String mqttUri = agServer.getMqttBroker();
if (mqttUri != agMqtt.getUri()) { if (mqttUri != agMqtt.getUri()) {
agMqtt.end(); agMqtt.end();
if (mqttTask != NULL) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
if (agMqtt.begin(mqttUri)) { if (agMqtt.begin(mqttUri)) {
Serial.println("Connect to new mqtt broker success"); Serial.println("Connect to new mqtt broker success");
createMqttTask();
} else { } else {
Serial.println("Connect to new mqtt broker failed"); Serial.println("Connect to new mqtt broker failed");
} }
@ -1506,18 +1677,81 @@ static void co2Calibration(void) {
* @param pm25Value PMS2.5 value * @param pm25Value PMS2.5 value
*/ */
static void setRGBledPMcolor(int pm25Value) { static void setRGBledPMcolor(int pm25Value) {
if (pm25Value >= 0 && pm25Value < 10) if (pm25Value <= 5) {
setRGBledColor('g'); /** G; 1 */
if (pm25Value >= 10 && pm25Value < 35) ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
setRGBledColor('y'); } else if (pm25Value <= 10) {
if (pm25Value >= 35 && pm25Value < 55) /** GG; 2 */
setRGBledColor('o'); ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
if (pm25Value >= 55 && pm25Value < 150) ag.ledBar.setColor(0, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
setRGBledColor('r'); } else if (pm25Value <= 20) {
if (pm25Value >= 150 && pm25Value < 250) /** YYY; 3 */
setRGBledColor('p'); ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
if (pm25Value >= 250 && pm25Value < 1000) ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
setRGBledColor('p'); ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
} else if (pm25Value <= 35) {
/** YYYY; 4 */
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
} else if (pm25Value <= 45) {
/** YYYYY; 5 */
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 255, 0, ag.ledBar.getNumberOfLeds() - 5);
} else if (pm25Value <= 55) {
/** RRRRRR; 6 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
} else if (pm25Value <= 65) {
/** RRRRRRR; 7 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
} else if (pm25Value <= 150) {
/** RRRRRRRR; 8 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
} else if (pm25Value <= 250) {
/** RRRRRRRRR; 9 */
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 9);
} else { /** > 250 */
/* PRPRPRPRP; 9 */
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 1);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 2);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 3);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 4);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 5);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 6);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 7);
ag.ledBar.setColor(255, 0, 0, ag.ledBar.getNumberOfLeds() - 8);
ag.ledBar.setColor(153, 153, 0, ag.ledBar.getNumberOfLeds() - 9);
}
} }
static void singleLedAnimation(uint8_t r, uint8_t g, uint8_t b) { static void singleLedAnimation(uint8_t r, uint8_t g, uint8_t b) {
@ -1786,7 +2020,9 @@ static void updateWiFiConnect(void) {
* *
*/ */
static void updateDispLedBar(void) { static void updateDispLedBar(void) {
appDispHandler(); if (factoryBtnPressTime == 0) {
appDispHandler();
}
appLedHandler(); appLedHandler();
} }
@ -1844,14 +2080,6 @@ static void sendDataToServer(void) {
resetWatchdog(); resetWatchdog();
} }
if (agMqtt.isConnected()) {
String topic = "airgradient/readings/" + getDevId();
if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) {
Serial.println("Mqtt sync success");
} else {
Serial.println("Mqtt sync failure");
}
}
bootCount++; bootCount++;
} }

View File

@ -85,6 +85,8 @@ enum {
#define LED_FAST_BLINK_DELAY 250 /** ms */ #define LED_FAST_BLINK_DELAY 250 /** ms */
#define LED_SLOW_BLINK_DELAY 1000 /** ms */ #define LED_SLOW_BLINK_DELAY 1000 /** ms */
#define LED_SHORT_BLINK_DELAY 500 /** ms */
#define LED_LONG_BLINK_DELAY 2000 /** ms */
#define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */ #define WIFI_CONNECT_COUNTDOWN_MAX 180 /** sec */
#define WIFI_CONNECT_RETRY_MS 10000 /** ms */ #define WIFI_CONNECT_RETRY_MS 10000 /** ms */
#define LED_BAR_COUNT_INIT_VALUE (-1) /** */ #define LED_BAR_COUNT_INIT_VALUE (-1) /** */
@ -92,6 +94,7 @@ enum {
#define DISP_UPDATE_INTERVAL 5000 /** ms */ #define DISP_UPDATE_INTERVAL 5000 /** ms */
#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */ #define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */
#define SERVER_SYNC_INTERVAL 60000 /** ms */ #define SERVER_SYNC_INTERVAL 60000 /** ms */
#define MQTT_SYNC_INTERVAL 60000 /** ms */
#define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */ #define SENSOR_CO2_CALIB_COUNTDOWN_MAX 5 /** sec */
#define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */ #define SENSOR_TVOC_UPDATE_INTERVAL 1000 /** ms */
#define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */ #define SENSOR_CO2_UPDATE_INTERVAL 5000 /** ms */
@ -152,6 +155,19 @@ public:
loadConfig(); loadConfig();
} }
/**
* @brief Reset local config into default value.
*
*/
void defaultReset(void) {
config.inF = false;
config.inUSAQI = false;
memset(config.models, 0, sizeof(config.models));
memset(config.mqttBrokers, 0, sizeof(config.mqttBrokers));
config.useRGBLedBar = UseLedBarOff;
saveConfig();
}
/** /**
* @brief Get server configuration * @brief Get server configuration
* *
@ -631,6 +647,7 @@ public:
int connectionFailedCount(void) { return connectFailedCount; } int connectionFailedCount(void) { return connectFailedCount; }
}; };
AgMqtt agMqtt; AgMqtt agMqtt;
static TaskHandle_t mqttTask = NULL;
/** Create airgradient instance for 'OPEN_AIR_OUTDOOR' board */ /** Create airgradient instance for 'OPEN_AIR_OUTDOOR' board */
AirGradient ag(OPEN_AIR_OUTDOOR); AirGradient ag(OPEN_AIR_OUTDOOR);
@ -701,11 +718,14 @@ static const char *getFwMode(int mode);
static void showNr(void); static void showNr(void);
static void webServerInit(void); static void webServerInit(void);
static String getServerSyncData(bool localServer); static String getServerSyncData(bool localServer);
static void createMqttTask(void);
static void factoryConfigReset(void);
bool hasSensorS8 = true; bool hasSensorS8 = true;
bool hasSensorPMS1 = true; bool hasSensorPMS1 = true;
bool hasSensorPMS2 = true; bool hasSensorPMS2 = true;
bool hasSensorSGP = true; bool hasSensorSGP = true;
uint32_t factoryBtnPressTime = 0;
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll); AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, serverConfigPoll);
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll); AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Poll);
@ -734,6 +754,7 @@ void setup() {
/** MQTT init */ /** MQTT init */
if (agServer.getMqttBroker().isEmpty() == false) { if (agServer.getMqttBroker().isEmpty() == false) {
if (agMqtt.begin(agServer.getMqttBroker())) { if (agMqtt.begin(agServer.getMqttBroker())) {
createMqttTask();
Serial.println("MQTT client init success"); Serial.println("MQTT client init success");
} else { } else {
Serial.println("MQTT client init failure"); Serial.println("MQTT client init failure");
@ -773,6 +794,8 @@ void loop() {
} }
} }
updateWiFiConnect(); updateWiFiConnect();
factoryConfigReset();
} }
void sendPing() { void sendPing() {
@ -793,14 +816,6 @@ static void sendDataToServer(void) {
resetWatchdog(); resetWatchdog();
} }
if (agMqtt.isConnected()) {
String topic = "airgradient/readings/" + getDevId();
if (agMqtt.publish(topic.c_str(), syncData.c_str(), syncData.length())) {
Serial.println("Mqtt sync success");
} else {
Serial.println("Mqtt sync failure");
}
}
loopCount++; loopCount++;
} }
@ -1162,8 +1177,13 @@ static void serverConfigPoll(void) {
String mqttUri = agServer.getMqttBroker(); String mqttUri = agServer.getMqttBroker();
if (mqttUri != agMqtt.getUri()) { if (mqttUri != agMqtt.getUri()) {
agMqtt.end(); agMqtt.end();
if (mqttTask != NULL) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
if (agMqtt.begin(mqttUri)) { if (agMqtt.begin(mqttUri)) {
Serial.println("Connect to new mqtt broker success"); Serial.println("Connect to new mqtt broker success");
createMqttTask();
} else { } else {
Serial.println("Connect to new mqtt broker failed"); Serial.println("Connect to new mqtt broker failed");
} }
@ -1418,6 +1438,94 @@ static String getServerSyncData(bool localServer) {
return JSON.stringify(root); return JSON.stringify(root);
} }
static void createMqttTask(void) {
if (mqttTask) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
xTaskCreate(
[](void *param) {
for (;;) {
delay(MQTT_SYNC_INTERVAL);
/** Send data */
if (agMqtt.isConnected()) {
String syncData = getServerSyncData(false);
String topic = "airgradient/readings/" + getDevId();
if (agMqtt.publish(topic.c_str(), syncData.c_str(),
syncData.length())) {
Serial.println("Mqtt sync success");
} else {
Serial.println("Mqtt sync failure");
}
}
}
},
"mqtt-task", 1024 * 3, NULL, 6, &mqttTask);
if (mqttTask == NULL) {
Serial.println("Creat mqttTask failed");
}
}
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) {
Serial.println("Factory reset keep presssed for 8 sec");
uint32_t ledTime = millis();
bool ledOn = true;
ag.statusLed.setOn();
while (ag.button.getState() == ag.button.BUTTON_PRESSED) {
ms = (uint32_t)(millis() - ledTime);
if (ms >= LED_SHORT_BLINK_DELAY) {
ledTime = millis();
ag.statusLed.setToggle();
}
ms = (uint32_t)(millis() - factoryBtnPressTime);
if (ms > 10000) {
ag.statusLed.setOff();
/** Stop MQTT task first */
if (mqttTask) {
vTaskDelete(mqttTask);
mqttTask = NULL;
}
/** Disconnect WIFI */
WiFi.disconnect();
wifiManager.resetSettings();
/** Reset local config */
agServer.defaultReset();
Serial.println("Factory successful");
ledBlinkDelay(LED_LONG_BLINK_DELAY);
ledBlinkDelay(LED_LONG_BLINK_DELAY);
ledBlinkDelay(LED_LONG_BLINK_DELAY);
ESP.restart();
}
}
/** Show current content cause reset ignore */
factoryBtnPressTime = 0;
ag.statusLed.setOff();
}
}
} else {
if (factoryBtnPressTime != 0) {
ag.statusLed.setOff();
}
factoryBtnPressTime = 0;
}
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
int32_t event_id, void *event_data) { int32_t event_id, void *event_data) {
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data;