From 72706c37a41941b3cb925dd8deb6c1149cac2e71 Mon Sep 17 00:00:00 2001 From: Shiven Mian Date: Sat, 17 Feb 2024 16:54:54 -0800 Subject: [PATCH 1/2] feat: added WiFi captive portal --- .../01OS/clients/esp32/wifi_captiveportal.ino | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 01OS/01OS/clients/esp32/wifi_captiveportal.ino diff --git a/01OS/01OS/clients/esp32/wifi_captiveportal.ino b/01OS/01OS/clients/esp32/wifi_captiveportal.ino new file mode 100644 index 0000000..2c772c2 --- /dev/null +++ b/01OS/01OS/clients/esp32/wifi_captiveportal.ino @@ -0,0 +1,190 @@ +#include //not needed in the arduino ide + +// Captive Portal +#include //https://github.com/me-no-dev/AsyncTCP using the latest dev version from @me-no-dev +#include +#include //https://github.com/me-no-dev/ESPAsyncWebServer using the latest dev version from @me-no-dev +#include //Used for mpdu_rx_disable android workaround + +// Pre reading on the fundamentals of captive portals https://textslashplain.com/2022/06/24/captive-portals/ + +const char *ssid = "captive"; // FYI The SSID can't have a space in it. +// const char * password = "12345678"; //Atleast 8 chars +const char *password = NULL; // no password + +#define MAX_CLIENTS 4 // ESP32 supports up to 10 but I have not tested it yet +#define WIFI_CHANNEL 6 // 2.4ghz channel 6 https://en.wikipedia.org/wiki/List_of_WLAN_channels#2.4_GHz_(802.11b/g/n/ax) + +const IPAddress localIP(4, 3, 2, 1); // the IP address the web server, Samsung requires the IP to be in public space +const IPAddress gatewayIP(4, 3, 2, 1); // IP address of the network should be the same as the local IP for captive portals +const IPAddress subnetMask(255, 255, 255, 0); // no need to change: https://avinetworks.com/glossary/subnet-mask/ + +const String localIPURL = "http://4.3.2.1"; // a string version of the local IP with http, used for redirecting clients to your webpage + +const char index_html[] PROGMEM = R"=====( + + + + ESP32 WiFi Setup + + + + +

WiFi Setup

+
+
+
+
+

