Merge pull request #173 from airgradienthq/develop

Next version 3.1.3
This commit is contained in:
Phat Nguyen
2024-06-06 13:17:08 +07:00
committed by GitHub
10 changed files with 152 additions and 69 deletions

View File

@ -41,7 +41,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
#define LED_BAR_COUNT_INIT_VALUE (-1) /** */ #define LED_BAR_COUNT_INIT_VALUE (-1) /** */
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */ #define LED_BAR_ANIMATION_PERIOD 100 /** ms */
#define DISP_UPDATE_INTERVAL 5000 /** ms */ #define DISP_UPDATE_INTERVAL 5000 /** ms */
#define SERVER_CONFIG_UPDATE_INTERVAL 30000 /** ms */ #define SERVER_CONFIG_SYNC_INTERVAL 60000 /** ms */
#define SERVER_SYNC_INTERVAL 60000 /** ms */ #define SERVER_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 */
@ -82,7 +82,7 @@ bool hasSensorPMS = true;
bool hasSensorSHT = true; bool hasSensorSHT = true;
int pmFailCount = 0; int pmFailCount = 0;
int getCO2FailCount = 0; int getCO2FailCount = 0;
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, AgSchedule configSchedule(SERVER_CONFIG_SYNC_INTERVAL,
updateServerConfiguration); updateServerConfiguration);
AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule serverSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler); AgSchedule dispSchedule(DISP_UPDATE_INTERVAL, dispHandler);

View File

