diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino new file mode 100644 index 0000000..20fe4a7 --- /dev/null +++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino @@ -0,0 +1,785 @@ +#include "AgApiClient.h" +#include "AgConfigure.h" +#include "AgSchedule.h" +#include "AgWiFiConnector.h" +#include "LocalServer.h" +#include "OpenMetrics.h" +#include +#include +#include +#include +#include + +#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"); + } +} diff --git a/examples/DiyProIndoorV4_2/LocalServer.cpp b/examples/DiyProIndoorV4_2/LocalServer.cpp new file mode 100644 index 0000000..8970ece --- /dev/null +++ b/examples/DiyProIndoorV4_2/LocalServer.cpp @@ -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; } diff --git a/examples/DiyProIndoorV4_2/LocalServer.h b/examples/DiyProIndoorV4_2/LocalServer.h new file mode 100644 index 0000000..1a943b8 --- /dev/null +++ b/examples/DiyProIndoorV4_2/LocalServer.h @@ -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 +#include + +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_ */ diff --git a/examples/DiyProIndoorV4_2/OpenMetrics.cpp b/examples/DiyProIndoorV4_2/OpenMetrics.cpp new file mode 100644 index 0000000..e11ba46 --- /dev/null +++ b/examples/DiyProIndoorV4_2/OpenMetrics.cpp @@ -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; +} diff --git a/examples/DiyProIndoorV4_2/OpenMetrics.h b/examples/DiyProIndoorV4_2/OpenMetrics.h new file mode 100644 index 0000000..ed890f5 --- /dev/null +++ b/examples/DiyProIndoorV4_2/OpenMetrics.h @@ -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_ */ diff --git a/src/AgConfigure.cpp b/src/AgConfigure.cpp index 0173edb..032ddca 100644 --- a/src/AgConfigure.cpp +++ b/src/AgConfigure.cpp @@ -43,7 +43,7 @@ JSON_PROP_DEF(ledBarTestRequested); JSON_PROP_DEF(offlineMode); #define jprop_model_default "" -#define jprop_country_default "" +#define jprop_country_default "TH" #define jprop_pmStandard_default getPMStandardString(false) #define jprop_ledBarMode_default getLedBarModeName(LedBarMode::LedBarModeCO2) #define jprop_abcDays_default 8 @@ -614,15 +614,18 @@ bool Configuration::parse(String data, bool isLocal) { } } - if (JSON.typeof_(root["targetFirmware"]) == "string") { - String newVer = root["targetFirmware"]; - String curVer = String(GIT_VERSION); - if (curVer != newVer) { - logInfo("Detected new firmware version: " + newVer); - otaNewFirmwareVersion = newVer; - udpated = true; - } else { - otaNewFirmwareVersion = String(""); + if (ag->getBoardType() == ONE_INDOOR || + ag->getBoardType() == OPEN_AIR_OUTDOOR) { + if (JSON.typeof_(root["targetFirmware"]) == "string") { + String newVer = root["targetFirmware"]; + String curVer = String(GIT_VERSION); + if (curVer != newVer) { + logInfo("Detected new firmware version: " + newVer); + otaNewFirmwareVersion = newVer; + udpated = true; + } else { + otaNewFirmwareVersion = String(""); + } } } diff --git a/src/AgConfigure.h b/src/AgConfigure.h index 24473ec..a4aaa1b 100644 --- a/src/AgConfigure.h +++ b/src/AgConfigure.h @@ -42,6 +42,7 @@ public: bool hasSensorS8 = true; bool hasSensorPMS1 = true; bool hasSensorPMS2 = true; + bool hasSensorPMS = true; bool hasSensorSGP = true; bool hasSensorSHT = true; diff --git a/src/AgStateMachine.cpp b/src/AgStateMachine.cpp index 38e2d3e..e74da9f 100644 --- a/src/AgStateMachine.cpp +++ b/src/AgStateMachine.cpp @@ -224,7 +224,7 @@ void StateMachine::co2Calibration(void) { /** Count down to 0 then start */ 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 = "after " + String(SENSOR_CO2_CALIB_COUNTDOWN_MAX - i) + " sec"; disp.setText("Start CO2 calib", str.c_str(), ""); @@ -236,13 +236,13 @@ void StateMachine::co2Calibration(void) { } if (ag->s8.setBaselineCalibration()) { - if (ag->isOne()) { + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { disp.setText("Calibration", "success", ""); } else { logInfo("CO2 Calibration: success"); } delay(1000); - if (ag->isOne()) { + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { disp.setText("Wait for", "calib finish", "..."); } else { logInfo("CO2 Calibration: Wait for calibration finish..."); @@ -254,7 +254,7 @@ void StateMachine::co2Calibration(void) { delay(1000); count++; } - if (ag->isOne()) { + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { String str = "after " + String(count); disp.setText("Calib finish", str.c_str(), "sec"); } else { @@ -262,7 +262,7 @@ void StateMachine::co2Calibration(void) { } delay(2000); } else { - if (ag->isOne()) { + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { disp.setText("Calibration", "failure!!!", ""); } else { logInfo("CO2 Calibration: failure!!!"); @@ -399,7 +399,7 @@ StateMachine::~StateMachine() {} */ void StateMachine::displayHandle(AgStateMachineState state) { // Ignore handle if not ONE_INDOOR board - if (!ag->isOne()) { + if (!(ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2))) { if (state == AgStateMachineCo2Calibration) { co2Calibration(); } diff --git a/src/AgValue.cpp b/src/AgValue.cpp index c3bcc85..e721938 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -19,8 +19,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } - if (ag->isOne()) { - if (config->hasSensorPMS1) { + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { + if (config->hasSensorPMS1 || config->hasSensorPMS) { if (this->pm01_1 >= 0) { root["pm01"] = this->pm01_1; } diff --git a/src/AgWiFiConnector.cpp b/src/AgWiFiConnector.cpp index f71a9cd..b4a17f4 100644 --- a/src/AgWiFiConnector.cpp +++ b/src/AgWiFiConnector.cpp @@ -13,7 +13,6 @@ */ void WifiConnector::setAirGradient(AirGradient *ag) { this->ag = ag; } -#ifdef ESP32 /** * @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, Configuration &config) : PrintLog(log, "WifiConnector"), disp(disp), sm(sm), config(config) {} -#else -WifiConnector::WifiConnector(Stream &log) : PrintLog(log, "WiFiConnector") {} -#endif + +// #ifdef ESP8266 +// WifiConnector::WifiConnector(Stream &log) : PrintLog(log, "WiFiConnector") {} +// #endif WifiConnector::~WifiConnector() {} @@ -49,20 +49,18 @@ bool WifiConnector::connect(void) { WIFI()->setConnectTimeout(15); WIFI()->setTimeout(WIFI_CONNECT_COUNTDOWN_MAX); -#ifdef ESP32 WIFI()->setAPCallback([this](WiFiManager *obj) { _wifiApCallback(); }); WIFI()->setSaveConfigCallback([this]() { _wifiSaveConfig(); }); WIFI()->setSaveParamsCallback([this]() { _wifiSaveParamCallback(); }); - WIFI()->setConfigPortalTimeoutCallback([this](){}); - if (ag->isOne()) { + WIFI()->setConfigPortalTimeoutCallback([this]() {}); + if (ag->isOne() || (ag->getBoardType() == DIY_PRO_INDOOR_V4_2)) { disp.setText("Connecting to", "WiFi", "..."); } else { logInfo("Connecting to WiFi..."); } ssid = "airgradient-" + ag->deviceId(); -#else - ssid = "AG-" + String(ESP.getChipId(), HEX); -#endif + + // ssid = "AG-" + String(ESP.getChipId(), HEX); WIFI()->setConfigPortalTimeout(WIFI_CONNECT_COUNTDOWN_MAX); WiFiManagerParameter postToAg("chbPostToAg", @@ -78,6 +76,8 @@ bool WifiConnector::connect(void) { WIFI()->autoConnect(ssid.c_str(), WIFI_HOTSPOT_PASSWORD_DEFAULT); + logInfo("Wait for configure portal"); + #ifdef ESP32 // Task handle WiFi connection. xTaskCreate( @@ -139,10 +139,14 @@ bool WifiConnector::connect(void) { delay(1); // avoid watchdog timer reset. } +#else + _wifiProcess(); +#endif + /** Show display wifi connect result failed */ if (WiFi.isConnected() == false) { sm.handleLeds(AgStateMachineWiFiManagerConnectFailed); - if (ag->isOne()) { + if (ag->isOne() || ag->getBoardType() == DIY_PRO_INDOOR_V4_2) { sm.displayHandle(AgStateMachineWiFiManagerConnectFailed); } delay(6000); @@ -160,9 +164,7 @@ bool WifiConnector::connect(void) { } hasPortalConfig = false; } -#else - _wifiProcess(); -#endif + return true; } @@ -179,20 +181,20 @@ void WifiConnector::disconnect(void) { #ifdef ESP32 #else -void WifiConnector::displayShowText(String ln1, String ln2, String ln3) { - char buf[9]; - ag->display.clear(); +// void WifiConnector::displayShowText(String ln1, String ln2, String ln3) { +// char buf[9]; +// ag->display.clear(); - ag->display.setCursor(1, 1); - ag->display.setText(ln1); - ag->display.setCursor(1, 19); - ag->display.setText(ln2); - ag->display.setCursor(1, 37); - ag->display.setText(ln3); +// ag->display.setCursor(1, 1); +// ag->display.setText(ln1); +// ag->display.setCursor(1, 19); +// ag->display.setText(ln2); +// ag->display.setCursor(1, 37); +// ag->display.setText(ln3); - ag->display.show(); - delay(100); -} +// ag->display.show(); +// delay(100); +// } #endif /** @@ -205,7 +207,6 @@ bool WifiConnector::wifiClientConnected(void) { return WiFi.softAPgetStationNum() ? true : false; } -#ifdef ESP32 /** * @brief Handle WiFiManage softAP setup completed callback * @@ -247,7 +248,7 @@ bool WifiConnector::_wifiConfigPortalActive(void) { return WIFI()->getConfigPortalActive(); } void WifiConnector::_wifiTimeoutCallback(void) { connectorTimeout = true; } -#endif + /** * @brief Process WiFiManager connection * @@ -256,34 +257,66 @@ void WifiConnector::_wifiProcess() { #ifdef ESP32 WIFI()->process(); #else - int count = WIFI_CONNECT_COUNTDOWN_MAX; - displayShowText(String(WIFI_CONNECT_COUNTDOWN_MAX) + " sec", "SSID:", ssid); + /** Wait for WiFi connect and show LED, display status */ + uint32_t dispPeriod = millis(); + uint32_t ledPeriod = millis(); + bool clientConnectChanged = false; + AgStateMachineState stateOld = sm.getDisplayState(); + while (WIFI()->getConfigPortalActive()) { WIFI()->process(); - uint32_t lastTime = millis(); - uint32_t ms = (uint32_t)(millis() - lastTime); - if (ms >= 1000) { - lastTime = millis(); + if (WiFi.isConnected() == false) { + /** Display countdown */ + uint32_t ms; + 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--; - - // Timeout - if (count == 0) { - break; + /** Check for client connect to change led color */ + bool clientConnected = wifiClientConnected(); + if (clientConnected != clientConnectChanged) { + clientConnectChanged = clientConnected; + if (clientConnectChanged) { + sm.handleLeds(AgStateMachineWiFiManagerPortalActive); + } else { + sm.ledAnimationInit(); + sm.handleLeds(AgStateMachineWiFiManagerMode); + if (ag->isOne()) { + sm.displayHandle(AgStateMachineWiFiManagerMode); + } + } } } + + delay(1); } - if (!WiFi.isConnected()) { - displayShowText("Booting", "offline", "mode"); - Serial.println("failed to connect and hit timeout"); - delay(2500); - } else { - hasConfig = true; - } + // TODO This is for basic + // if (!WiFi.isConnected()) { + // disp.setText("Booting", "offline", "mode"); + // Serial.println("failed to connect and hit timeout"); + // delay(2500); + // } else { + // hasConfig = true; + // } #endif } @@ -344,7 +377,7 @@ String WifiConnector::localIpStr(void) { return WiFi.localIP().toString(); } /** * @brief Get status that wifi has configurated - * + * * @return true Configurated * @return false Not Configurated */ @@ -357,8 +390,8 @@ bool WifiConnector::hasConfigurated(void) { /** * @brief Get WiFi connection porttal timeout. - * - * @return true - * @return false + * + * @return true + * @return false */ bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; } diff --git a/src/AgWiFiConnector.h b/src/AgWiFiConnector.h index b4e76a7..99fc61b 100644 --- a/src/AgWiFiConnector.h +++ b/src/AgWiFiConnector.h @@ -12,13 +12,10 @@ class WifiConnector : public PrintLog { private: AirGradient *ag; -#ifdef ESP32 OledDisplay &disp; StateMachine &sm; Configuration &config; -#else - void displayShowText(String ln1, String ln2, String ln3); -#endif + String ssid; void *wifi = NULL; bool hasConfig; @@ -30,23 +27,21 @@ private: public: void setAirGradient(AirGradient *ag); -#ifdef ESP32 + WifiConnector(OledDisplay &disp, Stream &log, StateMachine &sm, Configuration& config); -#else - WifiConnector(Stream &log); +#ifdef ESP8266 + // WifiConnector(Stream &log); #endif ~WifiConnector(); bool connect(void); void disconnect(void); void handle(void); -#ifdef ESP32 void _wifiApCallback(void); void _wifiSaveConfig(void); void _wifiSaveParamCallback(void); bool _wifiConfigPortalActive(void); void _wifiTimeoutCallback(void); -#endif void _wifiProcess(); bool isConnected(void); void reset(void); diff --git a/src/App/AppDef.cpp b/src/App/AppDef.cpp index ad2d75d..beaa975 100644 --- a/src/App/AppDef.cpp +++ b/src/App/AppDef.cpp @@ -14,6 +14,8 @@ const char *AgFirmwareModeName(AgFirmwareMode mode) { return "0-1PS"; case FW_MODE_O_1P: return "O-1P"; + case FW_MODE_I_8PSL: + return "I-8PSL"; default: break; } diff --git a/src/App/AppDef.h b/src/App/AppDef.h index a4d9cfc..5434e04 100644 --- a/src/App/AppDef.h +++ b/src/App/AppDef.h @@ -101,6 +101,7 @@ enum AgFirmwareMode { FW_MODE_O_1PP, /** PMS5003T_1, PMS5003T_2 */ FW_MODE_O_1PS, /** PMS5003T, S8 */ FW_MODE_O_1P, /** PMS5003T */ + FW_MODE_I_8PSL, /** DIY_PRO 4.2 */ }; const char *AgFirmwareModeName(AgFirmwareMode mode); diff --git a/src/Main/LedBar.cpp b/src/Main/LedBar.cpp index 63aed35..97fb7ea 100644 --- a/src/Main/LedBar.cpp +++ b/src/Main/LedBar.cpp @@ -116,6 +116,9 @@ void LedBar::setColor(uint8_t red, uint8_t green, uint8_t blue) { */ void LedBar::show(void) { // Ignore update the LED if LED bar disabled + if(this->isBegin() == false) { + return; + } if (enabled == false) { return; }