Skip to content

Commit

Permalink
V0.3.0 (#2)
Browse files Browse the repository at this point in the history
* Update README.md

* Tidy up and remove unused libs

* 0.3.0 Dev
  • Loading branch information
CDFER committed Nov 17, 2022
1 parent 2332eec commit d4efec4
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 47 deletions.
52 changes: 30 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,62 @@

A ESP32 Captive Portal (think airport wifi sign in page) example that works on all devices (or that's the goal).

When you connect to the wifi "captive" password "12345678" it should take you straight to http://4.3.2.1/ and display some simple text.

| Status | Issue | Version | Device Name | Browser | OS |
|--------|----------|---------|-------------------------|---------|-------------------------|
|| | V0.2.0 | Iphone XR | Default | iOS 16 |
|| | V0.2.0 | XPS15 9550 | Firefox | Win 11 Home |
|| | V0.2.0 | XPS15 9550 | Chrome | Win 11 Home |
|| | V0.2.0 | Samsung A53 | Default | Android 9 (OneUI1) |
| 🤷 | Cellular | V0.2.0 | Onplus 6 | Default | Android 11 (OxygenOS11) |
|| | V0.2.0 | XPS15 9575 | Edge | Win 10 Pro |
|| | V0.2.0 | XPS15 9570 | Edge | Win 10 Edu |
|| | V0.2.0 | Samsung S20 FE 5G | Default | Android 12 (OneUI4.1) |

When you connect to the wifi "captive" password "12345678" it should take you straight to <http://4.3.2.1/> and display a green page with some simple text.

| Status | Version | Connect | Popup | Serve Page | OS | Device Name | Browser | Notes |
|--------|-----------|---------|-------|------------|-------------------------|---------------------|---------|----------------------|
|| V0.3.0 |||| Win 11 Home (22H2) | XPS15 9550 | Firefox | |
|| V0.3.0 |||| Win 11 Home (22H2) | XPS15 9550 | Chrome | |
|| V0.3.0 |||| Android 11 (OxygenOS11) | Oneplus 6 | Default | Cellular must be off |
|| V0.3.0 |||| MacOSX (10.6.8) | Macbook Air (2011) | Safari | |
|| V0.3.0 |||| Windows 7 Starter | Toshiba NB200 | IE | |
|| V0.3.0 |||| iOS 9 (9.3.5) | iPad mini (2012) | Default | |
|| V0.3.0 |||| Android 9 (OneUI1) | Samsung A53 | Default | |
|| V0.3.0 |||| iOS 10 (10.3.3) | iPhone 5c | Default | |
|| V0.2.0 |||| iOS 16 | iPhone XR | Default | |
|| V0.2.0 |||| MacOS Monterey (12.5.1) | Macbook Pro 16 2019 | Chrome | |
|| V0.2.0 |||| MacOS Monterey (12.5.1) | Macbook Pro 16 2019 | Safari | |
|| V0.1 |||| Win 10 Pro | XPS15 9575 | Edge | |
|| V0.1 |||| Win 10 Edu | XPS15 9570 | Edge | |
|| V0.1 |||| Android 12 (OneUI4.1) | Samsung S20 FE 5G | Default | |

## Quickstart with ESP Home Flasher tool on Windows, MacOS and Linux

This is a simple GUI-based tool that can be downloaded from here: https://github.com/esphome/esphome-flasher/releases/

If running Windows, you will most likely need a driver from here: https://www.wemos.cc/en/latest/ch340_driver.html before your computer will show the COM port in ESPhome Flasher.
This is a simple GUI-based tool that can be downloaded from here: <https://github.com/esphome/esphome-flasher/releases/>

If running Windows, you will most likely need a driver from here: <https://www.wemos.cc/en/latest/ch340_driver.html> before your computer will show the COM port in ESPhome Flasher.

## Did it work?
If you test this code on a device (even if it works) it would be really helpful if you fill out the form here: https://forms.gle/ArLPTnwRA3QGTKyc6

If you test this code on a device (even if it works) it would be really helpful if you fill out the form here: <https://forms.gle/ArLPTnwRA3QGTKyc6>

## Known Bugs/limitations with current version

## Known Bugs with current version
- Oneplus 6 phone (Oxygen OS 11) sometimes gets stuck on setting client side IP address when cellular is on

- On older devices you may need to open a web browser for it to display
- max of 4 clients connected at the same time
- MacOS post macOS Big Sur no pop up

### Further testing required
- If you have a lot of tabs open in Windows 11 (and probably other desktop OS) it increases the load on the ESP32 DNS server.

- If you have a lot of tabs open in Windows 11 (and probably other OS) it increases the load on the ESP32 DNS server.
- HTML Webpage being served multiple times
- Other ESP32 chip variants (all testing so far is on the ESP32 D0WDQ6 chip in the ESP32S module)
- Test increasing the max clients connected up from 4 to max supported 10


### Future Dev Options to look into (Help or suggestions are appreciated):

- Set client DHCP IP address range in private space (currently clients must accept DHCP Server Range: 4.3.2.2 to 4.3.2.12)
- Support integrating the DHCP or IPv6 Router Advertisement (RA) options for Captive Portals on iOS 14+ and macOS Big Sur+ https://developer.apple.com/news/?id=q78sq5rv
- Port https://github.com/Aircoookie/WLED-WebInstaller


### Compile yourself using PlatformIO highly recommended

- Make sure Git client is installed on your system.
- Download and install Visual Studio Code by Microsoft.
- Open VS Code and go to the Extensions manager (the icon with the stacked blocks in the left bar)
- Search for platformio ide and install the PlatformIO extension
- Download the source code by executing git clone https://github.com/CDFER/Captive-Portal-ESP32.git. in some folder.
- In VS Code Go to File -> Open Folder and open that root folder (the one that contains platformio.ini, NOT the src folder)
- Upload to the esp32 using the right arrow button in the bottom left corner of vs code

4 changes: 2 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ framework = arduino
lib_deps =
https://github.com/me-no-dev/AsyncTCP
ESP Async WebServer
monitor_speed = 115200 # default esp32
check_skip_packages = yes # fixes inspect in platformio
board_build.partitions = huge_app.csv # not required, increases Flash size for program
board_build.filesystem = littlefs

[env:myrelease] #Low flash and ram usage, no debugging
build_type = release
Expand All @@ -29,6 +27,8 @@ build_flags =

[env:mydebug]
build_type = debug
monitor_speed = 115200 # default esp32
monitor_filters = esp32_exception_decoder
build_flags =
-DCORE_DEBUG_LEVEL=5 # verbose debug info output on serial
-DUSE_SERIAL=true #enables the use of the serial port
Expand Down
76 changes: 53 additions & 23 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#include <Arduino.h>
#include <DNSServer.h>
#include <esp_wifi.h> //Used for mpdu_rx_disable android workaround
#include <WiFi.h>
#include <AsyncTCP.h> //https://github.com/me-no-dev/AsyncTCP using the latest dev version from @me-no-dev
#include <ESPAsyncWebServer.h> //ESP Async WebServer using the latest stable version from @me-no-dev

#define DEBUG_SERIAL if(USE_SERIAL)Serial //don't touch, enable serial in platformio.ini


// Dependency Graph
// |-- AsyncTCP @ 1.1.1+sha.ca8ac5f
// |-- ESP Async WebServer @ 1.2.3
Expand All @@ -16,29 +14,57 @@
// | |-- WiFi @ 2.0.0
// |-- DNSServer @ 2.0.0
// | |-- WiFi @ 2.0.0
// |-- WiFi @ 2.0.0

//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";

#define MAX_CLIENTS 4
#define WIFI_CHANNEL 6 //2.4ghz channel 6


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
const IPAddress subnetMask(255,255,255,0);

const String localIPURL = "http://4.3.2.1";

const char index_html[] PROGMEM = R"=====(
<!DOCTYPE html> <html>
<head>
<title>ESP32 Captive Portal</title>
<style>
body {background-color:#06cc13;}
h1 {color: white;}
h2 {color: white;}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Hello World!</h1>
<h2>This is a captive portal example. All requests will be redirected here </h2>
</body>
</html>
)=====";

DNSServer dnsServer;
AsyncWebServer server(80);

void setup(){ //the order of the code is really important and it is critical the the android workaround is after the dns and sofAP setup
void setup(){ //the order of the code is important and it is critical the the android workaround is after the dns and sofAP setup

#if USE_SERIAL == true
Serial.begin(115200);
while (!Serial);
Serial.println("\n\nCaptive Test, compiled " __DATE__ " " __TIME__ "by CD_FER");
Serial.println("\n\nCaptive Test, V0.3.0dev compiled " __DATE__ " " __TIME__ " by CD_FER");
#endif

WiFi.mode(WIFI_AP);
WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0)); //Samsung requires the IP to be in public space
WiFi.softAP("captive", "12345678", 6, 0, 4); //2.4ghz channel 6, do broadcast SSID (0), 4 max clients, FYI The SSID in SoftAP can't have a space in it.
WiFi.softAPConfig(localIP, gatewayIP, subnetMask); //Samsung requires the IP to be in public space
WiFi.softAP(ssid, password, WIFI_CHANNEL, 0, MAX_CLIENTS);

dnsServer.setErrorReplyCode(DNSReplyCode::NoError); //not sure if this is necessary
dnsServer.setTTL(300); //set 5min client side cache for DNS
// if DNSServer is started with "*" for domain name, it will reply with provided IP to all DNS request
dnsServer.start(53, "*", WiFi.softAPIP());
dnsServer.start(53, "*", localIP); //if DNSServer is started with "*" for domain name, it will reply with provided IP to all DNS request

//ampdu_rx_disable android workaround see https://github.com/espressif/arduino-esp32/issues/4423
esp_wifi_stop();
Expand All @@ -49,39 +75,42 @@ void setup(){ //the order of the code is really important and it is critical the

esp_wifi_init(&my_config); //set the new config
esp_wifi_start(); //Restart WiFi
delay(100); //this seems to be necessary don't ask me why
delay(100); //this is necessary don't ask me why

//Required
server.on("/connecttest.txt",[](AsyncWebServerRequest *request){request->redirect("http://logout.net/");}); //windows 11 captive portal workaround
server.on("/connecttest.txt",[](AsyncWebServerRequest *request){request->redirect("http://logout.net");}); //windows 11 captive portal workaround

//Probably not Required, but might speed things up?
server.on("/canonical.html",[](AsyncWebServerRequest *request){request->redirect("http://4.3.2.1/");}); //firefox captive portal call home
//Probably not all are Required, but some are. Others might speed things up?
server.on("/canonical.html",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //firefox captive portal call home
server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home
server.on("/redirect",[](AsyncWebServerRequest *request){request->redirect("http://4.3.2.1/");}); //microsoft redirect
server.on("/redirect",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //microsoft redirect
server.on("/success.txt",[](AsyncWebServerRequest *request){request->send(200);}); //firefox captive portal call home
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 :)
server.on("/generate_204",[](AsyncWebServerRequest *request){request->redirect("http://4.3.2.1/");}); //chromium? android? captive portal redirect
server.on("/generate_204",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //chromium? android? captive portal redirect
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 WARNING IOS (and maybe macos) WILL NOT POP UP IF THIS PAGE CONTAINS THE WORD "Success" https://www.esp8266.com/viewtopic.php?f=34&t=4398
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", "<!DOCTYPE html><html><head><title>ESP32 Captive Portal</title></head><body><p>This is a captive portal example. All requests will "
"be redirected here.</p></body>");
server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request){
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", index_html);
response->addHeader("Cache-Control", "public,max-age=31536000");
request->send(response);
DEBUG_SERIAL.println("Served Basic HTML Page with 1 year Cache header");
DEBUG_SERIAL.println("Served Basic HTML Page");

});

server.onNotFound([](AsyncWebServerRequest *request){
request->redirect("http://4.3.2.1/");
DEBUG_SERIAL.print("server.onnotfound ");
request->redirect(localIPURL);
DEBUG_SERIAL.print("onnotfound ");
DEBUG_SERIAL.print(request->host()); //This gives some insight into whatever was being requested on the serial monitor
DEBUG_SERIAL.print(" ");
DEBUG_SERIAL.print(request->url());
DEBUG_SERIAL.print(" sent redirect to http://4.3.2.1/\n");
DEBUG_SERIAL.print(" sent redirect to " + localIPURL +"\n");
});

server.begin();
Expand All @@ -94,4 +123,5 @@ void setup(){ //the order of the code is really important and it is critical the

void loop(){
dnsServer.processNextRequest();
delay(1);
}

0 comments on commit d4efec4

Please sign in to comment.