项目文件夹

文件
wehub-resource-sync 9740bc64c9
Bench Regression Guard / bench compile-verify (--no-run) (push) Failing after 0s
Continuous Deployment / Pre-deployment Checks (push) Has been skipped
Bench Regression Guard / bench fast-run (informational, non-gating) (push) Has been skipped
Firmware CI / Verify version.txt matches release tag (push) Has been skipped
Dashboard a11y + cross-browser / a11y (push) Failing after 0s
nvsim Dashboard → GitHub Pages / build-and-deploy (push) Failing after 2s
Firmware CI / Build firmware (esp32s3 / 4mb) (push) Failing after 15s
Firmware CI / Build firmware (esp32c6 / c6-4mb) (push) Failing after 15s
Firmware QEMU Tests (ADR-061) / Build Espressif QEMU (push) Failing after 1s
Firmware QEMU Tests (ADR-061) / Fuzz Testing (ADR-061 Layer 6) (push) Failing after 1s
Firmware QEMU Tests (ADR-061) / QEMU Test (boundary-max) (push) Has been skipped
Firmware CI / Build firmware (esp32s3 / 8mb) (push) Failing after 15s
Firmware QEMU Tests (ADR-061) / QEMU Test (boundary-min) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (default) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (edge-tier0) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (edge-tier1) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (full-adr060) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / QEMU Test (tdm-3node) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / Swarm Test (ADR-062) (push) Has been skipped
Firmware QEMU Tests (ADR-061) / NVS Matrix Generation (push) Failing after 1s
Fix-Marker Regression Guard / Verify fix markers (push) Failing after 1s
ADR-115 MQTT integration tests / mqtt-integration (push) Failing after 1s
npm packages / harness/ruview (node 20) (push) Failing after 1s
npm packages / tools/ruview-mcp (node 20) (push) Failing after 1s
npm packages / tools/ruview-cli (node 20) (push) Failing after 1s
npm packages / tools/ruview-cli (node 22) (push) Failing after 1s
npm packages / tools/ruview-mcp (node 22) (push) Failing after 1s
nvsim-server → ghcr.io / build-and-publish (push) Failing after 1s
ruview-swarm CI guard / tests (full+train) (push) Failing after 2s
ruview-swarm CI guard / tests (ruflo) (push) Failing after 1s
ruview-swarm CI guard / tests (train) (push) Failing after 2s
BFLD MQTT Integration / cargo test --features mqtt (live mosquitto) (push) Failing after 29s
ruview-swarm CI guard / tests (default) (push) Failing after 2s
Point Cloud Viewer → GitHub Pages / build-and-deploy (push) Failing after 8s
ruview-swarm CI guard / ITAR / publish guard (push) Failing after 0s
ruview-swarm CI guard / build train_marl bin (push) Failing after 2s
ruview-swarm CI guard / clippy (-D warnings, --no-deps) (push) Failing after 3s
Security Scanning / Dependency Vulnerability Scan (push) Failing after 0s
Security Scanning / Static Application Security Testing (push) Failing after 1s
Security Scanning / Infrastructure Security Scan (push) Failing after 1s
Security Scanning / Secret Scanning (push) Failing after 1s
npm packages / harness/ruview (node 22) (push) Failing after 17s
Security Scanning / License Compliance Scan (push) Failing after 1s
Security Scanning / Container Security Scan (push) Failing after 4s
Security Scanning / Security Policy Compliance (push) Failing after 0s
wifi-densepose sensing-server → Docker Hub + ghcr.io / build · push · smoke-test (push) Failing after 1s
three.js demos → GitHub Pages / build-and-deploy (push) Failing after 1s
Verify Pipeline Determinism / Verify Pipeline Determinism (3.11) (push) Failing after 1s
Continuous Deployment / Deploy to Production (push) Has been cancelled
Continuous Deployment / Rollback Deployment (push) Has been cancelled
Continuous Deployment / Post-deployment Monitoring (push) Has been cancelled
Continuous Deployment / Notify Deployment Status (push) Has been cancelled
Continuous Deployment / Deploy to Staging (push) Has been cancelled
Security Scanning / Security Report (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:59:54 +08:00

6.3 KiB

ADR-019: Sensing-Only UI Mode with Gaussian Splat Visualization

Field Value
Status Accepted
Date 2026-02-28
Deciders ruv
Relates to ADR-013 (Feature-Level Sensing), ADR-018 (ESP32 Dev Implementation)

Context

The WiFi-DensePose UI was originally built to require the full FastAPI DensePose backend (localhost:8000) for all functionality. This backend depends on heavy Python packages (PyTorch ~2GB, torchvision, OpenCV, SQLAlchemy, Redis) making it impractical for lightweight sensing-only deployments where the user simply wants to visualize live WiFi signal data from ESP32 CSI or Windows RSSI collectors.

A Rust port exists (v2) using Axum with lighter runtime footprint (~10MB binary, ~5MB RAM), but it still requires libtorch C++ bindings and OpenBLAS for compilation—a non-trivial build.

Users need a way to run the UI with only the sensing pipeline active, without installing the full DensePose backend stack.

Decision

Implement a sensing-only UI mode that:

  1. Decouples the sensing pipeline from the DensePose API backend. The sensing WebSocket server (ws_server.py on port 8765) operates independently of the FastAPI backend (port 8000).

  2. Auto-detects sensing-only mode at startup. When the DensePose backend is unreachable, the UI sets backendDetector.sensingOnlyMode = true and:

    • Suppresses all API requests to localhost:8000 at the ApiService.request() level
    • Skips initialization of DensePose-dependent tabs (Dashboard, Hardware, Live Demo)
    • Shows a green "Sensing mode" status toast instead of error banners
    • Silences health monitoring polls
  3. Adds a new "Sensing" tab with Three.js Gaussian splat visualization:

    • Custom GLSL ShaderMaterial rendering point-cloud splats on a 20×20 floor grid
    • Signal field splats colored by intensity (blue → green → red)
    • Body disruption blob at estimated motion position
    • Breathing ring modulation when breathing-band power detected
    • Side panel with RSSI sparkline, feature meters, and classification badge
  4. Python WebSocket bridge (archive/v1/src/sensing/ws_server.py) that:

    • Auto-detects ESP32 UDP CSI stream on port 5005 (ADR-018 binary frames)
    • Falls back to WindowsWifiCollectorSimulatedCollector
    • Runs RssiFeatureExtractorPresenceClassifier pipeline
    • Broadcasts JSON sensing updates every 500ms on ws://localhost:8765
  5. Client-side fallback: sensing.service.js generates simulated data when the WebSocket server is unreachable, so the visualization always works.

Architecture

ESP32 (UDP :5005)  ──┐
                     ├──▶  ws_server.py (:8765)  ──▶  sensing.service.js  ──▶  SensingTab.js
Windows WiFi RSSI ───┘         │                          │                      │
                          Feature extraction          WebSocket client      gaussian-splats.js
                          + Classification            + Reconnect            (Three.js ShaderMaterial)
                                                      + Sim fallback

Data flow

Source Collector Feature Extraction Output
ESP32 CSI (ADR-018) Esp32UdpCollector (UDP :5005) Amplitude mean → pseudo-RSSI → RssiFeatureExtractor sensing_update JSON
Windows WiFi WindowsWifiCollector (netsh) RSSI + signal% → RssiFeatureExtractor sensing_update JSON
Simulated SimulatedCollector Synthetic RSSI patterns sensing_update JSON

Sensing update JSON schema

{
  "type": "sensing_update",
  "timestamp": 1234567890.123,
  "source": "esp32",
  "nodes": [{ "node_id": 1, "rssi_dbm": -39, "position": [2,0,1.5], "amplitude": [...], "subcarrier_count": 56 }],
  "features": { "mean_rssi": -39.0, "variance": 2.34, "motion_band_power": 0.45, ... },
  "classification": { "motion_level": "active", "presence": true, "confidence": 0.87 },
  "signal_field": { "grid_size": [20,1,20], "values": [...] }
}

Files

Created

File Purpose
archive/v1/src/sensing/ws_server.py Python asyncio WebSocket server with auto-detect collectors
ui/components/SensingTab.js Sensing tab UI with Three.js integration
ui/components/gaussian-splats.js Custom GLSL Gaussian splat renderer
ui/services/sensing.service.js WebSocket client with reconnect + simulation fallback

Modified

File Change
ui/index.html Added Sensing nav tab button and content section
ui/app.js Sensing-only mode detection, conditional tab init
ui/style.css Sensing tab layout and component styles
ui/config/api.config.js AUTO_DETECT: false (sensing uses own WS)
ui/services/api.service.js Short-circuit requests in sensing-only mode
ui/services/health.service.js Skip polling when backend unreachable
ui/components/DashboardTab.js Graceful failure in sensing-only mode

Consequences

Positive

  • UI works with zero heavy dependencies—only pip install websockets (+ numpy/scipy already installed)
  • ESP32 CSI data flows end-to-end without PyTorch, OpenCV, or database
  • Existing DensePose tabs still work when the full backend is running
  • Clean console output—no ERR_CONNECTION_REFUSED spam in sensing-only mode

Negative

  • Two separate WebSocket endpoints: :8765 (sensing) and :8000/api/v1/stream/pose (DensePose)
  • Pose estimation, zone occupancy, and historical data features unavailable in sensing-only mode
  • Client-side simulation fallback may mislead users if they don't notice the "Simulated" badge

Neutral

  • Rust Axum backend remains a future option for a unified lightweight server
  • The sensing pipeline reuses the existing RssiFeatureExtractor and PresenceClassifier classes unchanged

Alternatives Considered

  1. Install minimal FastAPI (pip install fastapi uvicorn pydantic): Starts the server but pose endpoints return errors without PyTorch.
  2. Build Rust backend: Single binary, but requires libtorch + OpenBLAS build toolchain.
  3. Merge sensing into FastAPI: Would require FastAPI installed even for sensing-only use.

Option 1 was rejected because it still shows broken tabs. The chosen approach cleanly separates concerns.