From 4e581954bbc697eeddd5a856d367f7639cc1aa88 Mon Sep 17 00:00:00 2001 From: drjones Date: Fri, 3 Apr 2026 07:53:06 -0700 Subject: [PATCH] Fix web UI: captive portal DNS + chunked HTML delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phone browsers do a captive portal check (DNS + HTTP) when joining a new WiFi AP. Without a DNS server the DNS query hangs forever and the phone blocks all HTTP traffic to the network — page never loads. Added DNSServer resolving all queries to 192.168.4.1. handleNotFound now 302-redirects to / so captive portal probes get the main page. Replaced single 15 KB send_P() with chunked transfer encoding in 512B pieces with yield() between each chunk, keeping the WiFi stack responsive. Made-with: Cursor --- src/main.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 751094a..92c6eec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include "driver/gpio.h" @@ -35,6 +36,7 @@ CC1101 radio1(&mod1); CC1101 radio2(&mod2); static WebServer server(WEB_PORT); +static DNSServer dnsServer; static Preferences preferences; // CC1101 valid discrete power levels in dBm (RadioLib only accepts these exact values) @@ -2240,7 +2242,18 @@ window.addEventListener('resize',capDrawWave); )HTML"; static void handleRoot() { - server.send_P(200, "text/html; charset=utf-8", kHtml, sizeof(kHtml) - 1); + server.setContentLength(CONTENT_LENGTH_UNKNOWN); + server.send(200, "text/html; charset=utf-8", ""); + const size_t total = sizeof(kHtml) - 1; + size_t off = 0; + while (off < total) { + size_t n = total - off; + if (n > 512) n = 512; + server.sendContent_P(kHtml + off, n); + off += n; + yield(); + } + server.sendContent(""); } static void handleLog() { @@ -2531,9 +2544,8 @@ static void handleCaptureWave() { } static void handleNotFound() { - const String uri = server.uri(); - logLine("[HTTP] 404 " + uri); - server.send(404, "text/plain", "404: Not found"); + server.sendHeader("Location", "http://192.168.4.1/"); + server.send(302, "text/plain", "Redirect"); } static void handleSelfTest() { @@ -2706,6 +2718,9 @@ void setup() { server.onNotFound(handleNotFound); server.begin(); + dnsServer.start(53, "*", WiFi.softAPIP()); + logLine("[DNS] Captive portal DNS on *:53 → " + WiFi.softAPIP().toString()); + // OTA firmware updates over WiFi (connect to 'killer' AP, upload via PlatformIO OTA) ArduinoOTA.setHostname("killer"); ArduinoOTA.setPassword("killerpw"); @@ -2731,6 +2746,7 @@ void setup() { } void loop() { + dnsServer.processNextRequest(); espNowTick(); ArduinoOTA.handle(); server.handleClient();