Complete configuration Web UI with tabbed SPA (fw 0.8.2).

Add now-playing view with metadata polling, six-band EQ controls, full REST coverage, companion-chip badges, and gzip-www helper for the embedded setup page.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 07:36:06 +02:00
co-authored by Cursor
parent 1c38ac6f08
commit 8d826b4d73
9 changed files with 765 additions and 510 deletions
+7 -7
View File
@@ -7,7 +7,7 @@
**Open-source digital radio — Si4684 tuner · ADAU1701 SigmaDSP · Bluetooth aptX Adaptive · ESP32-S3** **Open-source digital radio — Si4684 tuner · ADAU1701 SigmaDSP · Bluetooth aptX Adaptive · ESP32-S3**
![Status](https://img.shields.io/badge/hardware-verified-brightgreen) ![Status](https://img.shields.io/badge/hardware-verified-brightgreen)
![Firmware](https://img.shields.io/badge/firmware-0.8.1-blue) ![Firmware](https://img.shields.io/badge/firmware-0.8.2-blue)
![CI](https://github.com/manvalan/DigiRadio/actions/workflows/ci.yml/badge.svg) ![CI](https://github.com/manvalan/DigiRadio/actions/workflows/ci.yml/badge.svg)
![PCB](https://img.shields.io/badge/PCB-6--layer-blue) ![PCB](https://img.shields.io/badge/PCB-6--layer-blue)
![Hardware License](https://img.shields.io/badge/hardware-CERN--OHL--S-lightgrey) ![Hardware License](https://img.shields.io/badge/hardware-CERN--OHL--S-lightgrey)
@@ -57,7 +57,7 @@ no analogue conversions are introduced between the tuner and the wireless link.
- **6-layer impedance-controlled PCB**, 50 × 90 mm, two ground planes - **6-layer impedance-controlled PCB**, 50 × 90 mm, two ground planes
- Three antennas (ESP32 2.4 GHz, BT1035 2.4 GHz, FM/DAB SMA) with proper keep-outs - Three antennas (ESP32 2.4 GHz, BT1035 2.4 GHz, FM/DAB SMA) with proper keep-outs
### Firmware (ESP-IDF, C++23 — fw **0.8.1**) ### Firmware (ESP-IDF, C++23 — fw **0.8.2**)
| Area | Capability | | Area | Capability |
|------|------------| |------|------------|
@@ -67,7 +67,7 @@ no analogue conversions are introduced between the tuner and the wireless link.
| **Audio** | 5-band EQ, input mixer, stereo/bass enhancement overlays, profile persist in NVS | | **Audio** | 5-band EQ, input mixer, stereo/bass enhancement overlays, profile persist in NVS |
| **Presets** | Station list CRUD, reorder, recall with audio profile re-apply, last-preset restore at boot | | **Presets** | Station list CRUD, reorder, recall with audio profile re-apply, last-preset restore at boot |
| **Bluetooth** | Discoverable pairing, A2DP status, disconnect | | **Bluetooth** | Discoverable pairing, A2DP status, disconnect |
| **Network** | SoftAP setup mode, STA provisioning, gzipped SPA (`/`), typed JSON REST API | | **Network** | SoftAP setup mode, STA provisioning, tabbed gzipped SPA (`/`), typed JSON REST API |
| **Security** | NVS-backed credential and preset storage (flash encryption planned — see roadmap) | | **Security** | NVS-backed credential and preset storage (flash encryption planned — see roadmap) |
| **Quality** | **13** host unit tests, Doxygen gate, LaTeX manual sync check, GitHub Actions CI on `main` | | **Quality** | **13** host unit tests, Doxygen gate, LaTeX manual sync check, GitHub Actions CI on `main` |
@@ -83,6 +83,7 @@ Vertical slices landed on `main` (newest first):
| Version | Highlights | | Version | Highlights |
|---------|------------| |---------|------------|
| **0.8.2** | Tabbed configuration Web UI — now-playing, 6-band EQ, full API coverage |
| **0.8.1** | `IntegrationService` — boot preset recall, tune orchestration (tuner + audio + NVS `last_preset`); services stub removed | | **0.8.1** | `IntegrationService` — boot preset recall, tune orchestration (tuner + audio + NVS `last_preset`); services stub removed |
| **0.8.0** | Preset reorder API/UI; broadcast metadata (RDS + DAB DLS); `readDabServiceData` driver path | | **0.8.0** | Preset reorder API/UI; broadcast metadata (RDS + DAB DLS); `readDabServiceData` driver path |
| **0.7.1** | CI workflow (host tests, Doxygen, manual sync); Doxygen warnings cleared | | **0.7.1** | CI workflow (host tests, Doxygen, manual sync); Doxygen warnings cleared |
@@ -90,8 +91,7 @@ Vertical slices landed on `main` (newest first):
| **0.50.6** | ADAU1701 runtime EQ/mixer, Si4684 tuning & DAB service list, BT1035 driver | | **0.50.6** | ADAU1701 runtime EQ/mixer, Si4684 tuning & DAB service list, BT1035 driver |
| **0.30.4** | Secure store, Wi-Fi provisioning, companion-chip boot, walking skeleton | | **0.30.4** | Secure store, Wi-Fi provisioning, companion-chip boot, walking skeleton |
**Next up** ([`Software/docs/TODO.md`](Software/docs/TODO.md)): polished configuration Web UI (T6), **Next up** ([`Software/docs/TODO.md`](Software/docs/TODO.md)): Si4684 blob procurement docs (T7), NVS/flash encryption (T8).
Si4684 blob procurement docs (T7), NVS/flash encryption (T8).
--- ---
@@ -221,8 +221,8 @@ Generated C++ API reference: run `doxygen Doxyfile` → `Software/docs/api/html/
| **PCB layout** | 6-layer, DRC clean, plane continuity verified | | **PCB layout** | 6-layer, DRC clean, plane continuity verified |
| **BOM** | Finalised (manufacturable / sourced) | | **BOM** | Finalised (manufacturable / sourced) |
| **Prototype** | In fabrication (PCBWay) | | **Prototype** | In fabrication (PCBWay) |
| **Firmware** | **0.8.1** on `main` — CI green; tuner, DSP, BT, presets, RDS/DLS, integration service | | **Firmware** | **0.8.2** on `main` — CI green; full Web UI, integration, RDS/DLS |
| **Web UI** | Functional SPA; full polish tracked as T6 | | **Web UI** | Tabbed SPA covering every REST endpoint |
| **Production hardening** | Si4684 blob policy (T7), NVS encryption (T8) — open | | **Production hardening** | Si4684 blob policy (T7), NVS encryption (T8) — open |
Agent task list: [`Software/docs/TODO.md`](Software/docs/TODO.md). Agent task list: [`Software/docs/TODO.md`](Software/docs/TODO.md).
+4 -3
View File
@@ -2,8 +2,8 @@
Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3. Open-source Hi-Fi DAB+/FM receiver firmware for the ESP32-S3.
**Status:** fw **0.8.1**`IntegrationService` (boot preset recall, tune + **Status:** fw **0.8.2**tabbed Web UI (now-playing, 6-band EQ, all APIs);
audio profile); RDS/DLS now-playing metadata; **13** host tests; CI on `main`. `IntegrationService`; **13** host tests; CI on `main`.
See [`docs/TODO.md`](docs/TODO.md) for the agent task list. See [`docs/TODO.md`](docs/TODO.md) for the agent task list.
## Quick start ## Quick start
@@ -31,6 +31,7 @@ Documentation gates (must exit 0 before merging; also enforced in CI):
```bash ```bash
doxygen Doxyfile doxygen Doxyfile
python3 tools/check-manual-sync.py python3 tools/check-manual-sync.py
python3 tools/gzip-www.sh # after editing components/net/www/index.html
``` ```
Manual PDF (design + HTTP API + class reference): Manual PDF (design + HTTP API + class reference):
@@ -39,7 +40,7 @@ Manual PDF (design + HTTP API + class reference):
cd docs/manual && latexmk -lualatex manual.tex cd docs/manual && latexmk -lualatex manual.tex
``` ```
## HTTP API (fw 0.8.1) ## HTTP API (fw 0.8.2)
| Method | Path | Purpose | | Method | Path | Purpose |
|--------|------|---------| |--------|------|---------|
@@ -52,7 +52,7 @@ namespace net {
namespace { namespace {
constexpr char kTag[] = "SetupWebServer"; constexpr char kTag[] = "SetupWebServer";
constexpr char kFirmwareVersion[] = "0.8.1"; constexpr char kFirmwareVersion[] = "0.8.2";
constexpr unsigned kRebootDelaySec = 3; constexpr unsigned kRebootDelaySec = 3;
extern const uint8_t www_index_html_gz_start[] asm( extern const uint8_t www_index_html_gz_start[] asm(
File diff suppressed because it is too large Load Diff
Binary file not shown.
+7 -14
View File
@@ -12,8 +12,8 @@ errors, no plaintext secrets.
Working directory for all commands is `Software/`. Working directory for all commands is `Software/`.
**Current firmware:** `0.8.1`integration service (preset recall + **Current firmware:** `0.8.2`tabbed configuration Web UI (full API
audio profile), RDS/DLS metadata, CI gate. coverage), integration service, RDS/DLS metadata, CI gate.
--- ---
@@ -59,18 +59,11 @@ audio profile re-apply, and last-preset NVS. Stub removed; `app_main` and
## P2 — User interface ## P2 — User interface
### T6. Complete the configuration Web UI ### T6. Complete the configuration Web UI — **DONE (fw 0.8.2)**
**Why:** `components/net/www/index.html` is functional but the Tabbed SPA (`Now` / `Radio` / `Presets` / `Audio` / `BT` / `WiFi`):
requirement is an *elegant, essential* SPA. It should cover: now-playing hero with 5 s metadata poll, six-band EQ sliders, all REST
Wi-Fi provisioning, station list management, tuner control (FM/DAB, endpoints wired, companion-chip badges, `tools/gzip-www.sh` for the
seek, play), live EQ/volume/enhancement control, Bluetooth pairing, and embedded gzip blob. No debug routes in `SetupWebServer`.
now-playing metadata.
**What:** a minimal single-page app served gzipped from flash, design
tokens defined once (spacing, type scale, one accent), thin client over
the existing typed JSON API. No heavy frameworks. No business logic in
the UI.
**Done when:** every API capability has a UI control; the page is served
gzipped; no debug endpoint is exposed in a shipping build.
--- ---
+7 -4
View File
@@ -369,10 +369,13 @@ delegate to \texttt{AudioService}:
\item \texttt{POST /api/audio/bass-enhance} --- same schema. \item \texttt{POST /api/audio/bass-enhance} --- same schema.
\end{itemize} \end{itemize}
The gzipped setup page (\texttt{components/net/www/index.html}) exposes master The gzipped setup page (\texttt{components/net/www/index.html}) is a tabbed
volume, Si4684/ESP32 path levels, and enhancement sliders; saving sends SPA: a \emph{Now playing} view (RDS/DLS metadata), tuner and preset panels,
\texttt{PUT /api/audio/profile}, while slider release on enhancements sends master/path levels, six PEQ band gain sliders, enhancement overlays, Bluetooth
the dedicated POST routes for immediate safeload + persist. controls, and Wi-Fi provisioning. Saving sends \texttt{PUT /api/audio/profile};
enhancement sliders call the dedicated POST routes for immediate safeload +
persist. Regenerate \texttt{index.html.gz} with \texttt{tools/gzip-www.sh}
after editing the HTML source.
\section{Typical usage patterns} \section{Typical usage patterns}
\label{sec:adau1701-patterns} \label{sec:adau1701-patterns}
+1 -1
View File
@@ -36,7 +36,7 @@ Returns a health-check DTO serialised by
\begin{drnote}[Response schema] \begin{drnote}[Response schema]
\begin{drcode}[JSON] \begin{drcode}[JSON]
{"status":"ok","fw":"0.8.1", {"status":"ok","fw":"0.8.2",
"chips":{"si4684":true,"adau1701":true,"bt1035":true}} "chips":{"si4684":true,"adau1701":true,"bt1035":true}}
\end{drcode} \end{drcode}
\begin{itemize} \begin{itemize}
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Regenerate the gzipped setup UI embedded by components/net/CMakeLists.txt.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SRC="${ROOT}/components/net/www/index.html"
OUT="${ROOT}/components/net/www/index.html.gz"
gzip -c -9 "$SRC" > "$OUT"
echo "Wrote $(wc -c < "$OUT" | tr -d ' ') bytes -> ${OUT#"$ROOT"/}"