Merge branch 'enhance/AutoConnectAux' of https://github.com/Hieromon/AutoConnect into enhance/AutoConnectAux

pull/41/head
Hieromon Ikasamo 6 years ago
commit 8dcaa89df5
  1. 209
      src/AutoConnect.cpp
  2. 15
      src/AutoConnect.h
  3. 16
      src/AutoConnectDefs.h
  4. 794
      src/AutoConnectPage.cpp

@ -3,7 +3,7 @@
* @file AutoConnect.cpp * @file AutoConnect.cpp
* @author hieromon@gmail.com * @author hieromon@gmail.com
* @version 0.9.7 * @version 0.9.7
* @date 2018-11-17 * @date 2019-01-21
* @copyright MIT license. * @copyright MIT license.
*/ */
@ -51,9 +51,12 @@ void AutoConnect::_initialize() {
_rfReset = false; _rfReset = false;
_responsePage = nullptr; _responsePage = nullptr;
_currentPageElement = nullptr; _currentPageElement = nullptr;
_menuTitle = String(AUTOCONNECT_MENU_TITLE); _menuTitle = String(F(AUTOCONNECT_MENU_TITLE));
_connectTimeout = AUTOCONNECT_TIMEOUT; _connectTimeout = AUTOCONNECT_TIMEOUT;
memset(&_credential, 0x00, sizeof(struct station_config)); memset(&_credential, 0x00, sizeof(struct station_config));
#ifdef ARDUINO_ARCH_ESP32
_disconnectEventId = -1; // The member available for ESP32 only
#endif
_aux.release(); _aux.release();
} }
@ -81,12 +84,11 @@ bool AutoConnect::begin() {
* @param ssid SSID to be connected. * @param ssid SSID to be connected.
* @param passphrase Password for connection. * @param passphrase Password for connection.
* @param timeout A time out value in milliseconds for waiting connection. * @param timeout A time out value in milliseconds for waiting connection.
* @retval true Connection established, AutoConnect service started with WIFI_STA mode. * @return true Connection established, AutoConnect service started with WIFI_STA mode.
* @retval false Could not connected, Captive portal started with WIFI_AP_STA mode. * @return false Could not connected, Captive portal started with WIFI_AP_STA mode.
*/ */
bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long timeout) { bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long timeout) {
bool cs; bool cs;
bool hasTimeout;
// Overwrite for the current timeout value. // Overwrite for the current timeout value.
_connectTimeout = timeout; _connectTimeout = timeout;
@ -166,8 +168,10 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
// Activate the AP mode with configured softAP and start the access point. // Activate the AP mode with configured softAP and start the access point.
WiFi.mode(WIFI_AP_STA); WiFi.mode(WIFI_AP_STA);
while (WiFi.getMode() != WIFI_AP_STA) while (WiFi.getMode() != WIFI_AP_STA) {
delay(1);
yield(); yield();
}
// Connection unsuccessful, launch the captive portal. // Connection unsuccessful, launch the captive portal.
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266)
@ -176,15 +180,21 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
} }
#endif #endif
WiFi.softAP(_apConfig.apid.c_str(), _apConfig.psk.c_str(), _apConfig.channel, _apConfig.hidden); WiFi.softAP(_apConfig.apid.c_str(), _apConfig.psk.c_str(), _apConfig.channel, _apConfig.hidden);
while (WiFi.softAPIP() == IPAddress(0, 0, 0, 0)) { do {
delay(100); delay(100);
yield(); yield();
} } while (WiFi.softAPIP() == IPAddress(0, 0, 0, 0));
#if defined(ARDUINO_ARCH_ESP32) #if defined(ARDUINO_ARCH_ESP32)
if (!(_apConfig.apip == IPAddress(0, 0, 0, 0) || _apConfig.gateway == IPAddress(0, 0, 0, 0) || _apConfig.netmask == IPAddress(0, 0, 0, 0))) { if (!(_apConfig.apip == IPAddress(0, 0, 0, 0) || _apConfig.gateway == IPAddress(0, 0, 0, 0) || _apConfig.netmask == IPAddress(0, 0, 0, 0))) {
_config(); _config();
} }
#endif #endif
if (_apConfig.apip != IPAddress(0, 0, 0, 0)) {
do {
delay(100);
yield();
} while (WiFi.softAPIP() != _apConfig.apip);
}
_currentHostIP = WiFi.softAPIP(); _currentHostIP = WiFi.softAPIP();
AC_DBG("SoftAP %s/%s CH(%d) H(%d) IP:%s\n", _apConfig.apid.c_str(), _apConfig.psk.c_str(), _apConfig.channel, _apConfig.hidden, _currentHostIP.toString().c_str()); AC_DBG("SoftAP %s/%s CH(%d) H(%d) IP:%s\n", _apConfig.apid.c_str(), _apConfig.psk.c_str(), _apConfig.channel, _apConfig.hidden, _currentHostIP.toString().c_str());
@ -201,15 +211,14 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
_startDNSServer(); _startDNSServer();
// Start the captive portal to make a new connection // Start the captive portal to make a new connection
hasTimeout = false; bool hasTimeout = false;
_portalAccessPeriod = millis(); _portalAccessPeriod = millis();
while (WiFi.status() != WL_CONNECTED && !_rfReset) { while (WiFi.status() != WL_CONNECTED && !_rfReset) {
handleClient(); handleClient();
// Force execution of queued processes. // Force execution of queued processes.
yield(); yield();
// Check timeout // Check timeout
if (_hasTimeout(_apConfig.portalTimeout)) { if ((hasTimeout = _hasTimeout(_apConfig.portalTimeout))) {
hasTimeout = true;
AC_DBG("CP timeout exceeded:%ld\n", millis() - _portalAccessPeriod); AC_DBG("CP timeout exceeded:%ld\n", millis() - _portalAccessPeriod);
break; break;
} }
@ -220,6 +229,7 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long
if (cs) { if (cs) {
_dnsServer->stop(); _dnsServer->stop();
_dnsServer.reset(); _dnsServer.reset();
AC_DBG("DNS server stopped\n");
} }
// Captive portal staying time exceeds timeout, // Captive portal staying time exceeds timeout,
// Close the portal if an option for keeping the portal is false. // Close the portal if an option for keeping the portal is false.
@ -305,8 +315,10 @@ void AutoConnect::end() {
if (_webServer) { if (_webServer) {
switch (_webServerAlloc) { switch (_webServerAlloc) {
case AC_WEBSERVER_HOSTED: case AC_WEBSERVER_HOSTED:
if (_dnsServer) if (_dnsServer) {
_dnsServer->stop();
_dnsServer.reset(); _dnsServer.reset();
}
_webServer.reset(); _webServer.reset();
break; break;
case AC_WEBSERVER_PARASITIC: case AC_WEBSERVER_PARASITIC:
@ -379,7 +391,7 @@ void AutoConnect::_startWebServer() {
// here, Prepare PageBuilders for captive portal // here, Prepare PageBuilders for captive portal
if (!_responsePage) { if (!_responsePage) {
_responsePage = new PageBuilder(); _responsePage = new PageBuilder();
_responsePage->chunked(PB_ByteStream); _responsePage->chunked(AUTOCONNECT_HTTP_TRANSFER);
_responsePage->exitCanHandle(std::bind(&AutoConnect::_classifyHandle, this, std::placeholders::_1, std::placeholders::_2)); _responsePage->exitCanHandle(std::bind(&AutoConnect::_classifyHandle, this, std::placeholders::_1, std::placeholders::_2));
_responsePage->insert(*_webServer); _responsePage->insert(*_webServer);
@ -428,8 +440,8 @@ void AutoConnect::handleRequest() {
// Handling processing requests to AutoConnect. // Handling processing requests to AutoConnect.
if (_rfConnect) { if (_rfConnect) {
// Leave from the AP currently. // Leave from the AP currently.
// if (WiFi.status() == WL_CONNECTED) if (WiFi.status() == WL_CONNECTED)
// _disconnectWiFi(true); _disconnectWiFi(true);
// An attempt to establish a new AP. // An attempt to establish a new AP.
AC_DBG("Request for %s\n", reinterpret_cast<const char*>(_credential.ssid)); AC_DBG("Request for %s\n", reinterpret_cast<const char*>(_credential.ssid));
@ -438,7 +450,7 @@ void AutoConnect::handleRequest() {
if (WiFi.BSSID() != NULL) { if (WiFi.BSSID() != NULL) {
memcpy(_credential.bssid, WiFi.BSSID(), sizeof(station_config::bssid)); memcpy(_credential.bssid, WiFi.BSSID(), sizeof(station_config::bssid));
_currentHostIP = WiFi.localIP(); _currentHostIP = WiFi.localIP();
_redirectURI = String(AUTOCONNECT_URI_SUCCESS); _redirectURI = String(F(AUTOCONNECT_URI_SUCCESS));
// Save current credential // Save current credential
if (_apConfig.autoSave == AC_SAVECREDENTIAL_AUTO) { if (_apConfig.autoSave == AC_SAVECREDENTIAL_AUTO) {
@ -446,17 +458,20 @@ void AutoConnect::handleRequest() {
credit.save(&_credential); credit.save(&_credential);
AC_DBG("%s credential saved\n", reinterpret_cast<const char*>(_credential.ssid)); AC_DBG("%s credential saved\n", reinterpret_cast<const char*>(_credential.ssid));
} }
// Ensures that keeps a connection with the current AP while the portal behaves.
_setReconnect(AC_RECONNECT_SET);
} }
else else
AC_DBG("%s has no BSSID, saving is unavailable\n", reinterpret_cast<const char*>(_credential.ssid)); AC_DBG("%s has no BSSID, saving is unavailable\n", reinterpret_cast<const char*>(_credential.ssid));
} }
else { else {
_currentHostIP = WiFi.softAPIP(); _currentHostIP = WiFi.softAPIP();
_redirectURI = String(AUTOCONNECT_URI_FAIL); _redirectURI = String(F(AUTOCONNECT_URI_FAIL));
_rsConnect = WiFi.status(); _rsConnect = WiFi.status();
_disconnectWiFi(false); _disconnectWiFi(false);
while (WiFi.status() != WL_IDLE_STATUS && WiFi.status() != WL_DISCONNECTED) { while (WiFi.status() != WL_IDLE_STATUS && WiFi.status() != WL_DISCONNECTED) {
delay(10); delay(1);
yield(); yield();
} }
} }
@ -474,6 +489,7 @@ void AutoConnect::handleRequest() {
if (_rfDisconnect) { if (_rfDisconnect) {
// Disconnect from the current AP. // Disconnect from the current AP.
_waitForEndTransmission();
_stopPortal(); _stopPortal();
_disconnectWiFi(false); _disconnectWiFi(false);
while (WiFi.status() == WL_CONNECTED) { while (WiFi.status() == WL_CONNECTED) {
@ -533,7 +549,7 @@ void AutoConnect::onNotFound(WebServerClass::THandlerFunction fn) {
/** /**
* Load stored credentials that match nearby WLANs. * Load stored credentials that match nearby WLANs.
* @retval true A matched credential of BSSID was loaded. * @return true A matched credential of BSSID was loaded.
*/ */
bool AutoConnect::_loadAvailCredential() { bool AutoConnect::_loadAvailCredential() {
AutoConnectCredential credential(_apConfig.boundaryOffset); AutoConnectCredential credential(_apConfig.boundaryOffset);
@ -570,8 +586,9 @@ void AutoConnect::_stopPortal() {
delay(1000); delay(1000);
} }
_setReconnect(AC_RECONNECT_RESET);
WiFi.softAPdisconnect(false); WiFi.softAPdisconnect(false);
AC_DBG("SoftAP stopped\n"); AC_DBG("Portal stopped\n");
} }
/** /**
@ -581,9 +598,9 @@ void AutoConnect::_stopPortal() {
bool AutoConnect::_captivePortal() { bool AutoConnect::_captivePortal() {
String hostHeader = _webServer->hostHeader(); String hostHeader = _webServer->hostHeader();
if (!_isIP(hostHeader) && (hostHeader != WiFi.localIP().toString())) { if (!_isIP(hostHeader) && (hostHeader != WiFi.localIP().toString())) {
String location = String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI); String location = String(F("http://")) + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI);
_webServer->sendHeader("Location", location, true); _webServer->sendHeader(F("Location"), location, true);
_webServer->send(302, "text/plain", ""); _webServer->send(302, F("text/plain"), "");
_webServer->client().flush(); _webServer->client().flush();
_webServer->client().stop(); _webServer->client().stop();
return true; return true;
@ -593,6 +610,10 @@ bool AutoConnect::_captivePortal() {
/** /**
* Check whether the stay-time in the captive portal has a timeout. * Check whether the stay-time in the captive portal has a timeout.
* If the station is connected, the time measurement will be reset.
* @param timeout The time limit for keeping the captive portal.
* @return true There is no connection from the station even the time limit exceeds.
* @return false Connectionless duration has not exceeded yet.
*/ */
bool AutoConnect::_hasTimeout(unsigned long timeout) { bool AutoConnect::_hasTimeout(unsigned long timeout) {
uint8_t staNum; uint8_t staNum;
@ -629,11 +650,11 @@ void AutoConnect::_handleNotFound() {
else { else {
PageElement page404(_PAGE_404, { { "HEAD", std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1) } }); PageElement page404(_PAGE_404, { { "HEAD", std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1) } });
String html = page404.build(); String html = page404.build();
_webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate", true); _webServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"), true);
_webServer->sendHeader("Pragma", "no-cache"); _webServer->sendHeader(F("Pragma"), F("no-cache"));
_webServer->sendHeader("Expires", "-1"); _webServer->sendHeader(F("Expires"), F("-1"));
_webServer->sendHeader("Content-Length", String(html.length())); _webServer->sendHeader(F("Content-Length"), String(html.length()));
_webServer->send(404, "text/html", html); _webServer->send(404, F("text/html"), html);
} }
} }
} }
@ -645,7 +666,7 @@ void AutoConnect::_handleNotFound() {
*/ */
String AutoConnect::_induceReset(PageArgument& args) { String AutoConnect::_induceReset(PageArgument& args) {
_rfReset = true; _rfReset = true;
return String("Reset in progress..."); return String(F("Reset in progress..."));
} }
/** /**
@ -664,7 +685,7 @@ String AutoConnect::_induceDisconnect(PageArgument& args) {
* handling of the current request by PageBuilder triggered by handleClient(). * handling of the current request by PageBuilder triggered by handleClient().
* If "Credential" exists in POST parameter, it reads from EEPROM. * If "Credential" exists in POST parameter, it reads from EEPROM.
* @param args http request arguments. * @param args http request arguments.
* @retval A redirect response including "Location:" header. * @return A redirect response including "Location:" header.
*/ */
String AutoConnect::_induceConnect(PageArgument& args) { String AutoConnect::_induceConnect(PageArgument& args) {
// Retrieve credential from the post method content. // Retrieve credential from the post method content.
@ -675,7 +696,7 @@ String AutoConnect::_induceConnect(PageArgument& args) {
credential.load(args.arg(AUTOCONNECT_PARAMID_CRED).c_str(), &entry); credential.load(args.arg(AUTOCONNECT_PARAMID_CRED).c_str(), &entry);
strncpy(reinterpret_cast<char*>(_credential.ssid), reinterpret_cast<const char*>(entry.ssid), sizeof(_credential.ssid)); strncpy(reinterpret_cast<char*>(_credential.ssid), reinterpret_cast<const char*>(entry.ssid), sizeof(_credential.ssid));
strncpy(reinterpret_cast<char*>(_credential.password), reinterpret_cast<const char*>(entry.password), sizeof(_credential.password)); strncpy(reinterpret_cast<char*>(_credential.password), reinterpret_cast<const char*>(entry.password), sizeof(_credential.password));
AC_DBG("Credential loaded:%s %s\n", _credential.ssid, _credential.password); AC_DBG("Credential loaded:%s\n", _credential.ssid);
} }
else { else {
// Credential had by the post parameter. // Credential had by the post parameter.
@ -686,16 +707,32 @@ String AutoConnect::_induceConnect(PageArgument& args) {
// Turn on the trigger to start WiFi.begin(). // Turn on the trigger to start WiFi.begin().
_rfConnect = true; _rfConnect = true;
// Redirect to waiting URI while executing connection request. // Since v0.9.7, the redirect method changed from a 302 response to the
//_webServer->sendHeader("Location", String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT), true); // meta tag with refresh attribute.
String url = String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT); // This approach for ESP32 makes an inefficient choice. The waiting
_webServer->sendHeader("Location", url, true); // procedure for a connection attempt should be the server side. Also,
//_webServer->sendHeader("Connection", "keep-alive"); // the proper value of waiting time until refreshing is unknown. But
_webServer->send(302, "text/plain", ""); // AutoConnect cannot avoid the following error as affairs stand now
_webServer->client().flush(); // that occurs at connection establishment.
_webServer->client().stop(); // [WiFiClient.cpp:463] connected(): Disconnected: RES: 0, ERR: 128
_responsePage->cancel(); // When connecting as a station, TCP reset caused by switching of the
// radio channel occurs. Although the Espressif's view is true. However,
// the actual TCP reset occurs not at the time of switching the channel.
// It occurs at the connection from the ESP32 to the AP is established
// and it is possible that TCP reset is occurring in other situations.
// So, it may not be the real cause. Client-origin redirects with HTML
// refresh depend on the behavior of the arduino-esp32 library. Thus,
// the implementations for redirects with HTML will continue until
// the arduino-esp32 core supports reconnection.
// Redirect to waiting URI while executing connection request.
// String url = String(F("http://")) + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT);
// _webServer->sendHeader(F("Location"), url, true);
// _webServer->send(302, F("text/plain"), "");
// _webServer->client().stop();
// _webServer->client().flush();
// _waitForEndTransmission(); // Wait for response transmission complete
// _responsePage->cancel();
return String(""); return String("");
} }
@ -704,11 +741,25 @@ String AutoConnect::_induceConnect(PageArgument& args) {
* A destination as _redirectURI is indicated by loop to establish connection. * A destination as _redirectURI is indicated by loop to establish connection.
*/ */
String AutoConnect::_invokeResult(PageArgument& args) { String AutoConnect::_invokeResult(PageArgument& args) {
String redirect = String("http://") + _currentHostIP.toString() + _redirectURI; String redirect = String(F("http://"));
_webServer->sendHeader("Location", redirect, true); // The host address to which the connection result for ESP32 responds
_webServer->send(302, "text/plain", ""); // changed from v0.9.7. This change is a measure according to the
_webServer->client().flush(); // implementation of the arduino-esp32 1.0.1 core.
#if defined(ARDUINO_ARCH_ESP32)
// In ESP32, the station IP address just established could not be reached.
redirect += _webServer->client().localIP().toString();
#elif defined(ARDUINO_ARCH_ESP8266)
// In ESP8266, the host address that responds for the connection
// successful is the IP address of ESP8266 as a station.
// This is the specification as before.
redirect += _currentHostIP.toString();
#endif
redirect += _redirectURI;
_webServer->sendHeader(F("Location"), redirect, true);
_webServer->send(302, F("text/plain"), "");
_webServer->client().stop(); _webServer->client().stop();
_webServer->client().flush();
_waitForEndTransmission(); // Wait for response transmission complete
_responsePage->cancel(); _responsePage->cancel();
return String(""); return String("");
} }
@ -724,8 +775,8 @@ bool AutoConnect::_classifyHandle(HTTPMethod method, String uri) {
_portalAccessPeriod = millis(); _portalAccessPeriod = millis();
AC_DBG("Host:%s, URI:%s", _webServer->hostHeader().c_str(), uri.c_str()); AC_DBG("Host:%s, URI:%s", _webServer->hostHeader().c_str(), uri.c_str());
// When handleClient calls RequestHandler, the parsed http argument remains // When handleClient calls RequestHandler, the parsed http argument
// the previous request. // remains the previous request.
// If the current request argument contains AutoConnectElement, it is // If the current request argument contains AutoConnectElement, it is
// the form data of the AutoConnectAux page and with this timing save // the form data of the AutoConnectAux page and with this timing save
// the value of each element. // the value of each element.
@ -796,7 +847,7 @@ bool AutoConnect::_isIP(String ipStr) {
/** /**
* Convert MAC address in uint8_t array to Sting XX:XX:XX:XX:XX:XX format. * Convert MAC address in uint8_t array to Sting XX:XX:XX:XX:XX:XX format.
* @param mac Array of MAC address 6 bytes. * @param mac Array of MAC address 6 bytes.
* @retval MAC address string in XX:XX:XX:XX:XX:XX format. * @return MAC address string in XX:XX:XX:XX:XX:XX format.
*/ */
String AutoConnect::_toMACAddressString(const uint8_t mac[]) { String AutoConnect::_toMACAddressString(const uint8_t mac[]) {
String macAddr = String(""); String macAddr = String("");
@ -813,7 +864,7 @@ String AutoConnect::_toMACAddressString(const uint8_t mac[]) {
/** /**
* Convert dBm to the wifi signal quality. * Convert dBm to the wifi signal quality.
* @param rssi dBm. * @param rssi dBm.
* @retval a signal quality percentage. * @return A signal quality percentage.
*/ */
unsigned int AutoConnect::_toWiFiQuality(int32_t rssi) { unsigned int AutoConnect::_toWiFiQuality(int32_t rssi) {
unsigned int qu; unsigned int qu;
@ -831,7 +882,7 @@ unsigned int AutoConnect::_toWiFiQuality(int32_t rssi) {
/** /**
* Wait for establishment of the connection until the specified time expires. * Wait for establishment of the connection until the specified time expires.
* @param timeout Expiration time by millisecond unit. * @param timeout Expiration time by millisecond unit.
* @retval wl_status_t * @return wl_status_t
*/ */
wl_status_t AutoConnect::_waitForConnect(unsigned long timeout) { wl_status_t AutoConnect::_waitForConnect(unsigned long timeout) {
wl_status_t wifiStatus; wl_status_t wifiStatus;
@ -850,6 +901,60 @@ wl_status_t AutoConnect::_waitForConnect(unsigned long timeout) {
return wifiStatus; return wifiStatus;
} }
/**
* Control the automatic reconnection behaves. Reconnection behavior
* to the AP connected during captive portal operation is activated
* by an order as the argument.
* @param order AC_RECONNECT_SET or AC_RECONNECT_RESET
*/
void AutoConnect::_setReconnect(const AC_STARECONNECT_t order) {
#if defined(ARDUINO_ARCH_ESP32)
if (order == AC_RECONNECT_SET) {
_disconnectEventId = WiFi.onEvent([](WiFiEvent_t e, WiFiEventInfo_t info) {
AC_DBG("STA lost connection:%d\n", info.disconnected.reason);
bool rst = WiFi.reconnect();
AC_DBG("STA connection %s\n", rst ? "restored" : "failed");
}, WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED);
AC_DBG("Event<%d> handler registered\n", static_cast<int>(WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED));
}
else if (order == AC_RECONNECT_RESET) {
if (_disconnectEventId) {
WiFi.removeEvent(_disconnectEventId);
AC_DBG("Event<%d> handler released\n", static_cast<int>(WiFiEvent_t::SYSTEM_EVENT_AP_STADISCONNECTED));
}
}
#elif defined(ARDUINO_ARCH_ESP8266)
bool strc = order == AC_RECONNECT_SET ? true : false;
WiFi.setAutoReconnect(strc);
AC_DBG("STA reconnection:%s\n", strc ? "EN" : "DIS");
#endif
}
/**
* Wait for the end of transmission of the http response by closed
* from the http client.
*/
void AutoConnect::_waitForEndTransmission() {
#ifdef AC_DEBUG
AC_DBG("Leaves:");
unsigned long lt = millis();
#endif
while (_webServer->client().connected()) {
delay(1);
yield();
}
#ifdef AC_DEBUG
// Notifies of the time taken to end the session. If the http client
// times out, AC_DEBUG must be enabled and it is necessary to confirm
// that the http response is being transmitted correctly.
// To trace the correctness the close sequence of TCP connection,
// enable the debug log of the Arduino core side. If the normal,
// a message of closed the TCP connection will be logged between
// "Leaves:" and "the time taken to end the session" of the log.
AC_DBG_DUMB("%d[ms]\n", static_cast<int>(millis() - lt));
#endif
}
/** /**
* Disconnects the station from an associated access point. * Disconnects the station from an associated access point.
* @param wifiOff The station mode turning switch. * @param wifiOff The station mode turning switch.
@ -860,6 +965,8 @@ void AutoConnect::_disconnectWiFi(bool wifiOff) {
#elif defined(ARDUINO_ARCH_ESP32) #elif defined(ARDUINO_ARCH_ESP32)
WiFi.disconnect(wifiOff, true); WiFi.disconnect(wifiOff, true);
#endif #endif
while (WiFi.status() == WL_CONNECTED) while (WiFi.status() == WL_CONNECTED) {
delay(100); delay(1);
yield();
}
} }

@ -3,7 +3,7 @@
* @file AutoConnect.h * @file AutoConnect.h
* @author hieromon@gmail.com * @author hieromon@gmail.com
* @version 0.9.7 * @version 0.9.7
* @date 2018-11-17 * @date 2019-01-21
* @copyright MIT license. * @copyright MIT license.
*/ */
@ -199,6 +199,10 @@ class AutoConnect {
AC_WEBSERVER_HOSTED AC_WEBSERVER_HOSTED
}; };
typedef enum _webServerAllocateType AC_WEBSERVER_TYPE; typedef enum _webServerAllocateType AC_WEBSERVER_TYPE;
typedef enum {
AC_RECONNECT_SET,
AC_RECONNECT_RESET
} AC_STARECONNECT_t;
void _initialize(); void _initialize();
bool _config(); bool _config();
void _startWebServer(); void _startWebServer();
@ -224,7 +228,9 @@ class AutoConnect {
bool _hasTimeout(unsigned long timeout); bool _hasTimeout(unsigned long timeout);
bool _isIP(String ipStr); bool _isIP(String ipStr);
wl_status_t _waitForConnect(unsigned long timeout); wl_status_t _waitForConnect(unsigned long timeout);
void _waitForEndTransmission(void);
void _disconnectWiFi(bool wifiOff); void _disconnectWiFi(bool wifiOff);
void _setReconnect(const AC_STARECONNECT_t order);
/** Utilities */ /** Utilities */
static uint32_t _getChipId(); static uint32_t _getChipId();
@ -262,6 +268,9 @@ class AutoConnect {
bool _rfDisconnect; /**< URI /disc requested */ bool _rfDisconnect; /**< URI /disc requested */
bool _rfReset; /**< URI /reset requested */ bool _rfReset; /**< URI /reset requested */
wl_status_t _rsConnect; /**< connection result */ wl_status_t _rsConnect; /**< connection result */
#ifdef ARDUINO_ARCH_ESP32
WiFiEventId_t _disconnectEventId; /**< STA disconnection event handler registered id */
#endif
/** HTTP header information of the currently requested page. */ /** HTTP header information of the currently requested page. */
String _uri; /**< Requested URI */ String _uri; /**< Requested URI */
@ -276,6 +285,7 @@ class AutoConnect {
static const char _CSS_INPUT_BUTTON[] PROGMEM; static const char _CSS_INPUT_BUTTON[] PROGMEM;
static const char _CSS_INPUT_TEXT[] PROGMEM; static const char _CSS_INPUT_TEXT[] PROGMEM;
static const char _CSS_TABLE[] PROGMEM; static const char _CSS_TABLE[] PROGMEM;
static const char _CSS_SPINNER[] PROGMEM;
static const char _CSS_LUXBAR[] PROGMEM; static const char _CSS_LUXBAR[] PROGMEM;
static const char _ELM_HTML_HEAD[] PROGMEM; static const char _ELM_HTML_HEAD[] PROGMEM;
static const char _ELM_MENU_PRE[] PROGMEM; static const char _ELM_MENU_PRE[] PROGMEM;
@ -283,6 +293,7 @@ class AutoConnect {
static const char _ELM_MENU_POST[] PROGMEM; static const char _ELM_MENU_POST[] PROGMEM;
static const char _PAGE_STAT[] PROGMEM; static const char _PAGE_STAT[] PROGMEM;
static const char _PAGE_CONFIGNEW[] PROGMEM; static const char _PAGE_CONFIGNEW[] PROGMEM;
static const char _PAGE_CONNECTING[] PROGMEM;
static const char _PAGE_OPENCREDT[] PROGMEM; static const char _PAGE_OPENCREDT[] PROGMEM;
static const char _PAGE_SUCCESS[] PROGMEM; static const char _PAGE_SUCCESS[] PROGMEM;
static const char _PAGE_RESETTING[] PROGMEM; static const char _PAGE_RESETTING[] PROGMEM;
@ -297,6 +308,7 @@ class AutoConnect {
String _token_CSS_INPUT_BUTTON(PageArgument& args); String _token_CSS_INPUT_BUTTON(PageArgument& args);
String _token_CSS_INPUT_TEXT(PageArgument& args); String _token_CSS_INPUT_TEXT(PageArgument& args);
String _token_CSS_TABLE(PageArgument& args); String _token_CSS_TABLE(PageArgument& args);
String _token_CSS_SPINNER(PageArgument& args);
String _token_CSS_LUXBAR(PageArgument& args); String _token_CSS_LUXBAR(PageArgument& args);
String _token_HEAD(PageArgument& args); String _token_HEAD(PageArgument& args);
String _token_MENU_PRE(PageArgument& args); String _token_MENU_PRE(PageArgument& args);
@ -323,6 +335,7 @@ class AutoConnect {
String _token_OPEN_SSID(PageArgument& args); String _token_OPEN_SSID(PageArgument& args);
String _token_UPTIME(PageArgument& args); String _token_UPTIME(PageArgument& args);
String _token_BOOTURI(PageArgument& args); String _token_BOOTURI(PageArgument& args);
String _token_CURRENT_SSID(PageArgument& args);
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266)
friend class ESP8266WebServer; friend class ESP8266WebServer;

@ -86,21 +86,26 @@
#define AUTOCONNECT_URI_SUCCESS AUTOCONNECT_URI "/success" #define AUTOCONNECT_URI_SUCCESS AUTOCONNECT_URI "/success"
#define AUTOCONNECT_URI_FAIL AUTOCONNECT_URI "/fail" #define AUTOCONNECT_URI_FAIL AUTOCONNECT_URI "/fail"
// Time-out limitation when AutoConnect::begin // Time-out limitation when AutoConnect::begin [ms]
#ifndef AUTOCONNECT_TIMEOUT #ifndef AUTOCONNECT_TIMEOUT
#define AUTOCONNECT_TIMEOUT 30000 #define AUTOCONNECT_TIMEOUT 30000
#endif // !AUTOCONNECT_TIMEOUT #endif // !AUTOCONNECT_TIMEOUT
// Captive portal timeout value // Captive portal timeout value [ms]
#ifndef AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT #ifndef AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT
#define AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT 0 #define AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT 0
#endif // !AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT #endif // !AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT
// Advance wait time // Advance wait time [s]
#ifndef AUTOCONNECT_STARTUPTIME #ifndef AUTOCONNECT_STARTUPTIME
#define AUTOCONNECT_STARTUPTIME (AUTOCONNECT_TIMEOUT/1000) #define AUTOCONNECT_STARTUPTIME (AUTOCONNECT_TIMEOUT/1000)
#endif // !AUTOCONNECT_STARTUPTIME #endif // !AUTOCONNECT_STARTUPTIME
// Response wait time until requesting a result of connection attempt [s] as String
#ifndef AUTOCONNECT_RESPONSEREQUEST_TIMEOUT
#define AUTOCONNECT_RESPONSEREQUEST_TIMEOUT "7"
#endif // !AUTOCONNECT_RESPONSEREQUEST_TIMEOUT
// Default HTTP port // Default HTTP port
#ifndef AUTOCONNECT_HTTPPORT #ifndef AUTOCONNECT_HTTPPORT
#define AUTOCONNECT_HTTPPORT 80 #define AUTOCONNECT_HTTPPORT 80
@ -111,6 +116,11 @@
#define AUTOCONNECT_DNSPORT 53 #define AUTOCONNECT_DNSPORT 53
#endif // !AUTOCONNECT_DNSPORT #endif // !AUTOCONNECT_DNSPORT
// http response transfer method
#ifndef AUTOCONNECT_HTTP_TRANSFER
#define AUTOCONNECT_HTTP_TRANSFER PB_ByteStream
#endif // !AUTOCONNECT_HTTP_TRANSFER
// Explicitly avoiding unused warning with token handler of PageBuilder // Explicitly avoiding unused warning with token handler of PageBuilder
#define AC_UNUSED(expr) do { (void)(expr); } while (0) #define AC_UNUSED(expr) do { (void)(expr); } while (0)

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save