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. 98
      src/AutoConnectPage.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.
*/
@ -51,9 +51,12 @@ void AutoConnect::_initialize() {
_rfReset = false;
_responsePage = nullptr;
_currentPageElement = nullptr;
_menuTitle = String(AUTOCONNECT_MENU_TITLE);
_menuTitle = String(F(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<const char*>(_credential.ssid));
@ -438,7 +450,7 @@ void AutoConnect::handleRequest() {
if (WiFi.BSSID() != NULL) {
memcpy(_credential.bssid, WiFi.BSSID(), sizeof(station_config::bssid));
_currentHostIP = WiFi.localIP();
_redirectURI = String(AUTOCONNECT_URI_SUCCESS);
_redirectURI = String(F(AUTOCONNECT_URI_SUCCESS));
// Save current credential
if (_apConfig.autoSave == AC_SAVECREDENTIAL_AUTO) {
@ -446,17 +458,20 @@ void AutoConnect::handleRequest() {
credit.save(&_credential);
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
AC_DBG("%s has no BSSID, saving is unavailable\n", reinterpret_cast<const char*>(_credential.ssid));
}
else {
_currentHostIP = WiFi.softAPIP();
_redirectURI = String(AUTOCONNECT_URI_FAIL);
_redirectURI = String(F(AUTOCONNECT_URI_FAIL));
_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");
}
/**
@ -581,9 +598,9 @@ void AutoConnect::_stopPortal() {
bool AutoConnect::_captivePortal() {
String hostHeader = _webServer->hostHeader();
if (!_isIP(hostHeader) && (hostHeader != WiFi.localIP().toString())) {
String location = String("http://") + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI);
_webServer->sendHeader("Location", location, true);
_webServer->send(302, "text/plain", "");
String location = String(F("http://")) + _webServer->client().localIP().toString() + String(AUTOCONNECT_URI);
_webServer->sendHeader(F("Location"), location, true);
_webServer->send(302, F("text/plain"), "");
_webServer->client().flush();
_webServer->client().stop();
return true;
@ -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);
}
}
}
@ -645,7 +666,7 @@ void AutoConnect::_handleNotFound() {
*/
String AutoConnect::_induceReset(PageArgument& args) {
_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().
* 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<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));
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.
@ -686,16 +707,32 @@ String AutoConnect::_induceConnect(PageArgument& args) {
// Turn on the trigger to start WiFi.begin().
_rfConnect = true;
// 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();
// 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.
// 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 +741,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 +775,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 +847,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 +864,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 +882,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 +901,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<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.
* @param wifiOff The station mode turning switch.
@ -860,6 +965,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();
}
}

@ -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,7 @@ class AutoConnect {
String _token_OPEN_SSID(PageArgument& args);
String _token_UPTIME(PageArgument& args);
String _token_BOOTURI(PageArgument& args);
String _token_CURRENT_SSID(PageArgument& args);
#if defined(ARDUINO_ARCH_ESP8266)
friend class ESP8266WebServer;

@ -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)

@ -3,7 +3,7 @@
* @file AutoConnectPage.h
* @author hieromon@gmail.com
* @version 0.9.7
* @date 2018-11-17
* @date 2019-01-23
* @copyright MIT license.
*/
@ -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 = {
@ -511,7 +550,7 @@ const char AutoConnect::_PAGE_404[] PROGMEM = {
/**< The page that started the reset. */
const char AutoConnect::_PAGE_RESETTING[] PROGMEM = {
"{{HEAD}}"
"<meta http-equiv=\"refresh\" content=\"{{UPTIME}};URL={{BOOTURI}}\">"
"<meta http-equiv=\"refresh\" content=\"{{UPTIME}};url={{BOOTURI}}\">"
"<title>AutoConnect resetting</title>"
"</head>"
"<body>"
@ -668,6 +707,37 @@ const char AutoConnect::_PAGE_OPENCREDT[] PROGMEM = {
"</html>"
};
/**< A page that informs during a connection attempting. */
const char AutoConnect::_PAGE_CONNECTING[] PROGMEM = {
"{{REQ}}"
"{{HEAD}}"
"<meta http-equiv=\"refresh\" content=\"0;url=" AUTOCONNECT_URI_RESULT "\">"
"<title>AutoConnect connecting</title>"
"<style type=\"text/css\">"
"{{CSS_BASE}}"
"{{CSS_SPINNER}}"
"{{CSS_LUXBAR}}"
"</style>"
"<script type=\"text/javascript\">"
"setTimeout(\"link()\"," AUTOCONNECT_RESPONSEREQUEST_TIMEOUT ");"
"function link(){"
"location.href='" AUTOCONNECT_URI_RESULT "';"
"</script>"
"</head>"
"<body style=\"padding-top:58px;\">"
"<div class=\"container\">"
"{{MENU_PRE}}"
"{{MENU_POST}}"
"<div class=\"spinner\">"
"<div style=\"position:absolute;left:-100%;right:-100%;text-align:center;margin:10px auto;font-weight:bold;color:#4169e1;\">{{CUR_SSID}}</div>"
"<div class=\"double-bounce1\"></div>"
"<div class=\"double-bounce2\"></div>"
"</div>"
"</div>"
"</body>"
"</html>"
};
/**< A page announcing that a connection has been established. */
const char AutoConnect::_PAGE_SUCCESS[] PROGMEM = {
"{{HEAD}}"
@ -764,8 +834,8 @@ const char AutoConnect::_PAGE_DISCONN[] PROGMEM = {
"<body style=\"padding-top:58px;\">"
"<div class=\"container\">"
"{{MENU_PRE}}"
"{{MENU_AUX}}"
"{{MENU_POST}}"
"</div>"
"</body>"
"</html>"
};
@ -802,6 +872,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 +888,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 +1169,10 @@ String AutoConnect::_token_BOOTURI(PageArgument& args) {
return String("");
}
String AutoConnect::_token_CURRENT_SSID(PageArgument& args) {
AC_UNUSED(args);
return String(reinterpret_cast<char*>(_credential.ssid));
}
/**
* This function dynamically build up the response pages that conform to
@ -1156,8 +1236,16 @@ PageElement* AutoConnect::_setupPage(String uri) {
else if (uri == String(AUTOCONNECT_URI_CONNECT)) {
// Setup /auto/connect
elm->setMold("{{REQ}}");
_menuTitle = FPSTR("Connecting");
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("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)) {
@ -1183,7 +1271,6 @@ PageElement* AutoConnect::_setupPage(String uri) {
elm->addToken(String(FPSTR("CSS_BASE")), std::bind(&AutoConnect::_token_CSS_BASE, 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_AUX")), std::bind(&AutoConnect::_token_MENU_AUX, this, std::placeholders::_1));
elm->addToken(String(FPSTR("MENU_POST")), std::bind(&AutoConnect::_token_MENU_POST, this, std::placeholders::_1));
}
else if (uri == String(AUTOCONNECT_URI_RESET)) {
@ -1224,6 +1311,7 @@ PageElement* AutoConnect::_setupPage(String uri) {
else if (uri == String(AUTOCONNECT_URI_FAIL)) {
// Setup /auto/fail
_menuTitle = FPSTR("Failed");
elm->setMold(_PAGE_FAIL);
elm->addToken(String(FPSTR("HEAD")), std::bind(&AutoConnect::_token_HEAD, this, std::placeholders::_1));
elm->addToken(String(FPSTR("CSS_BASE")), std::bind(&AutoConnect::_token_CSS_BASE, this, std::placeholders::_1));

Loading…
Cancel
Save