Add USB serial config mode (no WiFi/AP required) - #436
Open
Variour wants to merge 6 commits into
Open
Conversation
…erver Refactors every REST endpoint in WebServer.h onto a shared (ApiRequest, ApiResponse) handler shape registered once in a dispatch table, instead of being written directly against AsyncWebServerRequest. Adds SerialConfigServer, a framed newline-delimited JSON protocol over the existing Serial connection that reaches the same dispatch table — so a device can be fully configured over USB without WiFi or the device's AP (#355), and a new endpoint only needs to be registered once to work over both HTTP and serial. Logger's serial sink is suspended for the duration of a serial config session so plain-text log lines can't corrupt the framed protocol.
Adds a Web Serial-backed window.fetch shim (data/index.html) that speaks SerialConfigServer's framed protocol, engaged only when the page can't reach a device over HTTP (see the startup probe) — every existing fetch()-based call site keeps working unmodified. The one XHR-based upload path (storage .wav upload) branches on serial mode explicitly, and scene save streams its body in chunks the same way the firmware side does. WebSocket push has no serial equivalent, so a lightweight poll substitutes for peers/groups live updates while connected this way (#355).
Publishes data/index.html to GitHub Pages so it's reachable without any device serving it — the standalone entry point for USB-serial config (#355). Requires the repo's Pages source to be set to "GitHub Actions" in Settings > Pages, a one-time manual step this workflow can't do itself.
Adds docs/serial-config.md (wire protocol, design rationale, constraints), a README section pointing users at the GitHub Pages entry point, and an architecture.md update noting SerialConfigServer alongside BatteryWebServer.
PreviewURL: https://batterylight-pr-436.blackpond-ef672c92.germanywestcentral.azurecontainerapps.io Hosted on Azure Container Apps — accessible from the internet. |
… serial Widens Config.h's deserialize* helpers from JsonVariant to JsonVariantConst (they were always read-only) — WebServer.h's transport-agnostic handlers pass ApiRequest::body as JsonVariantConst, which doesn't implicitly convert to the mutable JsonVariant these previously required, and failed to build on esp32s3/esp32dev CI. Also fixes SerialConfigServer::_handleRequest, which built every ApiRequest without ever copying the incoming frame's "body" field into it — every non-streaming POST over serial was silently dispatched with an empty body.
This was referenced Jul 23, 2026
Variour
added a commit
that referenced
this pull request
Jul 24, 2026
* mesh,web: add central event log + read endpoint for GenericEvent history Records GenericEvent broadcasts (buzzer presses, resets, ...) in receipt order in a fixed-size RAM ring buffer, with a read endpoint and live WebSocket push for a web UI viewer. #436 (shared ApiRequest/ApiResponse dispatch table for serial reachability) is still an open, unmerged PR, so GET /api/events is registered directly against AsyncWebServerRequest for now instead of the shared dispatch table the issue's design calls for — it should move onto that table once #436 lands. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMsq87s9e7zRUvfLYKxqvk * mesh,web: make event log display limit configurable, add device-side clear Adds a persisted eventLogLimit device setting (default 10) capping how many of the most recent matching entries GET /api/events returns, and a POST /api/events/clear endpoint that wipes the device's ring buffer and restarts arrival order at 0, broadcasting to connected WebSocket clients so other open viewers stay in sync. Adds matching UI: a "Max displayed" field in the Settings save flow and a confirm-gated "Clear event log" button. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMsq87s9e7zRUvfLYKxqvk * web: put event log's max-displayed and filter fields on one row Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMsq87s9e7zRUvfLYKxqvk --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
WebServer.honto a shared, transport-agnostic(ApiRequest, ApiResponse)handler shape (ApiTypes.h), registered once in a dispatch table instead of being written directly againstAsyncWebServerRequest.SerialConfigServer: a framed, chunked JSON protocol over the device's existingSerialconnection that reaches the same dispatch table — so a device can be fully configured (network, hardware, groups, scenes, sound storage) over USB, without WiFi or the device's own AP. A new endpoint only needs to be registered once to work over both HTTP and serial.Logger's serial sink is suspended for the duration of a serial config session so plain-text log lines can't corrupt the framed protocol.window.fetchshim todata/index.html, engaged only when the page can't reach a device over HTTP, so every existingfetch()call site keeps working unmodified; the one XHR-based.wavupload branches explicitly for serial mode.data/index.htmlto GitHub Pages (newpages-deploy.ymlworkflow) as the standalone entry point, since the device can't serve its own config page without a network connection.docs/serial-config.md, with a README section pointing users at the GitHub Pages URL.Closes #355
Test plan
npm run lint(ESLint) passesnpm test(mock server test suite, 36/36) passesclang-format --dry-run --Werrorpasses acrosssrc/.wavupload through the Settings > Storage UI still works end-to-end in HTTP mode (the modifieduploadStorageFile()correctly falls through to its original XHR path when not in serial mode)/api/*paths and identical JSON field keys before/after theWebServer.hrefactor (mock serverserver/index.jsneeds no changes as a result)pages-deploy.ymlto actually publish anything — not something CI can do itself.Generated by Claude Code