🚧 Web UI
This commit is contained in:
@@ -156,6 +156,33 @@ terminal, in `docker logs`, and in `journalctl` alike. Read vs write
|
||||
mappings are annotated correctly per the manual's Tables 119/120
|
||||
(e.g. word address `0x0000` reads as `%IW0` but writes to `%QW0`).
|
||||
|
||||
## Web UI
|
||||
|
||||
`serve` starts a browser UI alongside the Modbus server (spec §10):
|
||||
|
||||
```bash
|
||||
wago-sim serve --node config/pump_node.yaml --port 5020
|
||||
# Web UI on http://127.0.0.1:8080 — default login: admin / simu
|
||||
```
|
||||
|
||||
- **Overview**: realistic DIN-rail view of the coupler + modules with
|
||||
per-channel LEDs for digital I/O and bar/numeric indicators for
|
||||
analog values; updates live via WebSocket — including changes made
|
||||
by the PLC over Modbus.
|
||||
- **Manipulation**: click a DI/DO LED to toggle it (field side), or
|
||||
force DO/AO master-side; AI values can be set directly. All writes
|
||||
go through the simulator's internal data paths — never via Modbus
|
||||
TCP — while keeping read-back mirrors and statistics consistent.
|
||||
- **Diagnostics**: watchdog status, statistics with reset, and
|
||||
LED/module fault injection for FAT fault cases.
|
||||
|
||||
Configuration options: `--no-web`, `--web-port <n>` or env
|
||||
`WAGO_SIM_WEB_PORT` (default 8080); credentials via
|
||||
`WAGO_SIM_WEB_USER` / `WAGO_SIM_WEB_PASSWORD` (defaults
|
||||
`admin` / `simu`); `WAGO_SIM_WEB_READONLY=1` for observation-only
|
||||
benches (all mutating endpoints answer 403). Plain HTTP — keep the
|
||||
port inside the bench network.
|
||||
|
||||
## Documentation
|
||||
|
||||
- `docs/spec/software-spec.md` — the software specification
|
||||
@@ -261,6 +288,47 @@ requirement ID for each item in parentheses.
|
||||
protocol tracing, diagnostics and fault injection (FR-14.2.5–
|
||||
14.2.6); scoping questions to answer before planning (§14.3).
|
||||
|
||||
### Web UI (spec §10) — in implementation
|
||||
|
||||
- [x] Spec §10.3–10.6 updated with binding implementation decisions:
|
||||
FastAPI/Uvicorn in-process on the Modbus server's asyncio loop;
|
||||
vanilla single-page front-end (no build step) with realistic
|
||||
DIN-rail graphics and per-channel LEDs; session-cookie auth with
|
||||
default credentials `admin`/`simu` (env-overridable,
|
||||
read-only mode); backend API uses **only internal memory
|
||||
handlers** (`WagoDatastore`, `VirtualNode`, registers,
|
||||
watchdog, statistics) — never Modbus TCP; WebSocket live
|
||||
updates; milestones M1–M6.
|
||||
- [x] M1: webui package (`src/wago_sim/webui/`: `app.py`, `auth.py`,
|
||||
`state.py`, `api.py`, static SPA); session auth with scrypt
|
||||
hashing, lockout after 5 failed logins, read-only mode
|
||||
(`WAGO_SIM_WEB_READONLY`); `GET /api/node` with `DI0.1`-style
|
||||
and Modbus addresses; CLI wiring `--web/--no-web`,
|
||||
`--web-port`, env `WAGO_SIM_WEB_USER/PASSWORD/READONLY/
|
||||
NO_WEB/WEB_PORT`; login page + SPA shell.
|
||||
- [x] M2: node overview page — DIN-rail strip with coupler block
|
||||
(MS/NS/BF/SF LEDs), module bezels with article numbers,
|
||||
per-channel LEDs for DI/DO, bar+numeric indicators for AI/AO,
|
||||
live values via WebSocket (`/api/ws`, 10 Hz delta push),
|
||||
`GET /api/values` snapshot.
|
||||
- [x] M3: manipulation — DI/DO toggle (field side via
|
||||
`set_digital_input_channel`, master side via internal
|
||||
`write_bits`/`write_words` dispatch so mirrors/statistics stay
|
||||
consistent), AI value entry (raw counts), AO force;
|
||||
unknown-channel → 404, kind-mismatch → 400, read-only → 403.
|
||||
- [x] M4: diagnostics — watchdog status card (0x1006/0x100A),
|
||||
statistics table (0x1029 words) with reset, LED-error
|
||||
(0x1020/0x1021) and module-diagnosis (0x1050) fault injection
|
||||
and clear; SF LED on the coupler reflects injected LED errors.
|
||||
- [x] M5: configuration — coupler settings forms (watchdog time/masks/type/close-on-timeout via 0x1000–0x100B, response delay 0x1037, idle timeout 0x1030) with the device's own validation surfaced (writes refused while the watchdog runs → field error); module list editor over the 13-article catalog with SAVE CONFIG → live process-image rebuild (`rebuild_node`: datastore survives, values clear like a KBUS reset, 0x1022–0x1025 and 0x2030+ updated) + persistence to the node-config YAML via a comment-preserving custom emitter.
|
||||
- [ ] M6: scenario run view + alias-ownership rejection (FR-10.2.6,
|
||||
FR-10.2.9) — deferred.
|
||||
- [x] Tests: 28 web-UI tests (`tests/test_webui.py`) via httpx
|
||||
`ASGITransport` (in-process, no socket) + live verification:
|
||||
browser SAVE CONFIG rebuilds the node and persists YAML; Modbus
|
||||
master reads the module description (0x2030) correctly after the
|
||||
loader-overlap register fix. Full suite: 206 passing.
|
||||
|
||||
### Framework gaps (spec §4 — Scenario & Macro Engine)
|
||||
|
||||
- [ ] State machines: `states:` with entry actions, transitions on
|
||||
|
||||
Reference in New Issue
Block a user