+ +
+ + +)====="; + +DNSServer dnsServer; +AsyncWebServer server(80); + +void setUpDNSServer(DNSServer &dnsServer, const IPAddress &localIP) { +// Define the DNS interval in milliseconds between processing DNS requests +#define DNS_INTERVAL 30 + + // Set the TTL for DNS response and start the DNS server + dnsServer.setTTL(3600); + dnsServer.start(53, "*", localIP); +} + +void startSoftAccessPoint(const char *ssid, const char *password, const IPAddress &localIP, const IPAddress &gatewayIP) { +// Define the maximum number of clients that can connect to the server +#define MAX_CLIENTS 4 +// Define the WiFi channel to be used (channel 6 in this case) +#define WIFI_CHANNEL 6 + + // Set the WiFi mode to access point and station + WiFi.mode(WIFI_MODE_AP); + + // Define the subnet mask for the WiFi network + const IPAddress subnetMask(255, 255, 255, 0); + + // Configure the soft access point with a specific IP and subnet mask + WiFi.softAPConfig(localIP, gatewayIP, subnetMask); + + // Start the soft access point with the given ssid, password, channel, max number of clients + WiFi.softAP(ssid, password, WIFI_CHANNEL, 0, MAX_CLIENTS); + + // Disable AMPDU RX on the ESP32 WiFi to fix a bug on Android + esp_wifi_stop(); + esp_wifi_deinit(); + wifi_init_config_t my_config = WIFI_INIT_CONFIG_DEFAULT(); + my_config.ampdu_rx_enable = false; + esp_wifi_init(&my_config); + esp_wifi_start(); + vTaskDelay(100 / portTICK_PERIOD_MS); // Add a small delay +} + +void setUpWebserver(AsyncWebServer &server, const IPAddress &localIP) { + //======================== Webserver ======================== + // WARNING IOS (and maybe macos) WILL NOT POP UP IF IT CONTAINS THE WORD "Success" https://www.esp8266.com/viewtopic.php?f=34&t=4398 + // SAFARI (IOS) IS STUPID, G-ZIPPED FILES CAN'T END IN .GZ https://github.com/homieiot/homie-esp8266/issues/476 this is fixed by the webserver serve static function. + // SAFARI (IOS) there is a 128KB limit to the size of the HTML. The HTML can reference external resources/images that bring the total over 128KB + // SAFARI (IOS) popup browser has some severe limitations (javascript disabled, cookies disabled) + + // Required + server.on("/connecttest.txt", [](AsyncWebServerRequest *request) { request->redirect("http://logout.net"); }); // windows 11 captive portal workaround + server.on("/wpad.dat", [](AsyncWebServerRequest *request) { request->send(404); }); // Honestly don't understand what this is but a 404 stops win 10 keep calling this repeatedly and panicking the esp32 :) + + // Background responses: Probably not all are Required, but some are. Others might speed things up? + // A Tier (commonly used by modern systems) + server.on("/generate_204", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // android captive portal redirect + server.on("/redirect", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // microsoft redirect + server.on("/hotspot-detect.html", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // apple call home + server.on("/canonical.html", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // firefox captive portal call home + server.on("/success.txt", [](AsyncWebServerRequest *request) { request->send(200); }); // firefox captive portal call home + server.on("/ncsi.txt", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // windows call home + + // B Tier (uncommon) + // server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home + // server.on("/service/update2/json",[](AsyncWebServerRequest *request){request->send(200);}); //firefox? + // server.on("/chat",[](AsyncWebServerRequest *request){request->send(404);}); //No stop asking Whatsapp, there is no internet connection + // server.on("/startpage",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); + + // return 404 to webpage icon + server.on("/favicon.ico", [](AsyncWebServerRequest *request) { request->send(404); }); // webpage icon + + // Serve Basic HTML Page + server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse(200, "text/html", index_html); + response->addHeader("Cache-Control", "public,max-age=31536000"); // save this file to cache for 1 year (unless you refresh) + request->send(response); + Serial.println("Served Basic HTML Page"); + }); + + server.on("/setup", HTTP_POST, [](AsyncWebServerRequest *request) { + String ssid; + String password; + if (request->hasParam("ssid", true) && request->hasParam("password", true)) { + ssid = request->getParam("ssid", true)->value(); + password = request->getParam("password", true)->value(); + // Now connect to the WiFi network using the provided credentials + WiFi.begin(ssid.c_str(), password.c_str()); + // You may want to add some logic to check if the connection was successful + // and respond accordingly + request->send(200, "text/plain", "Connecting to " + ssid); + } else { + request->send(400, "text/plain", "Invalid request"); + } + }); + + // the catch all + server.onNotFound([](AsyncWebServerRequest *request) { + request->redirect(localIPURL); + Serial.print("onnotfound "); + Serial.print(request->host()); // This gives some insight into whatever was being requested on the serial monitor + Serial.print(" "); + Serial.print(request->url()); + Serial.print(" sent redirect to " + localIPURL + "\n"); + }); +} + +void setup() { + // Set the transmit buffer size for the Serial object and start it with a baud rate of 115200. + Serial.setTxBufferSize(1024); + Serial.begin(115200); + + // Wait for the Serial object to become available. + while (!Serial) + ; + + // Print a welcome message to the Serial port. + Serial.println("\n\nCaptive Test, V0.5.0 compiled " __DATE__ " " __TIME__ " by CD_FER"); //__DATE__ is provided by the platformio ide + Serial.printf("%s-%d\n\r", ESP.getChipModel(), ESP.getChipRevision()); + + startSoftAccessPoint(ssid, password, localIP, gatewayIP); + + setUpDNSServer(dnsServer, localIP); + + setUpWebserver(server, localIP); + server.begin(); + + Serial.print("\n"); + Serial.print("Startup Time:"); // should be somewhere between 270-350 for Generic ESP32 (D0WDQ6 chip, can have a higher startup time on first boot) + Serial.println(millis()); + Serial.print("\n"); +} + +void loop() { + dnsServer.processNextRequest(); // I call this atleast every 10ms in my other projects (can be higher but I haven't tested it for stability) + delay(DNS_INTERVAL); // seems to help with stability, if you are doing other things in the loop this may not be needed + + // Check WiFi connection status + if (WiFi.status() == WL_CONNECTED) { + // If connected, you might want to do something, like printing the IP address + Serial.println("Connected to WiFi!"); + Serial.println("IP Address: " + WiFi.localIP().toString()); + Serial.println("SSID " + WiFi.SSID()); + } +} \ No newline at end of file From 25cf7c8284e7a14cc7a162ff93547563dd49d717 Mon Sep 17 00:00:00 2001 From: Zach Wener Date: Sat, 17 Feb 2024 18:58:22 -0800 Subject: [PATCH 2/2] feat: added wifi scanning --- .../01OS/clients/esp32/wifi_captiveportal.ino | 190 ------------- .../wifi_captiveportal/wifi_captiveportal.ino | 260 ++++++++++++++++++ 2 files changed, 260 insertions(+), 190 deletions(-) delete mode 100644 01OS/01OS/clients/esp32/wifi_captiveportal.ino create mode 100644 01OS/01OS/clients/esp32/wifi_captiveportal/wifi_captiveportal.ino diff --git a/01OS/01OS/clients/esp32/wifi_captiveportal.ino b/01OS/01OS/clients/esp32/wifi_captiveportal.ino deleted file mode 100644 index 2c772c2..0000000 --- a/01OS/01OS/clients/esp32/wifi_captiveportal.ino +++ /dev/null @@ -1,190 +0,0 @@ -#include //not needed in the arduino ide - -// Captive Portal -#include //https://github.com/me-no-dev/AsyncTCP using the latest dev version from @me-no-dev -#include -#include //https://github.com/me-no-dev/ESPAsyncWebServer using the latest dev version from @me-no-dev -#include //Used for mpdu_rx_disable android workaround - -// Pre reading on the fundamentals of captive portals https://textslashplain.com/2022/06/24/captive-portals/ - -const char *ssid = "captive"; // FYI The SSID can't have a space in it. -// const char * password = "12345678"; //Atleast 8 chars -const char *password = NULL; // no password - -#define MAX_CLIENTS 4 // ESP32 supports up to 10 but I have not tested it yet -#define WIFI_CHANNEL 6 // 2.4ghz channel 6 https://en.wikipedia.org/wiki/List_of_WLAN_channels#2.4_GHz_(802.11b/g/n/ax) - -const IPAddress localIP(4, 3, 2, 1); // the IP address the web server, Samsung requires the IP to be in public space -const IPAddress gatewayIP(4, 3, 2, 1); // IP address of the network should be the same as the local IP for captive portals -const IPAddress subnetMask(255, 255, 255, 0); // no need to change: https://avinetworks.com/glossary/subnet-mask/ - -const String localIPURL = "http://4.3.2.1"; // a string version of the local IP with http, used for redirecting clients to your webpage - -const char index_html[] PROGMEM = R"=====( - - - - ESP32 WiFi Setup - - - - -

