Skip to content

Commit fdedb0f

Browse files
authored
V0.4.0 (#4)
* Switch Library, Added Tests * Comments, tidy up, etc, bump version * Update README.md * V0.4.0dev (#3) * no password, image * add image * Update README.md * Update README.md
1 parent e12c77c commit fdedb0f

File tree

4 files changed

+100
-53
lines changed

4 files changed

+100
-53
lines changed

README.md

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,41 @@
1-
# ESP32 Cross Platform Captive Portal Example
2-
## Built using Platformio and the Arduino C++ core
1+
# ESP32 Cross Platform Captive Portal ✨
32

43
[![Hippocratic License HL3-CL-EXTR-FFD-MEDIA-MIL-MY-SV-TAL](https://img.shields.io/static/v1?label=Hippocratic%20License&message=HL3-CL-EXTR-FFD-MEDIA-MIL-MY-SV-TAL&labelColor=5e2751&color=bc8c3d)](https://firstdonoharm.dev/version/3/0/cl-extr-ffd-media-mil-my-sv-tal.html)
54

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

8-
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.
6+
A ESP32 Captive Portal written in Arudino C++ (think airport wifi sign in page) demo that works on all devices[^1].
7+
8+
## ⚙️ Features
9+
```
10+
RAM: [= ] 11.6% (used 37976 bytes from 327680 bytes)
11+
Flash: [== ] 22.6% (used 711089 bytes from 3145728 bytes)
12+
```
13+
- about 0.1s reload time using modern browsers and systems
14+
- Lots of comments that explain how it all works
15+
16+
## 🖼️ User interface
17+
![User interface](/images/banner.jpg)
18+
19+
## 📲 Quickstart with ESP Home Flasher tool on Windows, MacOS and Linux
20+
21+
This is a simple all in one GUI tool that can be downloaded from here: <https://github.com/esphome/esphome-flasher/releases/>
22+
23+
Download the firmware from the releases page and chuck it in select the serial port from the dropdown and press flash ESP
24+
25+
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 ESP32 com port in the drop down menu in ESPhome Flasher.
26+
27+
### Compile yourself using PlatformIO
28+
29+
- Make sure Git client is installed on your system. https://github.com/git-guides/install-git
30+
- Download and install Visual Studio Code by Microsoft. https://code.visualstudio.com/download
31+
- Open Visual Studio Code and go to the Extensions manager (the icon with the stacked blocks in the left bar)
32+
- Search for platformio and install the PlatformIO extension
33+
- Download the source code by running a git clone (git gui can be found in your right click menu) with the link: https://github.com/CDFER/Captive-Portal-ESP32.git in your projects folder.
34+
- In VS Code Go to File -> Open Folder and open that root folder (the one that contains platformio.ini, NOT the src folder)
35+
- Upload to the esp32 using the right arrow button in the bottom left corner of vs code (it takes awhile for the first compile)
36+
37+
38+
## Testing Status
939

1040
| Status | Version | Connect | Popup | Serve Page | OS | Device Name | Browser | Notes |
1141
|--------|-----------|---------|-------|------------|-------------------------|---------------------|---------|----------------------|
@@ -26,45 +56,50 @@ When you connect to the wifi "captive" password "12345678" it should take you st
2656
|| V0.1 |||| Win 10 Edu | XPS15 9570 | Edge | |
2757
|| V0.1 |||| Android 12 (OneUI4.1) | Samsung S20 FE 5G | Default | |
2858

29-
## Quickstart with ESP Home Flasher tool on Windows, MacOS and Linux
30-
31-
This is a simple GUI-based tool that can be downloaded from here: <https://github.com/esphome/esphome-flasher/releases/>
32-
33-
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.
34-
35-
## Did it work?
59+
### Did it work?
3660

3761
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>
3862

63+
3964
## Known Bugs/limitations with current version
4065

4166
- Oneplus 6 phone (Oxygen OS 11) sometimes gets stuck on setting client side IP address when cellular is on
4267
- On older devices you may need to open a web browser for it to display
4368
- max of 4 clients connected at the same time
4469
- MacOS post macOS Big Sur no pop up
4570

71+
4672
### Further testing required
4773

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

79+
5380
### Future Dev Options to look into (Help or suggestions are appreciated):
5481

5582
- 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)
5683
- 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
5784
- Port https://github.com/Aircoookie/WLED-WebInstaller
5885

59-
### Compile yourself using PlatformIO
86+
### My Reading List
87+
88+
- https://www.linkedin.com/pulse/ios-7-captive-portal-guide-requirements-agathe-guib%C3%A9
89+
- https://developer.apple.com/news/?id=q78sq5rv
90+
-
91+
92+
93+
## ✌️ Other
94+
95+
This work was done as part of a project with Simon Ingram of Terrestrial Assemblages with the support of Govett-Brewster Art Gallery / Len Lye Centre
96+
97+
Thanks to @me-no-dev and everyone at @Espressif Systems for making a really awesome chip and porting it to arduino
98+
99+
Thanks to @LTRTNZ and @vincentd123 for putting up with my never ending shit and @Vincent for helping me through this crazy year
100+
60101

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

69-
Made with love by Chris Dirks (@cd_fer) in Aotearoa New Zealand
103+
[^1]: devices from the last 10 years, or that's the goal of this project :)
70104

105+
Made with love by Chris Dirks (@cd_fer) in Aotearoa New Zealand

images/banner.jpg

644 KB
Loading

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ board = esp32dev
1515
framework = arduino
1616
lib_deps =
1717
https://github.com/me-no-dev/AsyncTCP
18-
ESP Async WebServer
18+
https://github.com/me-no-dev/ESPAsyncWebServer
1919
check_skip_packages = yes # fixes inspect in platformio
2020
board_build.partitions = huge_app.csv # not required, increases Flash size for program
2121

src/main.cpp

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
#include <Arduino.h>
1+
#include <Arduino.h> //not needed in the arduino ide
2+
3+
//Captive Portal
24
#include <DNSServer.h>
35
#include <esp_wifi.h> //Used for mpdu_rx_disable android workaround
46
#include <AsyncTCP.h> //https://github.com/me-no-dev/AsyncTCP using the latest dev version from @me-no-dev
5-
#include <ESPAsyncWebServer.h> //ESP Async WebServer using the latest stable version from @me-no-dev
7+
#include <ESPAsyncWebServer.h> //https://github.com/me-no-dev/ESPAsyncWebServer using the latest dev version from @me-no-dev
68

7-
#define DEBUG_SERIAL if(USE_SERIAL)Serial //don't touch, enable serial in platformio.ini
9+
#define DEBUG_SERIAL if(USE_SERIAL)Serial //don't touch, enable serial in platformio.ini unless you are using the arduino ide
810

9-
// Dependency Graph
10-
// |-- AsyncTCP @ 1.1.1+sha.ca8ac5f
11-
// |-- ESP Async WebServer @ 1.2.3
11+
// Dependency Graph (these are the libary versions used by this version of the code)
12+
// |-- AsyncTCP @ 1.1.1+sha.ca8ac5f //Latest version of the main branch
13+
// |-- ESP Async WebServer @ 1.2.3+sha.f71e3d4 //Latest version of the main branch
1214
// | |-- AsyncTCP @ 1.1.1+sha.ca8ac5f
1315
// | |-- FS @ 2.0.0
1416
// | |-- WiFi @ 2.0.0
@@ -18,18 +20,23 @@
1820
//Pre reading on the fundamentals of captive portals https://textslashplain.com/2022/06/24/captive-portals/
1921

2022
const char * ssid = "captive"; //FYI The SSID can't have a space in it.
21-
const char * password = "12345678";
23+
//const char * password = "12345678"; //Atleast 8 chars
24+
const char * password = NULL; // no password
2225

23-
#define MAX_CLIENTS 4
24-
#define WIFI_CHANNEL 6 //2.4ghz channel 6
26+
#define MAX_CLIENTS 4 //ESP32 supports up to 10 but I have not tested it yet
27+
#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)
2528

2629

2730
const IPAddress localIP(4, 3, 2, 1); // the IP address the web server, Samsung requires the IP to be in public space
28-
const IPAddress gatewayIP(4, 3, 2, 1); // IP address of the network
29-
const IPAddress subnetMask(255,255,255,0);
31+
const IPAddress gatewayIP(4, 3, 2, 1); // IP address of the network should be the same as the local IP for captive portals
32+
const IPAddress subnetMask(255,255,255,0); //no need to change: https://avinetworks.com/glossary/subnet-mask/
33+
34+
const String localIPURL = "http://4.3.2.1"; //a string version of the local IP with http, used for redirecting clients to your webpage
3035

31-
const String localIPURL = "http://4.3.2.1";
3236

37+
//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
38+
//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
39+
//SAFARI (IOS) popup browser has some severe limitations (javascript disabled, cookies disabled, no .gz extension (even though gzip files are supported))
3340
const char index_html[] PROGMEM = R"=====(
3441
<!DOCTYPE html> <html>
3542
<head>
@@ -56,11 +63,11 @@ void setup(){ //the order of the code is important and it is critical the the an
5663
#if USE_SERIAL == true
5764
Serial.begin(115200);
5865
while (!Serial);
59-
Serial.println("\n\nCaptive Test, V0.3.0dev compiled " __DATE__ " " __TIME__ " by CD_FER");
66+
Serial.println("\n\nCaptive Test, V0.4.0 compiled " __DATE__ " " __TIME__ " by CD_FER"); //__DATE__ is provided by the platformio ide
6067
#endif
6168

62-
WiFi.mode(WIFI_AP);
63-
WiFi.softAPConfig(localIP, gatewayIP, subnetMask); //Samsung requires the IP to be in public space
69+
WiFi.mode(WIFI_AP); //access point mode
70+
WiFi.softAPConfig(localIP, gatewayIP, subnetMask);
6471
WiFi.softAP(ssid, password, WIFI_CHANNEL, 0, MAX_CLIENTS);
6572

6673
dnsServer.setTTL(300); //set 5min client side cache for DNS
@@ -77,33 +84,38 @@ void setup(){ //the order of the code is important and it is critical the the an
7784
esp_wifi_start(); //Restart WiFi
7885
delay(100); //this is necessary don't ask me why
7986

80-
//Required
81-
server.on("/connecttest.txt",[](AsyncWebServerRequest *request){request->redirect("http://logout.net");}); //windows 11 captive portal workaround
87+
//Required
88+
server.on("/connecttest.txt",[](AsyncWebServerRequest *request){request->redirect("http://logout.net");}); //windows 11 captive portal workaround
89+
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 :)
8290

83-
//Probably not all are Required, but some are. Others might speed things up?
84-
server.on("/canonical.html",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //firefox captive portal call home
85-
server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home
86-
server.on("/redirect",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //microsoft redirect
87-
server.on("/success.txt",[](AsyncWebServerRequest *request){request->send(200);}); //firefox captive portal call home
88-
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 :)
89-
server.on("/generate_204",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //chromium? android? captive portal redirect
90-
server.on("/service/update2/json",[](AsyncWebServerRequest *request){request->send(200);}); //firefox?
91-
server.on("/chat",[](AsyncWebServerRequest *request){request->send(404);}); //No stop asking Whatsapp, there is no internet connection
92-
server.on("/startpage",[](AsyncWebServerRequest *request){request->redirect(localIPURL);});
91+
//Background responses: Probably not all are Required, but some are. Others might speed things up?
92+
//A Tier (commonly used by modern systems)
93+
server.on("/generate_204",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); // android captive portal redirect
94+
server.on("/redirect",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //microsoft redirect
95+
server.on("/hotspot-detect.html",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //apple call home
96+
server.on("/canonical.html",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //firefox captive portal call home
97+
server.on("/success.txt",[](AsyncWebServerRequest *request){request->send(200);}); //firefox captive portal call home
98+
server.on("/ncsi.txt",[](AsyncWebServerRequest *request){request->redirect(localIPURL);}); //windows call home
99+
100+
//B Tier (uncommon)
101+
// server.on("/chrome-variations/seed",[](AsyncWebServerRequest *request){request->send(200);}); //chrome captive portal call home
102+
// server.on("/service/update2/json",[](AsyncWebServerRequest *request){request->send(200);}); //firefox?
103+
// server.on("/chat",[](AsyncWebServerRequest *request){request->send(404);}); //No stop asking Whatsapp, there is no internet connection
104+
// server.on("/startpage",[](AsyncWebServerRequest *request){request->redirect(localIPURL);});
93105

94106

95107
//return 404 to webpage icon
96108
server.on("/favicon.ico",[](AsyncWebServerRequest *request){request->send(404);}); //webpage icon
97109

98-
//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
110+
//Serve Basic HTML Page
99111
server.on("/", HTTP_ANY, [](AsyncWebServerRequest *request){
100112
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", index_html);
101-
response->addHeader("Cache-Control", "public,max-age=31536000");
113+
response->addHeader("Cache-Control", "public,max-age=31536000"); //save this file to cache for 1 year (unless you refresh)
102114
request->send(response);
103115
DEBUG_SERIAL.println("Served Basic HTML Page");
104-
105116
});
106117

118+
//the catch all
107119
server.onNotFound([](AsyncWebServerRequest *request){
108120
request->redirect(localIPURL);
109121
DEBUG_SERIAL.print("onnotfound ");
@@ -122,6 +134,6 @@ void setup(){ //the order of the code is important and it is critical the the an
122134
}
123135

124136
void loop(){
125-
dnsServer.processNextRequest();
126-
delay(1);
137+
dnsServer.processNextRequest(); //I call this atleast every 10ms in my other projects (can be higher but I haven't tested it for stability)
138+
delay(1); //seems to help with stability, if you are doing other things in the loop this may not be needed
127139
}

0 commit comments

Comments
 (0)