Sunday, September 29, 2024

ESP8266 Captive Portal, Static Serve, and Websockets

While working on a toy for my dog, I wanted to set up an AP with captive portal. This took a little bit because a lot of examples out there were a bit out of date and did not work properly. The main issue was that the CaptiveRequestHandler class was not specifically handling Android and iOS captive handler endpoints. 

I changed the class like this and it worked fine: 

class CaptiveRequestHandler : public AsyncWebHandler {
public:
  CaptiveRequestHandler() {}
  virtual ~CaptiveRequestHandler() {}

  bool canHandle(AsyncWebServerRequest *request){
    String url = request->url();
    return (url == "/generate_204" || url == "/hotspot-detect.html");
  }

    void handleRequest(AsyncWebServerRequest *request) {
        if (!request) {
            Serial.println("Received null request");
            return; // Return early if the request is null
        }

        // Check for specific requests (e.g., Android's `/generate_204`)
        if (request->url() == "/generate_204" || request->url() == "/hotspot-detect.html") {
            // Redirect to the captive portal (ESP8266’s IP)
            request->redirect("http://192.168.4.1/index.html");
        }
    }
};


The canHandle was modified to only handle these methods, otherwise to return false. This is important because later we want to handle requests with other handlers. 

That said, I also added a static serve handler:

WiFi.softAP(SSID);
dnsServer.start(53, "*", WiFi.softAPIP());
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");

This meant my index.html page would request other assets (images, css, js) and they would be served. One thing to note is that in order for this to work on a platformio project, you need to update your platform.io config with your (filesystemboard_build.filesystem = littlefs)

Finally because we are allowing handlers, we can setup the web sockets. 

// Set up WebSocket
ws.onEvent(onEvent);
server.addHandler(&ws);  // Add WebSocket handler to the server

// Start the server
server.begin();



No comments: