Add DiyProIndoorV4_2.ino example

This commit is contained in:
Phat Nguyen
2024-06-15 15:40:50 +07:00
parent 227a4f76f7
commit bd237ed95d
14 changed files with 1214 additions and 78 deletions

View File

@ -0,0 +1,785 @@
#include "AgApiClient.h"
#include "AgConfigure.h"
#include "AgSchedule.h"
#include "AgWiFiConnector.h"
#include "LocalServer.h"
#include "OpenMetrics.h"
#include <AirGradient.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */
#define DISP_UPDATE_INTERVAL 2500 /** ms */
#define SERVER_CONFIG_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_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 */
#define FIRMWARE_CHECK_FOR_UPDATE_MS (60 * 60 * 1000) /** ms */
static AirGradient ag(DIY_PRO_INDOOR_V4_2);
static Configuration configuration(Serial);
static AgApiClient apiClient(Serial, configuration);
static Measurements measurements;
static OledDisplay oledDisplay(configuration, measurements, Serial);
static StateMachine stateMachine(oledDisplay, Serial, measurements,
configuration);
static WifiConnector wifiConnector(oledDisplay, Serial, stateMachine,
configuration);
static OpenMetrics openMetrics(measurements, configuration, wifiConnector,
apiClient);
static LocalServer localServer(Serial, openMetrics, measurements, configuration,
wifiConnector);
static int pmFailCount = 0;
static uint32_t factoryBtnPressTime = 0;
static int getCO2FailCount = 0;
static AgFirmwareMode fwMode = FW_MODE_I_8PSL;
static bool ledBarButtonTest = false;
static String fwNewVersion;
static void boardInit(void);
static void failedHandler(String msg);
static void configurationUpdateSchedule(void);
static void appLedHandler(void);
static void appDispHandler(void);
static void oledDisplayLedBarSchedule(void);
static void updateTvoc(void);
static void updatePm(void);
static void sendDataToServer(void);
static void tempHumUpdate(void);
static void co2Update(void);
static void mdnsInit(void);
static void createMqttTask(void);
static void initMqtt(void);
static void factoryConfigReset(void);
static void wdgFeedUpdate(void);
static void ledBarEnabledUpdate(void);
static bool sgp41Init(void);
static void wifiFactoryConfigure(void);
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, oledDisplayLedBarSchedule);
AgSchedule configSchedule(SERVER_CONFIG_SYNC_INTERVAL,
configurationUpdateSchedule);
AgSchedule agApiPostSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, updatePm);
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate);
void setup() {
/** Serial for print debug message */
Serial.begin(115200);
delay(100); /** For bester show log */
/** Print device ID into log */
Serial.println("Serial nr: " + ag.deviceId());
/** Initialize local configure */
configuration.begin();
/** Init I2C */
Wire.begin(ag.getI2cSdaPin(), ag.getI2cSclPin());
delay(1000);
configuration.setAirGradient(&ag);
oledDisplay.setAirGradient(&ag);
stateMachine.setAirGradient(&ag);
wifiConnector.setAirGradient(&ag);
apiClient.setAirGradient(&ag);
openMetrics.setAirGradient(&ag);
localServer.setAirGraident(&ag);
/** Init sensor */
boardInit();
/** Connecting wifi */
bool connectToWifi = false;
if (ag.isOne() || ag.getBoardType() == DIY_PRO_INDOOR_V4_2) {
/** 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) {
Serial.println("Set for offline mode timeout");
break;
}
delay(1);
}
connectToWifi = !configuration.isOfflineMode();
} else {
configuration.setOfflineModeWithoutSave(true);
}
} else {
connectToWifi = true;
}
if (connectToWifi) {
apiClient.begin();
if (wifiConnector.connect()) {
if (wifiConnector.isConnected()) {
mdnsInit();
localServer.begin();
initMqtt();
sendDataToAg();
apiClient.fetchServerConfiguration();
configSchedule.update();
if (apiClient.isFetchConfigureFailed()) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
stateMachine.displayHandle(
AgStateMachineWiFiOkServerOkSensorConfigFailed);
} else {
stateMachine.displayClearAddToDashBoard();
}
}
stateMachine.handleLeds(
AgStateMachineWiFiOkServerOkSensorConfigFailed);
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
} else {
ledBarEnabledUpdate();
}
} else {
if (wifiConnector.isConfigurePorttalTimeout()) {
oledDisplay.showRebooting();
delay(2500);
oledDisplay.setText("", "", "");
ESP.restart();
}
}
}
}
/** 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);
}
/** Show display Warning up */
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
oledDisplay.setText("Warming Up", "Serial Number:", ag.deviceId().c_str());
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
Serial.println("Display brightness: " +
String(configuration.getDisplayBrightness()));
oledDisplay.setBrightness(configuration.getDisplayBrightness());
}
appLedHandler();
appDispHandler();
}
void loop() {
/** Handle schedule */
dispLedSchedule.run();
configSchedule.run();
agApiPostSchedule.run();
if (configuration.hasSensorS8) {
co2Schedule.run();
}
if (configuration.hasSensorPMS) {
pmsSchedule.run();
ag.pms5003.handle();
}
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
if (configuration.hasSensorSHT) {
tempHumSchedule.run();
}
}
if (configuration.hasSensorSGP) {
tvocSchedule.run();
}
/** Auto reset watchdog timer if offline mode or postDataToAirGradient */
if (configuration.isOfflineMode() ||
(configuration.isPostDataToAirGradient() == false)) {
watchdogFeedSchedule.run();
}
/** Check for handle WiFi reconnect */
wifiConnector.handle();
/** factory reset handle */
factoryConfigReset();
/** check that local configura changed then do some action */
configUpdateHandle();
localServer._handle();
if (ag.getBoardType() == DIY_PRO_INDOOR_V4_2) {
ag.sgp41.handle();
}
}
static void co2Update(void) {
int value = ag.s8.getCo2();
if (value >= 0) {
measurements.CO2 = value;
getCO2FailCount = 0;
Serial.printf("CO2 (ppm): %d\r\n", measurements.CO2);
} else {
getCO2FailCount++;
Serial.printf("Get CO2 failed: %d\r\n", getCO2FailCount);
if (getCO2FailCount >= 3) {
measurements.CO2 = -1;
}
}
}
static void mdnsInit(void) {
Serial.println("mDNS init");
if (!MDNS.begin(localServer.getHostname().c_str())) {
Serial.println("Init mDNS failed");
return;
}
MDNS.addService("_airgradient", "_tcp", 80);
MDNS.addServiceTxt("_airgradient", "_tcp", "model",
AgFirmwareModeName(fwMode));
MDNS.addServiceTxt("_airgradient", "_tcp", "serialno", ag.deviceId());
MDNS.addServiceTxt("_airgradient", "_tcp", "fw_ver", ag.getVersion());
MDNS.addServiceTxt("_airgradient", "_tcp", "vendor", "AirGradient");
}
static void createMqttTask(void) {
// if (mqttTask) {
// vTaskDelete(mqttTask);
// mqttTask = NULL;
// Serial.println("Delete old MQTT task");
// }
// Serial.println("Create new MQTT task");
// xTaskCreate(
// [](void *param) {
// for (;;) {
// delay(MQTT_SYNC_INTERVAL);
// /** Send data */
// if (mqttClient.isConnected()) {
// String payload = measurements.toString(
// true, fwMode, wifiConnector.RSSI(), ag, &configuration);
// String topic = "airgradient/readings/" + ag.deviceId();
// if (mqttClient.publish(topic.c_str(), payload.c_str(),
// payload.length())) {
// Serial.println("MQTT sync success");
// } else {
// Serial.println("MQTT sync failure");
// }
// }
// }
// },
// "mqtt-task", 1024 * 4, NULL, 6, &mqttTask);
// if (mqttTask == NULL) {
// Serial.println("Creat mqttTask failed");
// }
}
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");
// }
}
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
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
oledDisplay.setText("Factory reset", "keep pressed", "for 8 sec");
} else {
Serial.println("Factory reset, keep pressed for 8 sec");
}
int count = 7;
while (ag.button.getState() == ag.button.BUTTON_PRESSED) {
delay(1000);
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
String str = "for " + String(count) + " sec";
oledDisplay.setText("Factory reset", "keep pressed", str.c_str());
} 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;
// }
/** Reset WIFI */
WiFi.enableSTA(true); // Incase offline mode
WiFi.disconnect(true, true);
/** Reset local config */
configuration.reset();
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
oledDisplay.setText("Factory reset", "successful", "");
} else {
Serial.println("Factory reset successful");
}
delay(3000);
oledDisplay.setText("", "", "");
ESP.restart();
}
}
/** Show current content cause reset ignore */
factoryBtnPressTime = 0;
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
appDispHandler();
}
}
}
} else {
if (factoryBtnPressTime != 0) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
/** Restore last display content */
appDispHandler();
}
}
factoryBtnPressTime = 0;
}
}
static void wdgFeedUpdate(void) {
ag.watchdog.reset();
Serial.println();
Serial.println("Offline mode or isPostToAirGradient = false: watchdog reset");
Serial.println();
}
static void ledBarEnabledUpdate(void) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
int brightness = configuration.getLedBarBrightness();
Serial.println("LED bar brightness: " + String(brightness));
if ((brightness == 0) || (configuration.getLedBarMode() == LedBarModeOff)) {
ag.ledBar.setEnable(false);
} else {
ag.ledBar.setBrightness(brightness);
ag.ledBar.setEnable(configuration.getLedBarMode() != LedBarModeOff);
}
ag.ledBar.show();
}
}
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;
}
static void wifiFactoryConfigure(void) {
WiFi.begin("airgradient", "cleanair");
oledDisplay.setText("Configure WiFi", "connect to", "\'airgradient\'");
delay(2500);
oledDisplay.setText("Rebooting...", "", "");
delay(2500);
oledDisplay.setText("", "", "");
ESP.restart();
}
static void sendDataToAg() {
/** Change oledDisplay and led state */
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnecting);
}
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnecting);
/** Task handle led connecting animation */
// xTaskCreate(
// [](void *obj) {
// for (;;) {
// // ledSmHandler();
// stateMachine.handleLeds();
// if (stateMachine.getLedState() !=
// AgStateMachineWiFiOkServerConnecting) {
// break;
// }
// delay(LED_BAR_ANIMATION_PERIOD);
// }
// vTaskDelete(NULL);
// },
// "task_led", 2048, NULL, 5, NULL);
delay(1500);
if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected);
}
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnected);
} else {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
stateMachine.displayHandle(AgStateMachineWiFiOkServerConnectFailed);
}
stateMachine.handleLeds(AgStateMachineWiFiOkServerConnectFailed);
}
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
stateMachine.handleLeds(AgStateMachineNormal);
}
void dispSensorNotFound(String ss) {
ss = ss + " not found";
oledDisplay.setText("Sensor init", "Error:", ss.c_str());
delay(2000);
}
static void boardInit(void) {
/** Display init */
oledDisplay.begin();
/** Show boot display */
Serial.println("Firmware Version: " + ag.getVersion());
oledDisplay.setText("AirGradient ONE",
"FW Version: ", ag.getVersion().c_str());
delay(DISPLAY_DELAY_SHOW_CONTENT_MS);
ag.ledBar.begin();
ag.button.begin();
ag.watchdog.begin();
/** Run LED test on start up if button pressed */
if (ag.isOne()) {
oledDisplay.setText("Press now for", "LED test", "");
} else if (ag.getBoardType() == DIY_PRO_INDOOR_V4_2) {
oledDisplay.setText("Press now for", "factory WiFi", "configure");
}
ledBarButtonTest = false;
uint32_t stime = millis();
while (true) {
if (ag.button.getState() == ag.button.BUTTON_PRESSED) {
if (ag.isOne()) {
ledBarButtonTest = true;
stateMachine.executeLedBarPowerUpTest();
break;
}
if (ag.getBoardType() == DIY_PRO_INDOOR_V4_2) {
wifiFactoryConfigure();
}
}
delay(1);
uint32_t ms = (uint32_t)(millis() - stime);
if (ms >= 3000) {
break;
}
delay(1);
}
/** Check for button to reset WiFi connecto to "airgraident" after test LED
* bar */
if (ledBarButtonTest && ag.isOne()) {
if (ag.button.getState() == ag.button.BUTTON_PRESSED) {
wifiFactoryConfigure();
}
}
ledBarEnabledUpdate();
/** Show message init sensor */
oledDisplay.setText("Sensor", "initializing...", "");
/** Init sensor SGP41 */
if (sgp41Init() == false) {
dispSensorNotFound("SGP41");
}
/** Init SHT */
if (ag.sht.begin(Wire) == false) {
Serial.println("SHTx sensor not found");
configuration.hasSensorSHT = false;
dispSensorNotFound("SHT");
}
/** Init S8 CO2 sensor */
if (ag.s8.begin(&Serial) == false) {
Serial.println("CO2 S8 sensor not found");
configuration.hasSensorS8 = false;
dispSensorNotFound("S8");
}
/** Init PMS5003 */
configuration.hasSensorPMS1 = false;
configuration.hasSensorPMS2 = false;
if (ag.pms5003.begin(&Serial) == false) {
Serial.println("PMS sensor not found");
configuration.hasSensorPMS = false;
dispSensorNotFound("PMS");
}
/** 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");
}
}
localServer.setFwMode(FW_MODE_I_8PSL);
}
static void failedHandler(String msg) {
while (true) {
Serial.println(msg);
delay(1000);
}
}
static void configurationUpdateSchedule(void) {
if (apiClient.fetchServerConfiguration()) {
configUpdateHandle();
}
}
static void configUpdateHandle() {
if (configuration.isUpdated() == false) {
return;
}
stateMachine.executeCo2Calibration();
// String mqttUri = configuration.getMqttBrokerUri();
// if (mqttClient.isCurrentUri(mqttUri) == false) {
// mqttClient.end();
// initMqtt();
// }
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);
}
}
}
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
if (configuration.isLedBarBrightnessChanged()) {
if (configuration.getLedBarBrightness() == 0) {
ag.ledBar.setEnable(false);
} else {
if (configuration.getLedBarMode() != LedBarMode::LedBarModeOff) {
ag.ledBar.setEnable(true);
}
ag.ledBar.setBrightness(configuration.getLedBarBrightness());
}
ag.ledBar.show();
}
// if (configuration.isLedBarModeChanged()) {
// 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.setBrightness(configuration.getLedBarBrightness());
// }
// }
// ag.ledBar.show();
// }
if (configuration.isDisplayBrightnessChanged()) {
oledDisplay.setBrightness(configuration.getDisplayBrightness());
}
// stateMachine.executeLedBarTest();
}
appDispHandler();
appLedHandler();
}
static void appLedHandler(void) {
AgStateMachineState state = AgStateMachineNormal;
if (configuration.isOfflineMode() == false) {
if (wifiConnector.isConnected() == false) {
state = AgStateMachineWiFiLost;
} else if (apiClient.isFetchConfigureFailed()) {
state = AgStateMachineSensorConfigFailed;
} else if (apiClient.isPostToServerFailed()) {
state = AgStateMachineServerLost;
}
}
stateMachine.handleLeds(state);
}
static void appDispHandler(void) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
AgStateMachineState state = AgStateMachineNormal;
/** Only show display status on online mode. */
if (configuration.isOfflineMode() == false) {
if (wifiConnector.isConnected() == false) {
state = AgStateMachineWiFiLost;
} else if (apiClient.isFetchConfigureFailed()) {
state = AgStateMachineSensorConfigFailed;
if (apiClient.isNotAvailableOnDashboard()) {
stateMachine.displaySetAddToDashBoard();
} else {
stateMachine.displayClearAddToDashBoard();
}
} else if (apiClient.isPostToServerFailed()) {
state = AgStateMachineServerLost;
}
}
stateMachine.displayHandle(state);
}
}
static void oledDisplayLedBarSchedule(void) {
if (ag.isOne() || (ag.getBoardType() == DIY_PRO_INDOOR_V4_2)) {
if (factoryBtnPressTime == 0) {
appDispHandler();
}
}
appLedHandler();
}
static void updateTvoc(void) {
measurements.TVOC = ag.sgp41.getTvocIndex();
measurements.TVOCRaw = ag.sgp41.getTvocRaw();
measurements.NOx = ag.sgp41.getNoxIndex();
measurements.NOxRaw = ag.sgp41.getNoxRaw();
Serial.println();
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);
}
static void updatePm(void) {
if (ag.pms5003.isFailed() == false) {
measurements.pm01_1 = ag.pms5003.getPm01Ae();
measurements.pm25_1 = ag.pms5003.getPm25Ae();
measurements.pm10_1 = ag.pms5003.getPm10Ae();
measurements.pm03PCount_1 = ag.pms5003.getPm03ParticleCount();
Serial.println();
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);
pmFailCount = 0;
} else {
pmFailCount++;
Serial.printf("PMS read failed: %d\r\n", pmFailCount);
if (pmFailCount >= 3) {
measurements.pm01_1 = -1;
measurements.pm25_1 = -1;
measurements.pm10_1 = -1;
measurements.pm03PCount_1 = -1;
}
}
}
static void sendDataToServer(void) {
/** Ignore send data to server if postToAirGradient disabled */
if (configuration.isPostDataToAirGradient() == false ||
configuration.isOfflineMode()) {
return;
}
String syncData = measurements.toString(false, fwMode, wifiConnector.RSSI(),
&ag, &configuration);
if (apiClient.postToServer(syncData)) {
ag.watchdog.reset();
Serial.println();
Serial.println(
"Online mode and isPostToAirGradient = true: watchdog reset");
Serial.println();
}
measurements.bootCount++;
}
static void tempHumUpdate(void) {
delay(100);
if (ag.sht.measure()) {
measurements.Temperature = ag.sht.getTemperature();
measurements.Humidity = ag.sht.getRelativeHumidity();
Serial.printf("Temperature in C: %0.2f\r\n", measurements.Temperature);
Serial.printf("Relative Humidity: %d\r\n", measurements.Humidity);
Serial.printf("Temperature compensated in C: %0.2f\r\n",
measurements.Temperature);
Serial.printf("Relative Humidity compensated: %d\r\n",
measurements.Humidity);
// Update compensation temperature and humidity for SGP41
if (configuration.hasSensorSGP) {
ag.sgp41.setCompensationTemperatureHumidity(measurements.Temperature,
measurements.Humidity);
}
} else {
Serial.println("SHT read failed");
}
}

View File

@ -0,0 +1,61 @@
#include "LocalServer.h"
LocalServer::LocalServer(Stream &log, OpenMetrics &openMetrics,
Measurements &measure, Configuration &config,
WifiConnector &wifiConnector)
: PrintLog(log, "LocalServer"), openMetrics(openMetrics), measure(measure),
config(config), wifiConnector(wifiConnector), server(80) {}
LocalServer::~LocalServer() {}
bool LocalServer::begin(void) {
server.on("/measures/current", HTTP_GET, [this]() { _GET_measure(); });
server.on(openMetrics.getApi(), HTTP_GET, [this]() { _GET_metrics(); });
server.on("/config", HTTP_GET, [this]() { _GET_config(); });
server.on("/config", HTTP_PUT, [this]() { _PUT_config(); });
server.begin();
logInfo("Init: " + getHostname() + ".local");
return true;
}
void LocalServer::setAirGraident(AirGradient *ag) { this->ag = ag; }
String LocalServer::getHostname(void) {
return "airgradient_" + ag->deviceId();
}
void LocalServer::_handle(void) { server.handleClient(); }
void LocalServer::_GET_config(void) {
if(ag->isOne()) {
server.send(200, "application/json", config.toString());
} else {
server.send(200, "application/json", config.toString(fwMode));
}
}
void LocalServer::_PUT_config(void) {
String data = server.arg(0);
String response = "";
int statusCode = 400; // Status code for data invalid
if (config.parse(data, true)) {
statusCode = 200;
response = "Success";
} else {
response = config.getFailedMesage();
}
server.send(statusCode, "text/plain", response);
}
void LocalServer::_GET_metrics(void) {
server.send(200, openMetrics.getApiContentType(), openMetrics.getPayload());
}
void LocalServer::_GET_measure(void) {
server.send(
200, "application/json",
measure.toString(true, fwMode, wifiConnector.RSSI(), ag, &config));
}
void LocalServer::setFwMode(AgFirmwareMode fwMode) { this->fwMode = fwMode; }

View File

@ -0,0 +1,38 @@
#ifndef _LOCAL_SERVER_H_
#define _LOCAL_SERVER_H_
#include "AgConfigure.h"
#include "AgValue.h"
#include "AirGradient.h"
#include "OpenMetrics.h"
#include "AgWiFiConnector.h"
#include <Arduino.h>
#include <ESP8266WebServer.h>
class LocalServer : public PrintLog {
private:
AirGradient *ag;
OpenMetrics &openMetrics;
Measurements &measure;
Configuration &config;
WifiConnector &wifiConnector;
ESP8266WebServer server;
AgFirmwareMode fwMode;
public:
LocalServer(Stream &log, OpenMetrics &openMetrics, Measurements &measure,
Configuration &config, WifiConnector& wifiConnector);
~LocalServer();
bool begin(void);
void setAirGraident(AirGradient *ag);
String getHostname(void);
void setFwMode(AgFirmwareMode fwMode);
void _handle(void);
void _GET_config(void);
void _PUT_config(void);
void _GET_metrics(void);
void _GET_measure(void);
};
#endif /** _LOCAL_SERVER_H_ */

View File

@ -0,0 +1,186 @@
#include "OpenMetrics.h"
OpenMetrics::OpenMetrics(Measurements &measure, Configuration &config,
WifiConnector &wifiConnector, AgApiClient &apiClient)
: measure(measure), config(config), wifiConnector(wifiConnector),
apiClient(apiClient) {}
OpenMetrics::~OpenMetrics() {}
void OpenMetrics::setAirGradient(AirGradient *ag) { this->ag = ag; }
const char *OpenMetrics::getApiContentType(void) {
return "application/openmetrics-text; version=1.0.0; charset=utf-8";
}
const char *OpenMetrics::getApi(void) { return "/metrics"; }
String OpenMetrics::getPayload(void) {
String response;
String current_metric_name;
const auto add_metric = [&](const String &name, const String &help,
const String &type, const String &unit = "") {
current_metric_name = "airgradient_" + name;
if (!unit.isEmpty())
current_metric_name += "_" + unit;
response += "# HELP " + current_metric_name + " " + help + "\n";
response += "# TYPE " + current_metric_name + " " + type + "\n";
if (!unit.isEmpty())
response += "# UNIT " + current_metric_name + " " + unit + "\n";
};
const auto add_metric_point = [&](const String &labels, const String &value) {
response += current_metric_name + "{" + labels + "} " + value + "\n";
};
add_metric("info", "AirGradient device information", "info");
add_metric_point("airgradient_serial_number=\"" + ag->deviceId() +
"\",airgradient_device_type=\"" + ag->getBoardName() +
"\",airgradient_library_version=\"" + ag->getVersion() +
"\"",
"1");
add_metric("config_ok",
"1 if the AirGradient device was able to successfully fetch its "
"configuration from the server",
"gauge");
add_metric_point("", apiClient.isFetchConfigureFailed() ? "0" : "1");
add_metric(
"post_ok",
"1 if the AirGradient device was able to successfully send to the server",
"gauge");
add_metric_point("", apiClient.isPostToServerFailed() ? "0" : "1");
add_metric(
"wifi_rssi",
"WiFi signal strength from the AirGradient device perspective, in dBm",
"gauge", "dbm");
add_metric_point("", String(wifiConnector.RSSI()));
if (config.hasSensorS8 && measure.CO2 >= 0) {
add_metric("co2",
"Carbon dioxide concentration as measured by the AirGradient S8 "
"sensor, in parts per million",
"gauge", "ppm");
add_metric_point("", String(measure.CO2));
}
float _temp = -1001;
float _hum = -1;
int pm01 = -1;
int pm25 = -1;
int pm10 = -1;
int pm03PCount = -1;
int atmpCompensated = -1;
int ahumCompensated = -1;
if (config.hasSensorSHT) {
_temp = measure.Temperature;
_hum = measure.Humidity;
atmpCompensated = _temp;
ahumCompensated = _hum;
}
if (config.hasSensorPMS) {
pm01 = measure.pm01_1;
pm25 = measure.pm25_1;
pm10 = measure.pm10_1;
pm03PCount = measure.pm03PCount_1;
}
if (config.hasSensorPMS) {
if (pm01 >= 0) {
add_metric("pm1",
"PM1.0 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm01));
}
if (pm25 >= 0) {
add_metric("pm2d5",
"PM2.5 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm25));
}
if (pm10 >= 0) {
add_metric("pm10",
"PM10 concentration as measured by the AirGradient PMS "
"sensor, in micrograms per cubic meter",
"gauge", "ugm3");
add_metric_point("", String(pm10));
}
if (pm03PCount >= 0) {
add_metric("pm0d3",
"PM0.3 concentration as measured by the AirGradient PMS "
"sensor, in number of particules per 100 milliliters",
"gauge", "p100ml");
add_metric_point("", String(pm03PCount));
}
}
if (config.hasSensorSGP) {
if (measure.TVOC >= 0) {
add_metric("tvoc_index",
"The processed Total Volatile Organic Compounds (TVOC) index "
"as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOC));
}
if (measure.TVOCRaw >= 0) {
add_metric("tvoc_raw",
"The raw input value to the Total Volatile Organic Compounds "
"(TVOC) index as measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.TVOCRaw));
}
if (measure.NOx >= 0) {
add_metric("nox_index",
"The processed Nitrous Oxide (NOx) index as measured by the "
"AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOx));
}
if (measure.NOxRaw >= 0) {
add_metric("nox_raw",
"The raw input value to the Nitrous Oxide (NOx) index as "
"measured by the AirGradient SGP sensor",
"gauge");
add_metric_point("", String(measure.NOxRaw));
}
}
if (_temp > -1001) {
add_metric(
"temperature",
"The ambient temperature as measured by the AirGradient SHT / PMS "
"sensor, in degrees Celsius",
"gauge", "celsius");
add_metric_point("", String(_temp));
}
if (atmpCompensated > -1001) {
add_metric("temperature_compensated",
"The compensated ambient temperature as measured by the "
"AirGradient SHT / PMS "
"sensor, in degrees Celsius",
"gauge", "celsius");
add_metric_point("", String(atmpCompensated));
}
if (_hum >= 0) {
add_metric(
"humidity",
"The relative humidity as measured by the AirGradient SHT sensor",
"gauge", "percent");
add_metric_point("", String(_hum));
}
if (ahumCompensated >= 0) {
add_metric("humidity_compensated",
"The compensated relative humidity as measured by the "
"AirGradient SHT / PMS sensor",
"gauge", "percent");
add_metric_point("", String(ahumCompensated));
}
response += "# EOF\n";
return response;
}

View File

@ -0,0 +1,28 @@
#ifndef _OPEN_METRICS_H_
#define _OPEN_METRICS_H_
#include "AgConfigure.h"
#include "AgValue.h"
#include "AgWiFiConnector.h"
#include "AirGradient.h"
#include "AgApiClient.h"
class OpenMetrics {
private:
AirGradient *ag;
Measurements &measure;
Configuration &config;
WifiConnector &wifiConnector;
AgApiClient &apiClient;
public:
OpenMetrics(Measurements &measure, Configuration &conig,
WifiConnector &wifiConnector, AgApiClient& apiClient);
~OpenMetrics();
void setAirGradient(AirGradient *ag);
const char *getApiContentType(void);
const char* getApi(void);
String getPayload(void);
};
#endif /** _OPEN_METRICS_H_ */

View File

@ -43,7 +43,7 @@ JSON_PROP_DEF(ledBarTestRequested);
JSON_PROP_DEF(offlineMode); JSON_PROP_DEF(offlineMode);
#define jprop_model_default "" #define jprop_model_default ""
#define jprop_country_default "" #define jprop_country_default "TH"
#define jprop_pmStandard_default getPMStandardString(false) #define jprop_pmStandard_default getPMStandardString(false)
#define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2) #define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2)
#define jprop_abcDays_default 8 #define jprop_abcDays_default 8
@ -614,15 +614,18 @@ bool Configuration::parse(String data, bool isLocal) {
} }
} }
if (JSON.typeof_(root["targetFirmware"]) == "string") { if (ag->getBoardType() == ONE_INDOOR ||
String newVer = root["targetFirmware"]; ag->getBoardType() == OPEN_AIR_OUTDOOR) {
String curVer = String(GIT_VERSION); if (JSON.typeof_(root["targetFirmware"]) == "string") {
if (curVer != newVer) { String newVer = root["targetFirmware"];
logInfo("Detected new firmware version: " + newVer); String curVer = String(GIT_VERSION);
otaNewFirmwareVersion = newVer; if (curVer != newVer) {
udpated = true; logInfo("Detected new firmware version: " + newVer);
} else { otaNewFirmwareVersion = newVer;
otaNewFirmwareVersion = String(""); udpated = true;
} else {
otaNewFirmwareVersion = String("");
}
} }
} }

View File

@ -42,6 +42,7 @@ public:
bool hasSensorS8 = true; bool hasSensorS8 = true;
bool hasSensorPMS1 = true; bool hasSensorPMS1 = true;
bool hasSensorPMS2 = true; bool hasSensorPMS2 = true;
bool hasSensorPMS = true;
bool hasSensorSGP = true; bool hasSensorSGP = true;
bool hasSensorSHT = true; bool hasSensorSHT = true;

View File

@ -224,7 +224,7 @@ void StateMachine::co2Calibration(void) {
/** Count down to 0 then start */ /** Count down to 0 then start */
for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) { for (int i = 0; i < SENSOR_CO2_CALIB_COUNTDOWN_MAX; i++) {
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
String str = String str =
"after " + String(SENSOR_CO2_CALIB_COUNTDOWN_MAX - i) + " sec"; "after " + String(SENSOR_CO2_CALIB_COUNTDOWN_MAX - i) + " sec";
disp.setText("Start CO2 calib", str.c_str(), ""); disp.setText("Start CO2 calib", str.c_str(), "");
@ -236,13 +236,13 @@ void StateMachine::co2Calibration(void) {
} }
if (ag->s8.setBaselineCalibration()) { if (ag->s8.setBaselineCalibration()) {
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
disp.setText("Calibration", "success", ""); disp.setText("Calibration", "success", "");
} else { } else {
logInfo("CO2 Calibration: success"); logInfo("CO2 Calibration: success");
} }
delay(1000); delay(1000);
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
disp.setText("Wait for", "calib finish", "..."); disp.setText("Wait for", "calib finish", "...");
} else { } else {
logInfo("CO2 Calibration: Wait for calibration finish..."); logInfo("CO2 Calibration: Wait for calibration finish...");
@ -254,7 +254,7 @@ void StateMachine::co2Calibration(void) {
delay(1000); delay(1000);
count++; count++;
} }
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
String str = "after " + String(count); String str = "after " + String(count);
disp.setText("Calib finish", str.c_str(), "sec"); disp.setText("Calib finish", str.c_str(), "sec");
} else { } else {
@ -262,7 +262,7 @@ void StateMachine::co2Calibration(void) {
} }
delay(2000); delay(2000);
} else { } else {
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
disp.setText("Calibration", "failure!!!", ""); disp.setText("Calibration", "failure!!!", "");
} else { } else {
logInfo("CO2 Calibration: failure!!!"); logInfo("CO2 Calibration: failure!!!");
@ -399,7 +399,7 @@ StateMachine::~StateMachine() {}
*/ */
void StateMachine::displayHandle(AgStateMachineState state) { void StateMachine::displayHandle(AgStateMachineState state) {
// Ignore handle if not ONE_INDOOR board // Ignore handle if not ONE_INDOOR board
if (!ag->isOne()) { if (!(ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2))) {
if (state == AgStateMachineCo2Calibration) { if (state == AgStateMachineCo2Calibration) {
co2Calibration(); co2Calibration();
} }

View File

@ -19,8 +19,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
} }
} }
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
if (config->hasSensorPMS1) { if (config->hasSensorPMS1 || config->hasSensorPMS) {
if (this->pm01_1 >= 0) { if (this->pm01_1 >= 0) {
root["pm01"] = this->pm01_1; root["pm01"] = this->pm01_1;
} }

View File

@ -13,7 +13,6 @@
*/ */
void WifiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; } void WifiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; }
#ifdef ESP32
/** /**
* @brief Construct a new Ag Wi Fi Connector:: Ag Wi Fi Connector object * @brief Construct a new Ag Wi Fi Connector:: Ag Wi Fi Connector object
* *
@ -24,9 +23,10 @@ void WifiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; }
WifiConnector::WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm, WifiConnector::WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm,
Configuration &config) Configuration &config)
: PrintLog(log, "WifiConnector"), disp(disp), sm(sm), config(config) {} : PrintLog(log, "WifiConnector"), disp(disp), sm(sm), config(config) {}
#else
WifiConnector::WifiConnector(Stream &log) : PrintLog(log, "WiFiConnector") {} // #ifdef ESP8266
#endif // WifiConnector::WifiConnector(Stream &log) : PrintLog(log, "WiFiConnector") {}
// #endif
WifiConnector::~WifiConnector() {} WifiConnector::~WifiConnector() {}
@ -49,20 +49,18 @@ bool WifiConnector::connect(void) {
WIFI()->setConnectTimeout(15); WIFI()->setConnectTimeout(15);
WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX); WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
#ifdef ESP32
WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); }); WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); });
WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); }); WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); });
WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); }); WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); });
WIFI()->setConfigPortalTimeoutCallback([this](){}); WIFI()->setConfigPortalTimeoutCallback([this]() {});
if (ag->isOne()) { if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
disp.setText("Connecting to", "WiFi", "..."); disp.setText("Connecting to", "WiFi", "...");
} else { } else {
logInfo("Connecting to WiFi..."); logInfo("Connecting to WiFi...");
} }
ssid = "airgradient-" + ag->deviceId(); ssid = "airgradient-" + ag->deviceId();
#else
ssid = "AG-" + String(ESP.getChipId(), HEX); // ssid = "AG-" + String(ESP.getChipId(), HEX);
#endif
WIFI()->setConfigPortalTimeout(WIFI_CONNECT_COUNTDOWN_MAX); WIFI()->setConfigPortalTimeout(WIFI_CONNECT_COUNTDOWN_MAX);
WiFiManagerParameter postToAg("chbPostToAg", WiFiManagerParameter postToAg("chbPostToAg",
@ -78,6 +76,8 @@ bool WifiConnector::connect(void) {
WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT); WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT);
logInfo("Wait for configure portal");
#ifdef ESP32 #ifdef ESP32
// Task handle WiFi connection. // Task handle WiFi connection.
xTaskCreate( xTaskCreate(
@ -139,10 +139,14 @@ bool WifiConnector::connect(void) {
delay(1); // avoid watchdog timer reset. delay(1); // avoid watchdog timer reset.
} }
#else
_wifiProcess();
#endif
/** Show display wifi connect result failed */ /** Show display wifi connect result failed */
if (WiFi.isConnected() == false) { if (WiFi.isConnected() == false) {
sm.handleLeds(AgStateMachineWiFiManagerConnectFailed); sm.handleLeds(AgStateMachineWiFiManagerConnectFailed);
if (ag->isOne()) { if (ag->isOne() || ag->getBoardType() == DIY_PRO_INDOOR_V4_2) {
sm.displayHandle(AgStateMachineWiFiManagerConnectFailed); sm.displayHandle(AgStateMachineWiFiManagerConnectFailed);
} }
delay(6000); delay(6000);
@ -160,9 +164,7 @@ bool WifiConnector::connect(void) {
} }
hasPortalConfig = false; hasPortalConfig = false;
} }
#else
_wifiProcess();
#endif
return true; return true;
} }
@ -179,20 +181,20 @@ void WifiConnector::disconnect(void) {
#ifdef ESP32 #ifdef ESP32
#else #else
void WifiConnector::displayShowText(String ln1, String ln2, String ln3) { // void WifiConnector::displayShowText(String ln1, String ln2, String ln3) {
char buf[9]; // char buf[9];
ag->display.clear(); // ag->display.clear();
ag->display.setCursor(1, 1); // ag->display.setCursor(1, 1);
ag->display.setText(ln1); // ag->display.setText(ln1);
ag->display.setCursor(1, 19); // ag->display.setCursor(1, 19);
ag->display.setText(ln2); // ag->display.setText(ln2);
ag->display.setCursor(1, 37); // ag->display.setCursor(1, 37);
ag->display.setText(ln3); // ag->display.setText(ln3);
ag->display.show(); // ag->display.show();
delay(100); // delay(100);
} // }
#endif #endif
/** /**
@ -205,7 +207,6 @@ bool WifiConnector::wifiClientConnected(void) {
return WiFi.softAPgetStationNum() ? true : false; return WiFi.softAPgetStationNum() ? true : false;
} }
#ifdef ESP32
/** /**
* @brief Handle WiFiManage softAP setup completed callback * @brief Handle WiFiManage softAP setup completed callback
* *
@ -247,7 +248,7 @@ bool WifiConnector::_wifiConfigPortalActive(void) {
return WIFI()->getConfigPortalActive(); return WIFI()->getConfigPortalActive();
} }
void WifiConnector::_wifiTimeoutCallback(void) { connectorTimeout = true; } void WifiConnector::_wifiTimeoutCallback(void) { connectorTimeout = true; }
#endif
/** /**
* @brief Process WiFiManager connection * @brief Process WiFiManager connection
* *
@ -256,34 +257,66 @@ void WifiConnector::_wifiProcess() {
#ifdef ESP32 #ifdef ESP32
WIFI()->process(); WIFI()->process();
#else #else
int count = WIFI_CONNECT_COUNTDOWN_MAX; /** Wait for WiFi connect and show LED, display status */
displayShowText(String(WIFI_CONNECT_COUNTDOWN_MAX) + " sec", "SSID:", ssid); uint32_t dispPeriod = millis();
uint32_t ledPeriod = millis();
bool clientConnectChanged = false;
AgStateMachineState stateOld = sm.getDisplayState();
while (WIFI()->getConfigPortalActive()) { while (WIFI()->getConfigPortalActive()) {
WIFI()->process(); WIFI()->process();
uint32_t lastTime = millis(); if (WiFi.isConnected() == false) {
uint32_t ms = (uint32_t)(millis() - lastTime); /** Display countdown */
if (ms >= 1000) { uint32_t ms;
lastTime = millis(); if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) {
ms = (uint32_t)(millis() - dispPeriod);
if (ms >= 1000) {
dispPeriod = millis();
sm.displayHandle();
logInfo("displayHandle state: " + String(sm.getDisplayState()));
} else {
if (stateOld != sm.getDisplayState()) {
stateOld = sm.getDisplayState();
sm.displayHandle();
}
}
}
displayShowText(String(count) + " sec", "SSID:", ssid); /** LED animations */
ms = (uint32_t)(millis() - ledPeriod);
if (ms >= 100) {
ledPeriod = millis();
sm.handleLeds();
}
count--; /** Check for client connect to change led color */
bool clientConnected = wifiClientConnected();
// Timeout if (clientConnected != clientConnectChanged) {
if (count == 0) { clientConnectChanged = clientConnected;
break; if (clientConnectChanged) {
sm.handleLeds(AgStateMachineWiFiManagerPortalActive);
} else {
sm.ledAnimationInit();
sm.handleLeds(AgStateMachineWiFiManagerMode);
if (ag->isOne()) {
sm.displayHandle(AgStateMachineWiFiManagerMode);
}
}
} }
} }
delay(1);
} }
if (!WiFi.isConnected()) { // TODO This is for basic
displayShowText("Booting", "offline", "mode"); // if (!WiFi.isConnected()) {
Serial.println("failed to connect and hit timeout"); // disp.setText("Booting", "offline", "mode");
delay(2500); // Serial.println("failed to connect and hit timeout");
} else { // delay(2500);
hasConfig = true; // } else {
} // hasConfig = true;
// }
#endif #endif
} }
@ -344,7 +377,7 @@ String WifiConnector::localIpStr(void) { return WiFi.localIP().toString(); }
/** /**
* @brief Get status that wifi has configurated * @brief Get status that wifi has configurated
* *
* @return true Configurated * @return true Configurated
* @return false Not Configurated * @return false Not Configurated
*/ */
@ -357,8 +390,8 @@ bool WifiConnector::hasConfigurated(void) {
/** /**
* @brief Get WiFi connection porttal timeout. * @brief Get WiFi connection porttal timeout.
* *
* @return true * @return true
* @return false * @return false
*/ */
bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; } bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; }