@ -55,7 +55,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */ #define LED_BAR_ANIMATION_PERIOD 100 /** ms */
#define DISP_UPDATE_INTERVAL 2500 /** ms */ #define DISP_UPDATE_INTERVAL 2500 /** ms */
#define SERVER_CONFIG_UPDATE_INTERVAL 15000 /** ms */ #define SERVER_CONFIG_SYNC_INTERVAL 60000 /** ms */
#define SERVER_SYNC_INTERVAL 60000 /** ms */ #define SERVER_SYNC_INTERVAL 60000 /** ms */
#define MQTT_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 */
@ -64,6 +64,7 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
#define SENSOR_PM_UPDATE_INTERVAL 2000 /** ms */ #define SENSOR_PM_UPDATE_INTERVAL 2000 /** ms */
#define SENSOR_TEMP_HUM_UPDATE_INTERVAL 2000 /** ms */ #define SENSOR_TEMP_HUM_UPDATE_INTERVAL 2000 /** ms */
#define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */ #define DISPLAY_DELAY_SHOW_CONTENT_MS 2000 /** ms */
#define FIRMWARE_CHECK_FOR_UPDATE_MS (60*60*1000) /** ms */
/** I2C define */ /** I2C define */
#define I2C_SDA_PIN 7 #define I2C_SDA_PIN 7
@ -113,12 +114,13 @@ static void factoryConfigReset(void);
static void wdgFeedUpdate(void); static void wdgFeedUpdate(void);
static void ledBarEnabledUpdate(void); static void ledBarEnabledUpdate(void);
static bool sgp41Init(void); static bool sgp41Init(void);
static void firmwareCheckForUpdate(void);
static void otaHandlerCallback(OtaState state, String mesasge); static void otaHandlerCallback(OtaState state, String mesasge);
static void displayExecuteOta(OtaState state, String msg, static void displayExecuteOta(OtaState state, String msg,
int processing); int processing);
AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, oledDisplayLedBarSchedule); AgSchedule dispLedSchedule(DISP_UPDATE_INTERVAL, oledDisplayLedBarSchedule);
AgSchedule configSchedule(SERVER_CONFIG_UPDATE_INTERVAL, AgSchedule configSchedule(SERVER_CONFIG_SYNC_INTERVAL,
configurationUpdateSchedule); configurationUpdateSchedule);
AgSchedule agApiPostSchedule(SERVER_SYNC_INTERVAL, sendDataToServer); AgSchedule agApiPostSchedule(SERVER_SYNC_INTERVAL, sendDataToServer);
AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update); AgSchedule co2Schedule(SENSOR_CO2_UPDATE_INTERVAL, co2Update);
@ -126,6 +128,7 @@ AgSchedule pmsSchedule(SENSOR_PM_UPDATE_INTERVAL, updatePm);
AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate); AgSchedule tempHumSchedule(SENSOR_TEMP_HUM_UPDATE_INTERVAL, tempHumUpdate);
AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc); AgSchedule tvocSchedule(SENSOR_TVOC_UPDATE_INTERVAL, updateTvoc);
AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate); AgSchedule watchdogFeedSchedule(60000, wdgFeedUpdate);
AgSchedule checkForUpdateSchedule(FIRMWARE_CHECK_FOR_UPDATE_MS, firmwareCheckForUpdate);
void setup() { void setup() {
/** Serial for print debug message */ /** Serial for print debug message */
@ -166,16 +169,6 @@ void setup() {
/** Connecting wifi */ /** Connecting wifi */
bool connectToWifi = false; bool connectToWifi = false;
if (ag->isOne()) { if (ag->isOne()) {
if (ledBarButtonTest) {
if (ag->button.getState() == PushButton::BUTTON_PRESSED) {
WiFi.begin("airgradient", "cleanair");
Serial.println("WiFi Credential reset to factory defaults");
ESP.restart();
}
} else {
ledBarEnabledUpdate();
}
/** Show message confirm offline mode, should me perform if LED bar button /** Show message confirm offline mode, should me perform if LED bar button
* test pressed */ * test pressed */
if (ledBarButtonTest == false) { if (ledBarButtonTest == false) {
@ -219,10 +212,8 @@ void setup() {
#ifdef ESP8266 #ifdef ESP8266
// ota not supported // ota not supported
#else #else
otaHandler.updateFirmwareIfOutdated(ag->deviceId()); firmwareCheckForUpdate();
checkForUpdateSchedule.update();
/** Update first OTA */
measurements.otaBootCount = 0;
#endif #endif
apiClient.fetchServerConfiguration(); apiClient.fetchServerConfiguration();
@ -241,8 +232,12 @@ void setup() {
ledBarEnabledUpdate(); ledBarEnabledUpdate();
} }
} else { } else {
if (wifiConnector.isConfigurePorttalTimeout()) {
oledDisplay.showRebooting(); oledDisplay.showRebooting();
delay(2500); delay(2500);
oledDisplay.setText("", "", "");
ESP.restart();
}
} }
} }
} }
@ -312,6 +307,9 @@ void loop() {
/** check that local configura changed then do some action */ /** check that local configura changed then do some action */
configUpdateHandle(); configUpdateHandle();
/** Firmware check for update handle */
checkForUpdateSchedule.run();
} }
static void co2Update(void) { static void co2Update(void) {
@ -420,6 +418,7 @@ static void factoryConfigReset(void) {
} }
/** Reset WIFI */ /** Reset WIFI */
WiFi.enableSTA(true); // Incase offline mode
WiFi.disconnect(true, true); WiFi.disconnect(true, true);
/** Reset local config */ /** Reset local config */
@ -431,6 +430,7 @@ static void factoryConfigReset(void) {
Serial.println("Factory reset successful"); Serial.println("Factory reset successful");
} }
delay(3000); delay(3000);
oledDisplay.setText("","","");
ESP.restart(); ESP.restart();
} }
} }
@ -488,7 +488,22 @@ static bool sgp41Init(void) {
return false; return false;
} }
static void firmwareCheckForUpdate(void) {
Serial.println();
Serial.println("firmwareCheckForUpdate:");
if (wifiConnector.isConnected()) {
Serial.println("firmwareCheckForUpdate: Perform");
otaHandler.setHandlerCallback(otaHandlerCallback);
otaHandler.updateFirmwareIfOutdated(ag->deviceId());
} else {
Serial.println("firmwareCheckForUpdate: Ignored");
}
Serial.println();
}
static void otaHandlerCallback(OtaState state, String mesasge) { static void otaHandlerCallback(OtaState state, String mesasge) {
Serial.println("OTA message: " + mesasge);
switch (state) { switch (state) {
case OtaState::OTA_STATE_BEGIN: case OtaState::OTA_STATE_BEGIN:
displayExecuteOta(state, fwNewVersion, 0); displayExecuteOta(state, fwNewVersion, 0);
@ -511,7 +526,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) {
switch (state) { switch (state) {
case OtaState::OTA_STATE_BEGIN: { case OtaState::OTA_STATE_BEGIN: {
if (ag->isOne()) { if (ag->isOne()) {
oledDisplay.showNewFirmwareVersion(msg); oledDisplay.showFirmwareUpdateVersion(msg);
} else { } else {
Serial.println("New firmware: " + msg); Serial.println("New firmware: " + msg);
} }
@ -520,7 +535,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) {
} }
case OtaState::OTA_STATE_FAIL: { case OtaState::OTA_STATE_FAIL: {
if (ag->isOne()) { if (ag->isOne()) {
oledDisplay.showNewFirmwareFailed(); oledDisplay.showFirmwareUpdateFailed();
} else { } else {
Serial.println("Error: Firmware update: failed"); Serial.println("Error: Firmware update: failed");
} }
@ -528,9 +543,29 @@ static void displayExecuteOta(OtaState state, String msg, int processing) {
delay(2500); delay(2500);
break; break;
} }
case OtaState::OTA_STATE_SKIP: {
if (ag->isOne()) {
oledDisplay.showFirmwareUpdateSkipped();
} else {
Serial.println("Firmware update: Skipped");
}
delay(2500);
break;
}
case OtaState::OTA_STATE_UP_TO_DATE: {
if (ag->isOne()) {
oledDisplay.showFirmwareUpdateUpToDate();
} else {
Serial.println("Firmware update: up to date");
}
delay(2500);
break;
}
case OtaState::OTA_STATE_PROCESSING: { case OtaState::OTA_STATE_PROCESSING: {
if (ag->isOne()) { if (ag->isOne()) {
oledDisplay.showNewFirmwareUpdating(String(processing)); oledDisplay.showFirmwareUpdateProgress(processing);
} else { } else {
Serial.println("Firmware update: " + String(processing) + String("%")); Serial.println("Firmware update: " + String(processing) + String("%"));
} }
@ -546,13 +581,14 @@ static void displayExecuteOta(OtaState state, String msg, int processing) {
while (i != 0) { while (i != 0) {
i = i - 1; i = i - 1;
if (ag->isOne()) { if (ag->isOne()) {
oledDisplay.showNewFirmwareSuccess(String(i)); oledDisplay.showFirmwareUpdateSuccess(i);
} else { } else {
Serial.println("Rebooting... " + String(i)); Serial.println("Rebooting... " + String(i));
} }
delay(1000); delay(1000);
} }
oledDisplay.setBrightness(0);
esp_restart(); esp_restart();
} }
break; break;
@ -641,6 +677,24 @@ static void oneIndoorInit(void) {
} }
} }
/** Check for button to reset WiFi connecto to "airgraident" after test LED
* bar */
if (ledBarButtonTest) {
if (ag->button.getState() == ag->button.BUTTON_PRESSED) {
WiFi.begin("airgradient", "cleanair");
oledDisplay.setText("Configure WiFi", "connect to", "\'airgradient\'");
delay(2500);
oledDisplay.setText("Rebooting...", "","");
delay(2500);
oledDisplay.setText("","","");
ESP.restart();
}
}
ledBarEnabledUpdate();
/** Show message init sensor */
oledDisplay.setText("Sensor", "initializing...", "");
/** Init sensor SGP41 */ /** Init sensor SGP41 */
if (sgp41Init() == false) { if (sgp41Init() == false) {
dispSensorNotFound("SGP41"); dispSensorNotFound("SGP41");
@ -881,32 +935,6 @@ static void configUpdateHandle() {
stateMachine.executeLedBarTest(); stateMachine.executeLedBarTest();
} }
fwNewVersion = configuration.newFirmwareVersion();
if (fwNewVersion.length()) {
bool doOta = false;
if (measurements.otaBootCount == 0) {
doOta = true;
Serial.println("First OTA");
} else {
/** Only check for update each 1h*/
const float otaBootCount = 60.0f / (SERVER_SYNC_INTERVAL / 60000.0f);
if ((measurements.bootCount - measurements.otaBootCount) >= (int)otaBootCount) {
doOta = true;
} else {
Serial.println(
"OTA ignore, try again next " +
String(30 - (measurements.bootCount - measurements.otaBootCount)) +
String(" boots"));
}
}
if (doOta) {
measurements.otaBootCount = measurements.bootCount;
otaHandler.setHandlerCallback(otaHandlerCallback);
otaHandler.updateFirmwareIfOutdated(ag->deviceId());
}
}
appDispHandler(); appDispHandler();
appLedHandler(); appLedHandler();
} }

View File

@ -18,6 +18,8 @@ enum OtaUpdateOutcome {
enum OtaState { enum OtaState {
OTA_STATE_BEGIN, OTA_STATE_BEGIN,
OTA_STATE_FAIL, OTA_STATE_FAIL,
OTA_STATE_SKIP,
OTA_STATE_UP_TO_DATE,
OTA_STATE_PROCESSING, OTA_STATE_PROCESSING,
OTA_STATE_SUCCESS OTA_STATE_SUCCESS
}; };
@ -40,13 +42,22 @@ public:
config.url = urlAsChar; config.url = urlAsChar;
OtaUpdateOutcome ret = attemptToPerformOta(&config); OtaUpdateOutcome ret = attemptToPerformOta(&config);
Serial.println(ret); Serial.println(ret);
if (ret == OtaUpdateOutcome::UPDATE_PERFORMED) {
if (this->callback) { if (this->callback) {
switch (ret) {
case OtaUpdateOutcome::UPDATE_PERFORMED:
this->callback(OtaState::OTA_STATE_SUCCESS, ""); this->callback(OtaState::OTA_STATE_SUCCESS, "");
} break;
} else { case OtaUpdateOutcome::UDPATE_SKIPPED:
if(this->callback) { this->callback(OtaState::OTA_STATE_SKIP, "");
break;
case OtaUpdateOutcome::ALREADY_UP_TO_DATE:
this->callback(OtaState::OTA_STATE_UP_TO_DATE, "");
break;
case OtaUpdateOutcome::UPDATE_FAILED:
this->callback(OtaState::OTA_STATE_FAIL, ""); this->callback(OtaState::OTA_STATE_FAIL, "");
break;
default:
break;
} }
} }
} }
@ -127,6 +138,9 @@ private:
int data_read = int data_read =
esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE); esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE);
if (data_read == 0) { if (data_read == 0) {
if (this->callback) {
this->callback(OtaState::OTA_STATE_PROCESSING, String(100));
}
Serial.println("Connection closed, all data received"); Serial.println("Connection closed, all data received");
break; break;
} }

View File

@ -1,5 +1,5 @@
name=AirGradient Air Quality Sensor name=AirGradient Air Quality Sensor
version=3.1.0-beta.1 version=3.1.3
author=AirGradient <support@airgradient.com> author=AirGradient <support@airgradient.com>
maintainer=AirGradient <support@airgradient.com> maintainer=AirGradient <support@airgradient.com>
sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display. sentence=ESP32-C3 / ESP8266 library for air quality monitor measuring PM, CO2, Temperature, TVOC and Humidity with OLED display.

View File

@ -330,7 +330,7 @@ void OledDisplay::setBrightness(int percent) {
} }
} }
void OledDisplay::showNewFirmwareVersion(String version) { void OledDisplay::showFirmwareUpdateVersion(String version) {
if (isDisplayOff) { if (isDisplayOff) {
return; return;
} }
@ -344,7 +344,7 @@ void OledDisplay::showNewFirmwareVersion(String version) {
} while (DISP()->nextPage()); } while (DISP()->nextPage());
} }
void OledDisplay::showNewFirmwareUpdating(String percent) { void OledDisplay::showFirmwareUpdateProgress(int percent) {
if (isDisplayOff) { if (isDisplayOff) {
return; return;
} }
@ -353,11 +353,11 @@ void OledDisplay::showNewFirmwareUpdating(String percent) {
do { do {
DISP()->setFont(u8g2_font_t0_16_tf); DISP()->setFont(u8g2_font_t0_16_tf);
setCentralText(20, "Firmware Update"); setCentralText(20, "Firmware Update");
setCentralText(50, String("Updating... ") + percent + String("%")); setCentralText(50, String("Updating... ") + String(percent) + String("%"));
} while (DISP()->nextPage()); } while (DISP()->nextPage());
} }
void OledDisplay::showNewFirmwareSuccess(String count) { void OledDisplay::showFirmwareUpdateSuccess(int count) {
if (isDisplayOff) { if (isDisplayOff) {
return; return;
} }
@ -367,11 +367,11 @@ void OledDisplay::showNewFirmwareSuccess(String count) {
DISP()->setFont(u8g2_font_t0_16_tf); DISP()->setFont(u8g2_font_t0_16_tf);
setCentralText(20, "Firmware Update"); setCentralText(20, "Firmware Update");
setCentralText(40, "Success"); setCentralText(40, "Success");
setCentralText(60, String("Rebooting... ") + count); setCentralText(60, String("Rebooting... ") + String(count));
} while (DISP()->nextPage()); } while (DISP()->nextPage());
} }
void OledDisplay::showNewFirmwareFailed(void) { void OledDisplay::showFirmwareUpdateFailed(void) {
if (isDisplayOff) { if (isDisplayOff) {
return; return;
} }
@ -380,8 +380,34 @@ void OledDisplay::showNewFirmwareFailed(void) {
do { do {
DISP()->setFont(u8g2_font_t0_16_tf); DISP()->setFont(u8g2_font_t0_16_tf);
setCentralText(20, "Firmware Update"); setCentralText(20, "Firmware Update");
setCentralText(40, "Failed"); setCentralText(40, "fail, will retry");
setCentralText(60, String("Retry after 24h")); // setCentralText(60, "will retry");
} while (DISP()->nextPage());
}
void OledDisplay::showFirmwareUpdateSkipped(void) {
if (isDisplayOff) {
return;
}
DISP()->firstPage();
do {
DISP()->setFont(u8g2_font_t0_16_tf);
setCentralText(20, "Firmware Update");
setCentralText(40, "skipped");
} while (DISP()->nextPage());
}
void OledDisplay::showFirmwareUpdateUpToDate(void) {
if (isDisplayOff) {
return;
}
DISP()->firstPage();
do {
DISP()->setFont(u8g2_font_t0_16_tf);
setCentralText(20, "Firmware Update");
setCentralText(40, "up to date");
} while (DISP()->nextPage()); } while (DISP()->nextPage());
} }

View File

@ -36,10 +36,12 @@ public:
void showDashboard(void); void showDashboard(void);
void showDashboard(const char *status); void showDashboard(const char *status);
void setBrightness(int percent); void setBrightness(int percent);
void showNewFirmwareVersion(String version); void showFirmwareUpdateVersion(String version);
void showNewFirmwareUpdating(String percent); void showFirmwareUpdateProgress(int percent);
void showNewFirmwareSuccess(String count); void showFirmwareUpdateSuccess(int count);
void showNewFirmwareFailed(void); void showFirmwareUpdateFailed(void);
void showFirmwareUpdateSkipped(void);
void showFirmwareUpdateUpToDate(void);
void showRebooting(void); void showRebooting(void);
}; };