WiFi Setup

-
-
-
-
-

- -
- - -)====="; - -DNSServer dnsServer; -AsyncWebServer server(80); - -void setUpDNSServer(DNSServer &dnsServer, const IPAddress &localIP) { -// Define the DNS interval in milliseconds between processing DNS requests -#define DNS_INTERVAL 30 - - // Set the TTL for DNS response and start the DNS server - dnsServer.setTTL(3600); - dnsServer.start(53, "*", localIP); -} - -void startSoftAccessPoint(const char *ssid, const char *password, const IPAddress &localIP, const IPAddress &gatewayIP) { -// Define the maximum number of clients that can connect to the server -#define MAX_CLIENTS 4 -// Define the WiFi channel to be used (channel 6 in this case) -#define WIFI_CHANNEL 6 - - // Set the WiFi mode to access point and station - WiFi.mode(WIFI_MODE_AP); - - // Define the subnet mask for the WiFi network - const IPAddress subnetMask(255, 255, 255, 0); - - // Configure the soft access point with a specific IP and subnet mask - WiFi.softAPConfig(localIP, gatewayIP, subnetMask); - - // Start the soft access point with the given ssid, password, channel, max number of clients - WiFi.softAP(ssid, password, WIFI_CHANNEL, 0, MAX_CLIENTS); - - // Disable AMPDU RX on the ESP32 WiFi to fix a bug on Android - esp_wifi_stop(); - esp_wifi_deinit(); - wifi_init_config_t my_config = WIFI_INIT_CONFIG_DEFAULT(); - my_config.ampdu_rx_enable = false; - esp_wifi_init(&my_config); - esp_wifi_start(); - vTaskDelay(100 / portTICK_PERIOD_MS); // Add a small delay -} - -void setUpWebserver(AsyncWebServer &server, const IPAddress &localIP) { - //======================== Webserver ======================== - // WARNING IOS (and maybe macos) WILL NOT POP UP IF IT CONTAINS THE WORD "Success" https://www.esp8266.com/viewtopic.php?f=34&t=4398 - // SAFARI (IOS) IS STUPID, G-ZIPPED FILES CAN'T END IN .GZ https://github.com/homieiot/homie-esp8266/issues/476 this is fixed by the webserver serve static function. - // SAFARI (IOS) there is a 128KB limit to the size of the HTML. The HTML can reference external resources/images that bring the total over 128KB - // SAFARI (IOS) popup browser has some severe limitations (javascript disabled, cookies disabled) - - // Required - server.on("/connecttest.txt", [](AsyncWebServerRequest *request) { request->redirect("http://logout.net"); }); // windows 11 captive portal workaround - server.on("/wpad.dat", [](AsyncWebServerRequest *request) { request->send(404); }); // Honestly don't understand what this is but a 404 stops win 10 keep calling this repeatedly and panicking the esp32 :) - - // Background responses: Probably not all are Required, but some are. Others might speed things up? - // A Tier (commonly used by modern systems) - server.on("/generate_204", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // android captive portal redirect - server.on("/redirect", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // microsoft redirect - server.on("/hotspot-detect.html", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // apple call home - server.on("/canonical.html", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // firefox captive portal call home - server.on("/success.txt", [](AsyncWebServerRequest *request) { request->send(200); }); // firefox captive portal call home - server.on("/ncsi.txt", [](AsyncWebServerRequest *request) { request->redirect(localIPURL); }); // windows call home - - // B Tier (uncommon) - // server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home - // server.on("/service/update2/json",[](AsyncWebServerRequest *request){request->send(200);}); //firefox? - // server.on("/chat",[](AsyncWebServerRequest *request){request->send(404);}); //No stop asking Whatsapp, there is no internet connection - // server.on("/startpage",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); - - // return 404 to webpage icon - server.on("/favicon.ico", [](AsyncWebServerRequest *request) { request->send(404); }); // webpage icon - - // Serve Basic HTML Page - server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse(200, "text/html", index_html); - response->addHeader("Cache-Control", "public,max-age=31536000"); // save this file to cache for 1 year (unless you refresh) - request->send(response); - Serial.println("Served Basic HTML Page"); - }); - - server.on("/setup", HTTP_POST, [](AsyncWebServerRequest *request) { - String ssid; - String password; - if (request->hasParam("ssid", true) && request->hasParam("password", true)) { - ssid = request->getParam("ssid", true)->value(); - password = request->getParam("password", true)->value(); - // Now connect to the WiFi network using the provided credentials - WiFi.begin(ssid.c_str(), password.c_str()); - // You may want to add some logic to check if the connection was successful - // and respond accordingly - request->send(200, "text/plain", "Connecting to " + ssid); - } else { - request->send(400, "text/plain", "Invalid request"); - } - }); - - // the catch all - server.onNotFound([](AsyncWebServerRequest *request) { - request->redirect(localIPURL); - Serial.print("onnotfound "); - Serial.print(request->host()); // This gives some insight into whatever was being requested on the serial monitor - Serial.print(" "); - Serial.print(request->url()); - Serial.print(" sent redirect to " + localIPURL + "\n"); - }); -} - -void setup() { - // Set the transmit buffer size for the Serial object and start it with a baud rate of 115200. - Serial.setTxBufferSize(1024); - Serial.begin(115200); - - // Wait for the Serial object to become available. - while (!Serial) - ; - - // Print a welcome message to the Serial port. - Serial.println("\n\nCaptive Test, V0.5.0 compiled " __DATE__ " " __TIME__ " by CD_FER"); //__DATE__ is provided by the platformio ide - Serial.printf("%s-%d\n\r", ESP.getChipModel(), ESP.getChipRevision()); - - startSoftAccessPoint(ssid, password, localIP, gatewayIP); - - setUpDNSServer(dnsServer, localIP); - - setUpWebserver(server, localIP); - server.begin(); - - Serial.print("\n"); - Serial.print("Startup Time:"); // should be somewhere between 270-350 for Generic ESP32 (D0WDQ6 chip, can have a higher startup time on first boot) - Serial.println(millis()); - Serial.print("\n"); -} - -void loop() { - dnsServer.processNextRequest(); // I call this atleast every 10ms in my other projects (can be higher but I haven't tested it for stability) - delay(DNS_INTERVAL); // seems to help with stability, if you are doing other things in the loop this may not be needed - - // Check WiFi connection status - if (WiFi.status() == WL_CONNECTED) { - // If connected, you might want to do something, like printing the IP address - Serial.println("Connected to WiFi!"); - Serial.println("IP Address: " + WiFi.localIP().toString()); - Serial.println("SSID " + WiFi.SSID()); - } -} \ No newline at end of file diff --git a/01OS/01OS/clients/esp32/wifi_captiveportal/wifi_captiveportal.ino b/01OS/01OS/clients/esp32/wifi_captiveportal/wifi_captiveportal.ino new file mode 100644 index 0000000..92bceaf --- /dev/null +++ b/01OS/01OS/clients/esp32/wifi_captiveportal/wifi_captiveportal.ino @@ -0,0 +1,260 @@ +#include //not needed in the arduino ide + +// Captive Portal +#include //https://github.com/me-no-dev/AsyncTCP using the latest dev version from @me-no-dev +#include +#include //https://github.com/me-no-dev/ESPAsyncWebServer using the latest dev version from @me-no-dev +#include //Used for mpdu_rx_disable android workaround + +// Pre reading on the fundamentals of captive portals https://textslashplain.com/2022/06/24/captive-portals/ + +const char *ssid = "captive"; // FYI The SSID can't have a space in it. +// const char * password = "12345678"; //Atleast 8 chars +const char *password = NULL; // no password + +#define MAX_CLIENTS 4 // ESP32 supports up to 10 but I have not tested it yet +#define WIFI_CHANNEL 6 // 2.4ghz channel 6 https://en.wikipedia.org/wiki/List_of_WLAN_channels#2.4_GHz_(802.11b/g/n/ax) + +const IPAddress localIP(4, 3, 2, 1); // the IP address the web server, Samsung requires the IP to be in public space +const IPAddress gatewayIP(4, 3, 2, 1); // IP address of the network should be the same as the local IP for captive portals +const IPAddress subnetMask(255, 255, 255, 0); // no need to change: https://avinetworks.com/glossary/subnet-mask/ + +const String localIPURL = "http://4.3.2.1"; // a string version of the local IP with http, used for redirecting clients to your webpage + +String generateHTMLWithSSIDs() +{ + String html = "