View File

@ -12,13 +12,10 @@
class WifiConnector : public PrintLog { class WifiConnector : public PrintLog {
private: private:
AirGradient *ag; AirGradient *ag;
#ifdef ESP32
OledDisplay &disp; OledDisplay &disp;
StateMachine &sm; StateMachine &sm;
Configuration &config; Configuration &config;
#else
void displayShowText(String ln1, String ln2, String ln3);
#endif
String ssid; String ssid;
void *wifi = NULL; void *wifi = NULL;
bool hasConfig; bool hasConfig;
@ -30,23 +27,21 @@ private:
public: public:
void setAirGradient(AirGradient *ag); void setAirGradient(AirGradient *ag);
#ifdef ESP32
WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm, Configuration& config); WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm, Configuration& config);
#else #ifdef ESP8266
WifiConnector(Stream &log); // WifiConnector(Stream &log);
#endif #endif
~WifiConnector(); ~WifiConnector();
bool connect(void); bool connect(void);
void disconnect(void); void disconnect(void);
void handle(void); void handle(void);
#ifdef ESP32
void _wifiApCallback(void); void _wifiApCallback(void);
void _wifiSaveConfig(void); void _wifiSaveConfig(void);
void _wifiSaveParamCallback(void); void _wifiSaveParamCallback(void);
bool _wifiConfigPortalActive(void); bool _wifiConfigPortalActive(void);
void _wifiTimeoutCallback(void); void _wifiTimeoutCallback(void);
#endif
void _wifiProcess(); void _wifiProcess();
bool isConnected(void); bool isConnected(void);
void reset(void); void reset(void);

