diff --git a/src/AutoConnect.cpp b/src/AutoConnect.cpp index 294c9f0..d05d8cf 100644 --- a/src/AutoConnect.cpp +++ b/src/AutoConnect.cpp @@ -3,7 +3,7 @@ * @file AutoConnect.cpp * @author hieromon@gmail.com * @version 0.9.7 - * @date 2018-11-17 + * @date 2019-01-21 * @copyright MIT license. */ @@ -54,6 +54,9 @@ void AutoConnect::_initialize() { _menuTitle = String(AUTOCONNECT_MENU_TITLE); _connectTimeout = AUTOCONNECT_TIMEOUT; memset(&_credential, 0x00, sizeof(struct station_config)); +#ifdef ARDUINO_ARCH_ESP32 + _disconnectEventId = -1; // The member available for ESP32 only +#endif _aux.release(); } @@ -81,12 +84,11 @@ bool AutoConnect::begin() { * @param ssid SSID to be connected. * @param passphrase Password for connection. * @param timeout A time out value in milliseconds for waiting connection. - * @retval true Connection established, AutoConnect service started with WIFI_STA mode. - * @retval false Could not connected, Captive portal started with WIFI_AP_STA mode. + * @return true Connection established, AutoConnect service started with WIFI_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 cs; - bool hasTimeout; // Overwrite for the current timeout value. _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. WiFi.mode(WIFI_AP_STA); - while (WiFi.getMode() != WIFI_AP_STA) + while (WiFi.getMode() != WIFI_AP_STA) { + delay(1); yield(); + } // Connection unsuccessful, launch the captive portal. #if defined(ARDUINO_ARCH_ESP8266) @@ -176,15 +180,21 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long } #endif 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); yield(); - } + } while (WiFi.softAPIP() == IPAddress(0, 0, 0, 0)); #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))) { _config(); } #endif + if (_apConfig.apip != IPAddress(0, 0, 0, 0)) { + do { + delay(100); + yield(); + } while (WiFi.softAPIP() != _apConfig.apip); + } _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()); @@ -201,15 +211,14 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long _startDNSServer(); // Start the captive portal to make a new connection - hasTimeout = false; + bool hasTimeout = false; _portalAccessPeriod = millis(); while (WiFi.status() != WL_CONNECTED && !_rfReset) { handleClient(); // Force execution of queued processes. yield(); // Check timeout - if (_hasTimeout(_apConfig.portalTimeout)) { - hasTimeout = true; + if ((hasTimeout = _hasTimeout(_apConfig.portalTimeout))) { AC_DBG("CP timeout exceeded:%ld\n", millis() - _portalAccessPeriod); break; } @@ -220,6 +229,7 @@ bool AutoConnect::begin(const char* ssid, const char* passphrase, unsigned long if (cs) { _dnsServer->stop(); _dnsServer.reset(); + AC_DBG("DNS server stopped\n"); } // Captive portal staying time exceeds timeout, // Close the portal if an option for keeping the portal is false. @@ -305,8 +315,10 @@ void AutoConnect::end() { if (_webServer) { switch (_webServerAlloc) { case AC_WEBSERVER_HOSTED: - if (_dnsServer) + if (_dnsServer) { + _dnsServer->stop(); _dnsServer.reset(); + } _webServer.reset(); break; case AC_WEBSERVER_PARASITIC: @@ -379,7 +391,7 @@ void AutoConnect::_startWebServer() { // here, Prepare PageBuilders for captive portal if (!_responsePage) { _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->insert(*_webServer); @@ -428,8 +440,8 @@ void AutoConnect::handleRequest() { // Handling processing requests to AutoConnect. if (_rfConnect) { // Leave from the AP currently. -// if (WiFi.status() == WL_CONNECTED) -// _disconnectWiFi(true); + if (WiFi.status() == WL_CONNECTED) + _disconnectWiFi(true); // An attempt to establish a new AP. AC_DBG("Request for %s\n", reinterpret_cast(_credential.ssid)); @@ -446,6 +458,9 @@ void AutoConnect::handleRequest() { credit.save(&_credential); AC_DBG("%s credential saved\n", reinterpret_cast(_credential.ssid)); } + + // Ensures that keeps a connection with the current AP while the portal behaves. + _setReconnect(AC_RECONNECT_SET); } else AC_DBG("%s has no BSSID, saving is unavailable\n", reinterpret_cast(_credential.ssid)); @@ -456,7 +471,7 @@ void AutoConnect::handleRequest() { _rsConnect = WiFi.status(); _disconnectWiFi(false); while (WiFi.status() != WL_IDLE_STATUS && WiFi.status() != WL_DISCONNECTED) { - delay(10); + delay(1); yield(); } } @@ -474,6 +489,7 @@ void AutoConnect::handleRequest() { if (_rfDisconnect) { // Disconnect from the current AP. + _waitForEndTransmission(); _stopPortal(); _disconnectWiFi(false); while (WiFi.status() == WL_CONNECTED) { @@ -533,7 +549,7 @@ void AutoConnect::onNotFound(WebServerClass::THandlerFunction fn) { /** * 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() { AutoConnectCredential credential(_apConfig.boundaryOffset); @@ -570,8 +586,9 @@ void AutoConnect::_stopPortal() { delay(1000); } + _setReconnect(AC_RECONNECT_RESET); WiFi.softAPdisconnect(false); - AC_DBG("SoftAP stopped\n"); + AC_DBG("Portal stopped\n"); } /** @@ -593,6 +610,10 @@ bool AutoConnect::_captivePortal() { /** * 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) { uint8_t staNum; @@ -629,11 +650,11 @@ void AutoConnect::_handleNotFound() { else { PageElement page404(_PAGE_404, { { "HEAD", std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1) } }); String html = page404.build(); - _webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate", true); - _webServer->sendHeader("Pragma", "no-cache"); - _webServer->sendHeader("Expires", "-1"); - _webServer->sendHeader("Content-Length", String(html.length())); - _webServer->send(404, "text/html", html); + _webServer->sendHeader(F("Cache-Control"), F("no-cache, no-store, must-revalidate"), true); + _webServer->sendHeader(F("Pragma"), F("no-cache")); + _webServer->sendHeader(F("Expires"), F("-1")); + _webServer->sendHeader(F("Content-Length"), String(html.length())); + _webServer->send(404, F("text/html"), html); } } } @@ -664,7 +685,7 @@ String AutoConnect::_induceDisconnect(PageArgument& args) { * handling of the current request by PageBuilder triggered by handleClient(). * If "Credential" exists in POST parameter, it reads from EEPROM. * @param args http request arguments. - * @retval A redirect response including "Location:" header. + * @return A redirect response including "Location:" header. */ String AutoConnect::_induceConnect(PageArgument& args) { // 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); strncpy(reinterpret_cast(_credential.ssid), reinterpret_cast(entry.ssid), sizeof(_credential.ssid)); strncpy(reinterpret_cast(_credential.password), reinterpret_cast(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 { // Credential had by the post parameter. @@ -685,17 +706,34 @@ String AutoConnect::_induceConnect(PageArgument& args) { // Turn on the trigger to start WiFi.begin(). _rfConnect = true; + _menuTitle = String("Connecting"); + +// Since v0.9.7, the redirect method changed from a 302 response to the +// meta tag with refresh attribute. +// This approach for ESP32 makes an inefficient choice. The waiting +// procedure for a connection attempt should be the server side. Also, +// the proper value of waiting time until refreshing is unknown. But +// AutoConnect cannot avoid the following error as affairs stand now +// that occurs at connection establishment. +// [WiFiClient.cpp:463] connected(): Disconnected: RES: 0, ERR: 128 +// 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. - //_webServer->sendHeader("Location", String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT), true); - String url = String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT); - _webServer->sendHeader("Location", url, true); - //_webServer->sendHeader("Connection", "keep-alive"); - _webServer->send(302, "text/plain", ""); - _webServer->client().flush(); - _webServer->client().stop(); - _responsePage->cancel(); - + // 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(""); } @@ -704,11 +742,25 @@ String AutoConnect::_induceConnect(PageArgument& args) { * A destination as _redirectURI is indicated by loop to establish connection. */ String AutoConnect::_invokeResult(PageArgument& args) { - String redirect = String("http://") + _currentHostIP.toString() + _redirectURI; - _webServer->sendHeader("Location", redirect, true); - _webServer->send(302, "text/plain", ""); - _webServer->client().flush(); + String redirect = String(F("http://")); + // The host address to which the connection result for ESP32 responds + // changed from v0.9.7. This change is a measure according to the + // 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().flush(); + _waitForEndTransmission(); // Wait for response transmission complete _responsePage->cancel(); return String(""); } @@ -724,8 +776,8 @@ bool AutoConnect::_classifyHandle(HTTPMethod method, String uri) { _portalAccessPeriod = millis(); AC_DBG("Host:%s, URI:%s", _webServer->hostHeader().c_str(), uri.c_str()); - // When handleClient calls RequestHandler, the parsed http argument remains - // the previous request. + // When handleClient calls RequestHandler, the parsed http argument + // remains the previous request. // If the current request argument contains AutoConnectElement, it is // the form data of the AutoConnectAux page and with this timing save // the value of each element. @@ -796,7 +848,7 @@ bool AutoConnect::_isIP(String ipStr) { /** * Convert MAC address in uint8_t array to Sting XX:XX:XX:XX:XX:XX format. * @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 macAddr = String(""); @@ -813,7 +865,7 @@ String AutoConnect::_toMACAddressString(const uint8_t mac[]) { /** * Convert dBm to the wifi signal quality. * @param rssi dBm. - * @retval a signal quality percentage. + * @return A signal quality percentage. */ unsigned int AutoConnect::_toWiFiQuality(int32_t rssi) { unsigned int qu; @@ -831,7 +883,7 @@ unsigned int AutoConnect::_toWiFiQuality(int32_t rssi) { /** * Wait for establishment of the connection until the specified time expires. * @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 wifiStatus; @@ -850,6 +902,60 @@ wl_status_t AutoConnect::_waitForConnect(unsigned long timeout) { 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(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(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(millis() - lt)); +#endif +} + /** * Disconnects the station from an associated access point. * @param wifiOff The station mode turning switch. @@ -860,6 +966,8 @@ void AutoConnect::_disconnectWiFi(bool wifiOff) { #elif defined(ARDUINO_ARCH_ESP32) WiFi.disconnect(wifiOff, true); #endif - while (WiFi.status() == WL_CONNECTED) - delay(100); + while (WiFi.status() == WL_CONNECTED) { + delay(1); + yield(); + } } diff --git a/src/AutoConnect.h b/src/AutoConnect.h index 7d9f91e..530a84d 100644 --- a/src/AutoConnect.h +++ b/src/AutoConnect.h @@ -3,7 +3,7 @@ * @file AutoConnect.h * @author hieromon@gmail.com * @version 0.9.7 - * @date 2018-11-17 + * @date 2019-01-21 * @copyright MIT license. */ @@ -199,6 +199,10 @@ class AutoConnect { AC_WEBSERVER_HOSTED }; typedef enum _webServerAllocateType AC_WEBSERVER_TYPE; + typedef enum { + AC_RECONNECT_SET, + AC_RECONNECT_RESET + } AC_STARECONNECT_t; void _initialize(); bool _config(); void _startWebServer(); @@ -224,7 +228,9 @@ class AutoConnect { bool _hasTimeout(unsigned long timeout); bool _isIP(String ipStr); wl_status_t _waitForConnect(unsigned long timeout); + void _waitForEndTransmission(void); void _disconnectWiFi(bool wifiOff); + void _setReconnect(const AC_STARECONNECT_t order); /** Utilities */ static uint32_t _getChipId(); @@ -262,6 +268,9 @@ class AutoConnect { bool _rfDisconnect; /**< URI /disc requested */ bool _rfReset; /**< URI /reset requested */ 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. */ String _uri; /**< Requested URI */ @@ -276,6 +285,7 @@ class AutoConnect { static const char _CSS_INPUT_BUTTON[] PROGMEM; static const char _CSS_INPUT_TEXT[] PROGMEM; static const char _CSS_TABLE[] PROGMEM; + static const char _CSS_SPINNER[] PROGMEM; static const char _CSS_LUXBAR[] PROGMEM; static const char _ELM_HTML_HEAD[] PROGMEM; static const char _ELM_MENU_PRE[] PROGMEM; @@ -283,6 +293,7 @@ class AutoConnect { static const char _ELM_MENU_POST[] PROGMEM; static const char _PAGE_STAT[] PROGMEM; static const char _PAGE_CONFIGNEW[] PROGMEM; + static const char _PAGE_CONNECTING[] PROGMEM; static const char _PAGE_OPENCREDT[] PROGMEM; static const char _PAGE_SUCCESS[] PROGMEM; static const char _PAGE_RESETTING[] PROGMEM; @@ -297,6 +308,7 @@ class AutoConnect { String _token_CSS_INPUT_BUTTON(PageArgument& args); String _token_CSS_INPUT_TEXT(PageArgument& args); String _token_CSS_TABLE(PageArgument& args); + String _token_CSS_SPINNER(PageArgument& args); String _token_CSS_LUXBAR(PageArgument& args); String _token_HEAD(PageArgument& args); String _token_MENU_PRE(PageArgument& args); @@ -323,6 +335,8 @@ class AutoConnect { String _token_OPEN_SSID(PageArgument& args); String _token_UPTIME(PageArgument& args); String _token_BOOTURI(PageArgument& args); + String _token_CURRENT_SSID(PageArgument& args); + String _token_RESULT_URI(PageArgument& args); #if defined(ARDUINO_ARCH_ESP8266) friend class ESP8266WebServer; diff --git a/src/AutoConnectDefs.h b/src/AutoConnectDefs.h index a222ca2..ad69bc8 100644 --- a/src/AutoConnectDefs.h +++ b/src/AutoConnectDefs.h @@ -86,21 +86,26 @@ #define AUTOCONNECT_URI_SUCCESS AUTOCONNECT_URI "/success" #define AUTOCONNECT_URI_FAIL AUTOCONNECT_URI "/fail" -// Time-out limitation when AutoConnect::begin +// Time-out limitation when AutoConnect::begin [ms] #ifndef AUTOCONNECT_TIMEOUT #define AUTOCONNECT_TIMEOUT 30000 #endif // !AUTOCONNECT_TIMEOUT -// Captive portal timeout value +// Captive portal timeout value [ms] #ifndef AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT #define AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT 0 #endif // !AUTOCONNECT_CAPTIVEPORTAL_TIMEOUT -// Advance wait time +// Advance wait time [s] #ifndef AUTOCONNECT_STARTUPTIME #define AUTOCONNECT_STARTUPTIME (AUTOCONNECT_TIMEOUT/1000) #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 #ifndef AUTOCONNECT_HTTPPORT #define AUTOCONNECT_HTTPPORT 80 @@ -111,6 +116,11 @@ #define AUTOCONNECT_DNSPORT 53 #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 #define AC_UNUSED(expr) do { (void)(expr); } while (0) diff --git a/src/AutoConnectPage.cpp b/src/AutoConnectPage.cpp index 13e7caa..98e4bbd 100644 --- a/src/AutoConnectPage.cpp +++ b/src/AutoConnectPage.cpp @@ -270,6 +270,45 @@ const char AutoConnect::_CSS_TABLE[] PROGMEM = { "}" }; +/**< SVG animation for spinner */ +const char AutoConnect::_CSS_SPINNER[] PROGMEM = { + ".spinner{" + "width:40px;" + "height:40px;" + "position:relative;" + "margin:100px auto;" + "}" + ".double-bounce1, .double-bounce2{" + "width:100%;" + "height:100%;" + "border-radius:50%;" + "background-color:#333;" + "opacity:0.6;" + "position:absolute;" + "top:0;" + "left:0;" + "-webkit-animation:sk-bounce 2.0s infinite ease-in-out;" + "animation:sk-bounce 2.0s infinite ease-in-out;" + "}" + ".double-bounce2{" + "-webkit-animation-delay: -1.0s;" + "animation-delay: -1.0s;" + "}" + "@-webkit-keyframes sk-bounce{" + "0%, 100% {-webkit-transform:scale(0.0)}" + "50% {-webkit-transform:scale(1.0)}" + "}" + "@keyframes sk-bounce{" + "0%, 100% {" + "transform:scale(0.0);" + "-webkit-transform:scale(0.0);" + "} 50% {" + "transform:scale(1.0);" + "-webkit-transform:scale(1.0);" + "}" + "}" +}; + /**< Common menu bar. This style quotes LuxBar. */ /**< balzss/luxbar is licensed under the MIT License https://github.com/balzss/luxbar */ const char AutoConnect::_CSS_LUXBAR[] PROGMEM = { @@ -668,6 +707,35 @@ const char AutoConnect::_PAGE_OPENCREDT[] PROGMEM = { "" }; +/**< A page that informs during a connection attempting. */ +const char AutoConnect::_PAGE_CONNECTING[] PROGMEM = { + "{{REQ}}" + "{{HEAD}}" + "" + "AutoConnect connecting" + "" + "" + "" + "" + "
" + "{{MENU_PRE}}" + "{{MENU_POST}}" + "
" + "
{{CUR_SSID}}
" + "
" + "
" + "" + "" +}; + /**< A page announcing that a connection has been established. */ const char AutoConnect::_PAGE_SUCCESS[] PROGMEM = { "{{HEAD}}" @@ -802,6 +870,7 @@ String AutoConnect::_token_CSS_ICON_LOCK(PageArgument& args) { AC_UNUSED(args); return String(FPSTR(_CSS_ICON_LOCK)); } + String AutoConnect::_token_CSS_INPUT_BUTTON(PageArgument& args) { AC_UNUSED(args); return String(FPSTR(_CSS_INPUT_BUTTON)); @@ -817,6 +886,11 @@ String AutoConnect::_token_CSS_TABLE(PageArgument& args) { return String(FPSTR(_CSS_TABLE)); } +String AutoConnect::_token_CSS_SPINNER(PageArgument& args) { + AC_UNUSED(args); + return String(FPSTR(_CSS_SPINNER)); +} + String AutoConnect::_token_HEAD(PageArgument& args) { AC_UNUSED(args); return String(FPSTR(_ELM_HTML_HEAD)); @@ -1093,6 +1167,15 @@ String AutoConnect::_token_BOOTURI(PageArgument& args) { return String(""); } +String AutoConnect::_token_CURRENT_SSID(PageArgument& args) { + AC_UNUSED(args); + return String(reinterpret_cast(_credential.ssid)); +} + +String AutoConnect::_token_RESULT_URI(PageArgument& args) { + AC_UNUSED(args); + return _webServer->client().localIP().toString() + String(AUTOCONNECT_URI_RESULT); +} /** * This function dynamically build up the response pages that conform to @@ -1156,9 +1239,17 @@ PageElement* AutoConnect::_setupPage(String uri) { else if (uri == String(AUTOCONNECT_URI_CONNECT)) { // Setup /auto/connect - elm->setMold("{{REQ}}"); + elm->setMold(_PAGE_CONNECTING); elm->addToken(String(FPSTR("REQ")), std::bind(&AutoConnect::_induceConnect, this, std::placeholders::_1)); - } + elm->addToken(String(FPSTR("HEAD")), std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("URI_RESULT")), std::bind(&AutoConnect::_token_RESULT_URI, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("CSS_BASE")), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("CSS_SPINNER")), std::bind(&AutoConnect::_token_CSS_SPINNER, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("CSS_LUXBAR")), std::bind(&AutoConnect::_token_CSS_LUXBAR, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("MENU_PRE")), std::bind(&AutoConnect::_token_MENU_PRE, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("MENU_POST")), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1)); + elm->addToken(String(FPSTR("CUR_SSID")), std::bind(&AutoConnect::_token_CURRENT_SSID, this, std::placeholders::_1)); + } else if (uri == String(AUTOCONNECT_URI_OPEN)) { // Setup /auto/open