/* FSPage.ino - Example PageBuilder with HTML page stored SPIFFS Copyright (c) 2017 Hieromon Ikasamo. All rights reserved. This software is released under the MIT License. http://opensource.org/licenses/mit-license.php This is a sample sketch that connects to an existing WiFi router already connected Internet and makes ESP8266 join the network. After writing this sketch, probably you can access 192.168.4.1 from your smartphone and it will be listed the WiFi AP that you can connect. You can select and connect the listed SSID. It is using Web page transition in the dialogue procedure for connecting to SSID, and its HTML source is stored in SPIFFS or LittleFS file. Before executing this sketch, you need to upload the data folder to SPIFFS or LittleFS of ESP8266 by the tool as "ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE. */ #if defined(ARDUINO_ARCH_ESP8266) #include #include #define WIFI_EVENT_STA_CONNECTED WIFI_EVENT_STAMODE_CONNECTED #define WIFI_EVENT_STA_DISCONNECTED WIFI_EVENT_STAMODE_DISCONNECTED #define WIFI_EVENT_AP_STACONNECTED WIFI_EVENT_SOFTAPMODE_STACONNECTED #define WIFI_EVENT_AP_STADISCONNECTED WIFI_EVENT_SOFTAPMODE_STADISCONNECTED #define WIFI_EVENT_ALL WIFI_EVENT_ANY #define WIFI_AUTH_OPEN ENC_TYPE_NONE #elif defined(ARDUINO_ARCH_ESP32) #include #include #define WIFI_EVENT_STA_CONNECTED SYSTEM_EVENT_STA_CONNECTED #define WIFI_EVENT_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED #define WIFI_EVENT_AP_STACONNECTED SYSTEM_EVENT_AP_STACONNECTED #define WIFI_EVENT_AP_STADISCONNECTED SYSTEM_EVENT_AP_STADISCONNECTED #define WIFI_EVENT_ALL SYSTEM_EVENT_MAX #endif #include "PageBuilder.h" #define AP_NAME "esp-ap" #define AP_PASS "12345678" #if defined(ARDUINO_ARCH_ESP8266) #ifdef PB_USE_SPIFFS #include FS& FlashFile = SPIFFS; #else #include FS& FlashFile = LittleFS; #endif ESP8266WebServer server; #elif defined(ARDUINO_ARCH_ESP32) #include #include fs::SPIFFSFS& FlashFile = SPIFFS; WebServer server; #endif bool CONNECT_REQ; String CONN_SSID; String CONN_PSK; String REDIRECT_URI; String CURRENT_HOST; // Page URIs #define URI_ROOT "/" #define URI_JOIN "/join" #define URI_REQ "/request" #define URI_RESULT "/result" #define URI_WELCOME "/welcome" #define URI_FAILED "/failed" // Connection request redirector String reqConnect(PageArgument&); PageElement REQ_ELM("{{REQ}}", { {"REQ", reqConnect} }); PageBuilder REQ_PAGE(URI_REQ, {REQ_ELM}); // Connection result redirector String resConnect(PageArgument&); PageElement CONNRES_ELM("{{CONN}}", { {"CONN", resConnect} }); PageBuilder CONNRES_PAGE(URI_RESULT, {CONNRES_ELM}); // Convert RSSI dBm to signal strength unsigned int toWiFiQuality(int32_t rssi) { unsigned int qu; if (rssi <= -100) qu = 0; else if (rssi >= -50) qu = 100; else qu = 2 * (rssi + 100); return qu; } // This callback function would be invoked from the root page and scans nearby // WiFi-AP to make a connectable list. String listSSID(PageArgument& args) { String s_ssid_list = ""; int8_t nn = WiFi.scanNetworks(false, true); for (uint8_t i = 0; i < nn; i++) { String ssid = WiFi.SSID(i); if (ssid.length() == 0) ssid = "?"; s_ssid_list += "
" + ssid + ""; s_ssid_list += String(toWiFiQuality(WiFi.RSSI(i))) + "%"; if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) s_ssid_list += ""; s_ssid_list += "
"; } CONNECT_REQ = false; return s_ssid_list; } // Accepting connection request. // Flag the occurrence of the connection request and response a redirect to // the connection result page. String reqConnect(PageArgument& args) { if (CONN_SSID == "?") CONN_SSID = args.arg("ssid"); CONN_PSK = args.arg("psk"); // Leave from the AP currently. if (WiFi.status() == WL_CONNECTED) { WiFi.disconnect(); while (WiFi.status() == WL_CONNECTED); } // Available upon connection request. CONNECT_REQ = true; REDIRECT_URI = ""; CURRENT_HOST = ""; // Redirect http request to connection result page. server.sendHeader("Location", String("http://") + WiFi.softAPIP().toString() + String(URI_RESULT), true); server.send(302, "text/plain", ""); REQ_PAGE.cancel(); return ""; } // Performing AP connection procedure. void connWiFi() { // Starts connecting the ap as WIFI_STA Serial.print("Connect to " + CONN_SSID + "/" + CONN_PSK + " "); WiFi.begin(CONN_SSID.c_str(), CONN_PSK.c_str()); unsigned long tm = millis(); do { delay(500); Serial.print('.'); if (millis() - tm > 30000) break; } while (WiFi.status() != WL_CONNECTED); Serial.print(String(WiFi.status()) + ":"); // Dynamically switch the result page URL according to the connection result. // If it connected to the AP, redirect localIP () as the host address. // Connection failed, redirect to a failed page addressed on softAPIP(). if (WiFi.status() == WL_CONNECTED) { // Connection established, makes a response page into a new IP address. CURRENT_HOST = WiFi.localIP().toString(); REDIRECT_URI = URI_WELCOME; Serial.println("OK"); } else { // Connection refused, a fails page keeps on softAPIP. CURRENT_HOST = WiFi.softAPIP().toString(); REDIRECT_URI = URI_FAILED; Serial.println("Failed"); } } // Responds redirect destination according to the connection result of success // or failure to the AP. String resConnect(PageArgument& args) { String redirect = String("http://") + CURRENT_HOST + REDIRECT_URI; Serial.println("Redirect: " + redirect); server.sendHeader("Location", redirect, true); server.sendHeader("Connection", "keep-alive"); server.send(302, "text/plain", ""); server.client().stop(); CONNRES_PAGE.cancel(); Serial.println(); WiFi.printDiag(Serial); return ""; } // WiFi event determination and echo back. void broadcastEvent(WiFiEvent_t event) { static const char eventText_APSTA_CONN[] PROGMEM = "SoftAP station connected."; static const char eventText_APSTA_DISC[] PROGMEM = "SoftAP station disconnected."; static const char eventText_STA_CONN[] PROGMEM = "WiFi AP connected."; static const char eventText_STA_DISC[] PROGMEM = "WiFi AP disconnected."; const char* eventText; switch (event) { case WIFI_EVENT_AP_STACONNECTED: eventText = eventText_APSTA_CONN; break; case WIFI_EVENT_AP_STADISCONNECTED: eventText = eventText_APSTA_DISC; break; case WIFI_EVENT_STA_CONNECTED: eventText = eventText_STA_CONN; break; case WIFI_EVENT_STA_DISCONNECTED: eventText = eventText_STA_DISC; break; default: eventText = nullptr; } if (eventText) Serial.println(String("[event] ") + String(FPSTR(eventText))); } // Get an architecture of compiled String getArch(PageArgument& args) { #if defined(ARDUINO_ARCH_ESP8266) return "ESP8266"; #elif defined(ARDUINO_ARCH_ESP32) return "ESP32"; #endif } // HTML page declarations. // root page PageElement SSID_ELM("file:/root.htm", { { "SSID_LIST", listSSID }, { "URI_ROOT", [](PageArgument& args) { return URI_ROOT; }} }); PageBuilder SSID_PAGE(URI_ROOT, { SSID_ELM }); // SSID & Password entry page PageElement ENTRY_ELM("file:/entry.htm", { { "ESP_ARCH", getArch }, { "ENTRY", [](PageArgument& args) { CONN_SSID = args.arg("ssid"); return "AP"; } }, { "URI_REQ", [](PageArgument& args) { return URI_REQ; } }, { "SSID", [](PageArgument& args) { return CONN_SSID == "?" ? "placeholder=\"SSID\"" : String("value=\"" + CONN_SSID + "\" readonly"); } }, { "PSK", [](PageArgument& args) { return args.arg("psk_type") != "7" ? "" : ""; } } }); PageBuilder ENTRY_PAGE(URI_JOIN, {ENTRY_ELM}); // Connection successful page PageElement WELCOME_ELM("file:/connect.htm", { { "ESP-AP", [](PageArgument& args) { return AP_NAME; } }, { "SSID", [](PageArgument& args) { return WiFi.SSID(); } }, { "IP", [](PageArgument& args) { return WiFi.localIP().toString(); } }, { "GATEWAY", [](PageArgument& args) { return WiFi.gatewayIP().toString(); } }, { "SUBNET", [](PageArgument& args) { return WiFi.subnetMask().toString(); } } }); PageBuilder WELCOME_PAGE(URI_WELCOME, {WELCOME_ELM}); // Connection failed page PageElement FAILED_ELM("file:/failed.htm", { { "SSID", [](PageArgument& args) { return CONN_SSID; } }, { "RESULT", [](PageArgument& args) { return String(WiFi.status()); } } }); PageBuilder FAILED_PAGE(URI_FAILED, {FAILED_ELM}); void setup() { delay(1000); Serial.begin(115200); Serial.println(); // Prepare HTML page SSID_PAGE.insert(server); ENTRY_PAGE.insert(server); REQ_PAGE.insert(server); CONNRES_PAGE.insert(server); WELCOME_PAGE.insert(server); FAILED_PAGE.insert(server); // Start WiFi soft AP. WiFi.softAPdisconnect(); WiFi.disconnect(); delay(100); WiFi.mode(WIFI_AP_STA); WiFi.softAP(AP_NAME, AP_PASS); while (WiFi.softAPIP() == IPAddress(0, 0, 0, 0)) { yield(); delay(100); } Serial.print(AP_NAME " started. IP:"); Serial.println(WiFi.softAPIP()); // Start http server. FlashFile.begin(); server.begin(); // Turn on WiFi event handling. // It is deprecated in ESP8266, but it remains because the alternative // API's onSoftAPModeStationConnected event does not fire properly in // SoftAP + STA mode. WiFi.onEvent(broadcastEvent, WIFI_EVENT_ALL); } void loop() { server.handleClient(); if (CONNECT_REQ) { connWiFi(); CONNECT_REQ = false; } }