View File

@ -14,6 +14,8 @@ const char *AgFirmwareModeName(AgFirmwareMode mode) {
return "0-1PS"; return "0-1PS";
case FW_MODE_O_1P: case FW_MODE_O_1P:
return "O-1P"; return "O-1P";
case FW_MODE_I_8PSL:
return "I-8PSL";
default: default:
break; break;
} }

View File

@ -101,6 +101,7 @@ enum AgFirmwareMode {
FW_MODE_O_1PP, /** PMS5003T_1, PMS5003T_2 */ FW_MODE_O_1PP, /** PMS5003T_1, PMS5003T_2 */
FW_MODE_O_1PS, /** PMS5003T, S8 */ FW_MODE_O_1PS, /** PMS5003T, S8 */
FW_MODE_O_1P, /** PMS5003T */ FW_MODE_O_1P, /** PMS5003T */
FW_MODE_I_8PSL, /** DIY_PRO 4.2 */
}; };
const char *AgFirmwareModeName(AgFirmwareMode mode); const char *AgFirmwareModeName(AgFirmwareMode mode);

View File

@ -116,6 +116,9 @@ void LedBar::setColor(uint8_t red, uint8_t green, uint8_t blue) {
*/ */
void LedBar::show(void) { void LedBar::show(void) {
// Ignore update the LED if LED bar disabled // Ignore update the LED if LED bar disabled
if(this->isBegin() == false) {
return;
}
if (enabled == false) { if (enabled == false) {
return; return;
} }