I am using an ESP8266WiFiHW-628 V0.0.1 to create an access point (code below). While I am able to connect to the AP using a windows machine when I am trying to connect using iOS devices I get "Unable To Join the network ..."
I am using:
- ESP8266WiFiHW-628 V0.0.1
- VSCode
- PlatformIO
- 5v, 3A power supply (it currently shown max current of 0.8A)
- iPhone Xs with iOS 18.6.2 and iPhone SE with iOS 18.6.2
Looking for an working example showing how to set up the ESP8266 so iOS devices can connect to it.
I tried :
- Power supply problems - 4A power supply, showing less than 1A actual demand
- channels problem - tried 1,6,11. tried to turn off all the other wifi APs
- Weak signal strength - the iOS is 10cm from the ESP8266
- Strong pass - tried (when pass is incorrect message is different)
- IP conflicts - tried 10.0.0.1, 118.118.4.1 ....
- No DNS - Started a DNS + Setting DNS manually on the iPhone
- iPhone Private WiFi Address - Turn OFF "Private WiFi Address
Current Code:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <DNSServer.h>
// Create an instance of the AsyncWebServer on port 80.
AsyncWebServer server(80);
DNSServer dnsServer;
// IP configuration for iOS compatibility
IPAddress LocalIP(192, 168, 4, 1);
IPAddress Gateway(192, 168, 4, 1);
IPAddress Subnet(255, 255, 255, 0);
void setup() {
// Start serial communication for debugging purposes.
Serial.begin(115200);
Serial.println("\n--- Starting Setup ---");
// Create the Access Point with iOS-compatible settings.
// Configure IP settings first
WiFi.softAPdisconnect(true);
if (WiFi.softAPConfig(LocalIP, Gateway, Subnet)) {
Serial.println("AP configuration successful");
// Create AP with stronger password, channel 6, not hidden, max 4 clients
if (WiFi.softAP("CircularClockAP", "Clock123!@#", 6, false, 4)) {
Serial.println("Access Point created successfully");
// Prevent WiFi sleep for better stability with iOS devices
WiFi.setSleepMode(WIFI_NONE_SLEEP);
// Print the IP address of the Access Point.
Serial.print("AP IP Address: ");
Serial.println(WiFi.softAPIP());
Serial.printf("Connected stations: %d\n", WiFi.softAPgetStationNum());
} else {
Serial.println("Failed to create Access Point");
}
} else {
Serial.println("Failed to configure AP IP settings");
}
// Start DNS server for captive portal
dnsServer.start(53, "*", LocalIP);
Serial.println("DNS server started");
// Add captive portal detection handlers for iOS
server.on("/hotspot-detect.html", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("iOS captive portal detection");
request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>");
});
server.on("/library/test/success.html", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("iOS success page detection");
request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>");
});
server.on("/generate_204", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Android captive portal detection");
request->send(204); // No Content response for Android
});
// Handle Apple's connectivity check
server.on("/connecttest.txt", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Windows connectivity check");
request->send(200, "text/plain", "Microsoft Connect Test");
});
// Add a simple handler for the root URL.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String userAgent = request->getHeader("User-Agent") ? request->getHeader("User-Agent")->value() : "";
// If it's Apple's connectivity check, return success
if (userAgent.indexOf("CaptiveNetworkSupport") >= 0) {
Serial.println("Apple connectivity check - returning success");
request->send(200, "text/html", "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>");
return;
}
// For regular browsers, show configuration page
Serial.println("HTTP GET request received for the root URL (/).");
String html = "<!DOCTYPE html><html><head>";
html += "<meta charset='UTF-8'>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
html += "<title>Circular Clock Setup</title>";
html += "<style>body{font-family:Arial,sans-serif;margin:40px;background:#f5f5f5;}";
html += ".container{background:white;padding:30px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,0.1);}";
html += "h1{color:#333;text-align:center;}";
html += "p{color:#666;line-height:1.6;}";
html += ".status{background:#e8f5e8;padding:15px;border-radius:5px;margin:20px 0;}";
html += "</style></head><body>";
html += "<div class='container'>";
html += "<h1>🕐 Circular Clock Configuration</h1>";
html += "<div class='status'>✅ Successfully connected to Circular Clock!</div>";
html += "<p>Your iOS device is now connected and the captive portal has been validated.</p>";
html += "<p>You can now configure your Circular Clock settings or close this page.</p>";
html += "<p><strong>Network:</strong> CircularClockAP<br>";
html += "<strong>Status:</strong> Connected and Validated</p>";
html += "</div></body></html>";
request->send(200, "text/html", html);
});
// Catch-all handler for captive portal
server.onNotFound([](AsyncWebServerRequest *request){
Serial.println("Redirect from: " + request->url());
// For unknown URLs, redirect to main page
request->redirect("http://192.168.4.1/");
});
// Start the server.
server.begin();
Serial.println("Web server started.");
Serial.println("--- Setup Complete ---");
}
void loop() {
// Process DNS requests for captive portal
dnsServer.processNextRequest();
// Monitor connected devices every 10 seconds
static unsigned long lastCheck = 0;
if (millis() - lastCheck > 10000) { // Every 10 seconds
uint8_t stationCount = WiFi.softAPgetStationNum();
Serial.printf("AP Status - Connected devices: %d\n", stationCount);
if (stationCount > 0) {
Serial.println("iOS device connected successfully!");
}
lastCheck = millis();
}
// The Async libraries handle requests in the background.
// The loop processes DNS requests and monitors connections.
}