View File

@ -174,6 +174,7 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi,
} }
} }
root["boot"] = bootCount; root["boot"] = bootCount;
root["bootCount"] = bootCount;
if (localServer) { if (localServer) {
root["ledMode"] = config->getLedBarModeName(); root["ledMode"] = config->getLedBarModeName();

View File

@ -69,7 +69,6 @@ public:
int countPosition; int countPosition;
const int targetCount = 20; const int targetCount = 20;
int bootCount; int bootCount;
int otaBootCount;
String toString(bool isLocal, AgFirmwareMode fwMode, int rssi, void* _ag, void* _config); String toString(bool isLocal, AgFirmwareMode fwMode, int rssi, void* _ag, void* _config);
}; };

View File

@ -53,6 +53,7 @@ bool WifiConnector::connect(void) {
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](){});
if (ag->isOne()) { if (ag->isOne()) {
disp.setText("Connecting to", "WiFi", "..."); disp.setText("Connecting to", "WiFi", "...");
} else { } else {
@ -245,6 +246,7 @@ void WifiConnector::_wifiSaveParamCallback(void) {
bool WifiConnector::_wifiConfigPortalActive(void) { bool WifiConnector::_wifiConfigPortalActive(void) {
return WIFI()->getConfigPortalActive(); return WIFI()->getConfigPortalActive();
} }
void WifiConnector::_wifiTimeoutCallback(void) { connectorTimeout = true; }
#endif #endif
/** /**
* @brief Process WiFiManager connection * @brief Process WiFiManager connection
@ -352,3 +354,11 @@ bool WifiConnector::hasConfigurated(void) {
} }
return true; return true;
} }
/**
* @brief Get WiFi connection porttal timeout.
*
* @return true
* @return false
*/
bool WifiConnector::isConfigurePorttalTimeout(void) { return connectorTimeout; }

View File

@ -24,6 +24,7 @@ private:
bool hasConfig; bool hasConfig;
uint32_t lastRetry; uint32_t lastRetry;
bool hasPortalConfig = false; bool hasPortalConfig = false;
bool connectorTimeout = false;
bool wifiClientConnected(void); bool wifiClientConnected(void);
@ -44,6 +45,7 @@ public:
void _wifiSaveConfig(void); void _wifiSaveConfig(void);
void _wifiSaveParamCallback(void); void _wifiSaveParamCallback(void);
bool _wifiConfigPortalActive(void); bool _wifiConfigPortalActive(void);
void _wifiTimeoutCallback(void);
#endif #endif
void _wifiProcess(); void _wifiProcess();
bool isConnected(void); bool isConnected(void);
@ -51,6 +53,7 @@ public:
int RSSI(void); int RSSI(void);
String localIpStr(void); String localIpStr(void);
bool hasConfigurated(void); bool hasConfigurated(void);
bool isConfigurePorttalTimeout(void);
}; };
#endif /** _AG_WIFI_CONNECTOR_H_ */ #endif /** _AG_WIFI_CONNECTOR_H_ */