Select Wi-Fi Network



"; + + return html; +} + +const char index_html[] PROGMEM = R"=====( + + + + ESP32 WiFi Setup + + + + +

WiFi Setup

+
+
+
+
+

+ +
+ + +)====="; + +DNSServer dnsServer; +AsyncWebServer server(80); + +void setUpDNSServer(DNSServer &dnsServer, const IPAddress &localIP) +{ +// Define the DNS interval in milliseconds between processing DNS requests +#define DNS_INTERVAL 30 + + // Set the TTL for DNS response and start the DNS server + dnsServer.setTTL(3600); + dnsServer.start(53, "*", localIP); +} + +void startSoftAccessPoint(const char *ssid, const char *password, const IPAddress &localIP, const IPAddress &gatewayIP) +{ +// Define the maximum number of clients that can connect to the server +#define MAX_CLIENTS 4 +// Define the WiFi channel to be used (channel 6 in this case) +#define WIFI_CHANNEL 6 + + // Set the WiFi mode to access point and station + // WiFi.mode(WIFI_MODE_AP); + + // Define the subnet mask for the WiFi network + const IPAddress subnetMask(255, 255, 255, 0); + + // Configure the soft access point with a specific IP and subnet mask + WiFi.softAPConfig(localIP, gatewayIP, subnetMask); + + // Start the soft access point with the given ssid, password, channel, max number of clients + WiFi.softAP(ssid, password, WIFI_CHANNEL, 0, MAX_CLIENTS); + + // Disable AMPDU RX on the ESP32 WiFi to fix a bug on Android + esp_wifi_stop(); + esp_wifi_deinit(); + wifi_init_config_t my_config = WIFI_INIT_CONFIG_DEFAULT(); + my_config.ampdu_rx_enable = false; + esp_wifi_init(&my_config); + esp_wifi_start(); + vTaskDelay(100 / portTICK_PERIOD_MS); // Add a small delay +} + +void connectToWifi(String ssid, String password) +{ + WiFi.begin(ssid.c_str(), password.c_str()); + + // Wait for connection to establish + int attempts = 0; + while (WiFi.status() != WL_CONNECTED && attempts < 20) + { + delay(1000); + Serial.print("."); + attempts++; + } + + if (WiFi.status() == WL_CONNECTED) + { + Serial.println("Connected to Wi-Fi"); + } + else + { + Serial.println("Failed to connect to Wi-Fi. Check credentials."); + } +} + +void setUpWebserver(AsyncWebServer &server, const IPAddress &localIP) +{ + //======================== Webserver ======================== + // WARNING IOS (and maybe macos) WILL NOT POP UP IF IT CONTAINS THE WORD "Success" https://www.esp8266.com/viewtopic.php?f=34&t=4398 + // SAFARI (IOS) IS STUPID, G-ZIPPED FILES CAN'T END IN .GZ https://github.com/homieiot/homie-esp8266/issues/476 this is fixed by the webserver serve static function. + // SAFARI (IOS) there is a 128KB limit to the size of the HTML. The HTML can reference external resources/images that bring the total over 128KB + // SAFARI (IOS) popup browser has some severe limitations (javascript disabled, cookies disabled) + + // Required + server.on("/connecttest.txt", [](AsyncWebServerRequest *request) + { request->redirect("http://logout.net"); }); // windows 11 captive portal workaround + server.on("/wpad.dat", [](AsyncWebServerRequest *request) + { request->send(404); }); // Honestly don't understand what this is but a 404 stops win 10 keep calling this repeatedly and panicking the esp32 :) + + // Background responses: Probably not all are Required, but some are. Others might speed things up? + // A Tier (commonly used by modern systems) + server.on("/generate_204", [](AsyncWebServerRequest *request) + { request->redirect(localIPURL); }); // android captive portal redirect + server.on("/redirect", [](AsyncWebServerRequest *request) + { request->redirect(localIPURL); }); // microsoft redirect + server.on("/hotspot-detect.html", [](AsyncWebServerRequest *request) + { request->redirect(localIPURL); }); // apple call home + server.on("/canonical.html", [](AsyncWebServerRequest *request) + { request->redirect(localIPURL); }); // firefox captive portal call home + server.on("/success.txt", [](AsyncWebServerRequest *request) + { request->send(200); }); // firefox captive portal call home + server.on("/ncsi.txt", [](AsyncWebServerRequest *request) + { request->redirect(localIPURL); }); // windows call home + + // B Tier (uncommon) + // server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home + // server.on("/service/update2/json",[](AsyncWebServerRequest *request){request->send(200);}); //firefox? + // server.on("/chat",[](AsyncWebServerRequest *request){request->send(404);}); //No stop asking Whatsapp, there is no internet connection + // server.on("/startpage",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); + + // return 404 to webpage icon + server.on("/favicon.ico", [](AsyncWebServerRequest *request) + { request->send(404); }); // webpage icon + + // Serve Basic HTML Page + server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request) + { + String htmlContent = index_html; + Serial.printf("wifi scan complete: %d . WIFI_SCAN_RUNNING: %d", WiFi.scanComplete(), WIFI_SCAN_RUNNING); + if(WiFi.scanComplete() > 0) { + // Scan complete, process results + Serial.println("done scanning wifi"); + htmlContent = generateHTMLWithSSIDs(); + // WiFi.scanNetworks(true); // Start a new scan in async mode + } + AsyncWebServerResponse *response = request->beginResponse(200, "text/html", htmlContent); + response->addHeader("Cache-Control", "public,max-age=31536000"); // save this file to cache for 1 year (unless you refresh) + request->send(response); + Serial.println("Served Basic HTML Page"); }); + + // the catch all + server.onNotFound([](AsyncWebServerRequest *request) + { + request->redirect(localIPURL); + Serial.print("onnotfound "); + Serial.print(request->host()); // This gives some insight into whatever was being requested on the serial monitor + Serial.print(" "); + Serial.print(request->url()); + Serial.print(" sent redirect to " + localIPURL + "\n"); }); + + server.on("/submit", HTTP_POST, [](AsyncWebServerRequest *request) + { + String ssid; + String password; + + // Check if SSID parameter exists and assign it + if(request->hasParam("ssid", true)) { + ssid = request->getParam("ssid", true)->value(); + } + + // Check if Password parameter exists and assign it + if(request->hasParam("password", true)) { + password = request->getParam("password", true)->value(); + } + + // Attempt to connect to the Wi-Fi network with these credentials + connectToWifi(ssid, password); + + // Redirect user or send a response back + request->send(200, "text/plain", "Attempting to connect to " + ssid); }); +} + +void setup() +{ + // Set the transmit buffer size for the Serial object and start it with a baud rate of 115200. + Serial.setTxBufferSize(1024); + Serial.begin(115200); + + // Wait for the Serial object to become available. + while (!Serial) + ; + + WiFi.mode(WIFI_AP_STA); + + // Print a welcome message to the Serial port. + Serial.println("\n\nCaptive Test, V0.5.0 compiled " __DATE__ " " __TIME__ " by CD_FER"); //__DATE__ is provided by the platformio ide + Serial.printf("%s-%d\n\r", ESP.getChipModel(), ESP.getChipRevision()); + + startSoftAccessPoint(ssid, password, localIP, gatewayIP); + + setUpDNSServer(dnsServer, localIP); + + WiFi.scanNetworks(true); + + setUpWebserver(server, localIP); + server.begin(); + + Serial.print("\n"); + Serial.print("Startup Time:"); // should be somewhere between 270-350 for Generic ESP32 (D0WDQ6 chip, can have a higher startup time on first boot) + Serial.println(millis()); + Serial.print("\n"); +} + +void loop() +{ + dnsServer.processNextRequest(); // I call this atleast every 10ms in my other projects (can be higher but I haven't tested it for stability) + delay(DNS_INTERVAL); // seems to help with stability, if you are doing other things in the loop this may not be needed + + // Check WiFi connection status + if (WiFi.status() == WL_CONNECTED) + { + // If connected, you might want to do something, like printing the IP address + Serial.println("Connected to WiFi!"); + Serial.println("IP Address: " + WiFi.localIP().toString()); + Serial.println("SSID " + WiFi.SSID()); + } +} \ No newline at end of file