mirror of
https://github.com/ruvnet/RuView
synced 2026-07-26 18:01:48 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5402b070f6 |
@@ -6,27 +6,11 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## **See through walls with WiFi + Ai** ##
|
**See through walls with WiFi.** No cameras. No wearables. No Internet. Just radio waves.
|
||||||
|
|
||||||
**Perceive the world through signals.** No cameras. No wearables. No Internet. Just physics.
|
WiFi DensePose turns commodity WiFi signals into real-time human pose estimation, vital sign monitoring, and presence detection — all without a single pixel of video.
|
||||||
|
|
||||||
### π RuView is an edge AI perception system that learns directly from the environment around it.
|
By analyzing Channel State Information (CSI) disturbances caused by human movement, the system reconstructs body position, breathing rate, and heartbeat using physics-based signal processing and machine learning.
|
||||||
|
|
||||||
Instead of relying on cameras or cloud models, it observes whatever signals exist in a space such as WiFi, radio waves across the spectrum, motion patterns, vibration, sound, or other sensory inputs and builds an understanding of what is happening locally.
|
|
||||||
|
|
||||||
Built on top of [RuVector](https://github.com/ruvnet/ruvector/), the project became widely known for its implementation of WiFi DensePose — a sensing technique first explored in academic research such as Carnegie Mellon University's *DensePose From WiFi* work. That research demonstrated that WiFi signals can be used to reconstruct human pose.
|
|
||||||
|
|
||||||
RuView extends that concept into a practical edge system. By analyzing Channel State Information (CSI) disturbances caused by human movement, RuView reconstructs body position, breathing rate, heart rate, and presence in real time using physics-based signal processing and machine learning.
|
|
||||||
|
|
||||||
Unlike research systems that rely on synchronized cameras for training, RuView is designed to operate entirely from radio signals and self-learned embeddings at the edge.
|
|
||||||
|
|
||||||
The system runs entirely on inexpensive hardware such as an ESP32 sensor mesh (as low as ~$1 per node). Small programmable edge modules analyze signals locally and learn the RF signature of a room over time, allowing the system to separate the environment from the activity happening inside it.
|
|
||||||
|
|
||||||
Because RuView learns in proximity to the signals it observes, it improves as it operates. Each deployment develops a local model of its surroundings and continuously adapts without requiring cameras, labeled data, or cloud infrastructure.
|
|
||||||
|
|
||||||
In practice this means ordinary environments gain a new kind of spatial awareness. Rooms, buildings, and devices begin to sense presence, movement, and vital activity using the signals that already fill the space.
|
|
||||||
|
|
||||||
### Built for low-power edge applications
|
|
||||||
|
|
||||||
[Edge modules](#edge-intelligence-adr-041) are small programs that run directly on the ESP32 sensor — no internet needed, no cloud fees, instant response.
|
[Edge modules](#edge-intelligence-adr-041) are small programs that run directly on the ESP32 sensor — no internet needed, no cloud fees, instant response.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# ADR-051: Sensing Server Decomposition — main.rs God Object Breakup
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Status | Proposed |
|
||||||
|
| Date | 2026-03-06 |
|
||||||
|
| Deciders | ruv |
|
||||||
|
| Depends on | ADR-050 (Quality Engineering — Sprint 2) |
|
||||||
|
| Issue | [#174](https://github.com/ruvnet/RuView/issues/174) |
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
`sensing-server/src/main.rs` is 3,765 lines with cyclomatic complexity ~65. It contains 12 structs, 60+ functions, 10 constants, and a 37-field `AppStateInner` god object. This violates the project's 500-line file limit (CLAUDE.md) and makes unit testing individual components impossible.
|
||||||
|
|
||||||
|
The file mixes concerns:
|
||||||
|
- CLI argument parsing and server bootstrap
|
||||||
|
- HTTP route handlers (health, models, recordings, training, pose, vitals)
|
||||||
|
- WebSocket upgrade and client management
|
||||||
|
- UDP CSI frame receiver and parser
|
||||||
|
- Signal processing pipeline (feature extraction, classification, smoothing)
|
||||||
|
- Simulated data generator
|
||||||
|
- Windows WiFi scanning integration
|
||||||
|
- Pose estimation from WiFi signals
|
||||||
|
- Vital sign smoothing and filtering
|
||||||
|
- Model/recording file management
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Decompose `main.rs` into 14 focused modules. Each module owns its types, constants, and functions. `main.rs` retains only CLI parsing, state initialization, router construction, and server startup (~250 lines).
|
||||||
|
|
||||||
|
### Module Extraction Plan
|
||||||
|
|
||||||
|
| Module | Source Lines | Contents | Target Size |
|
||||||
|
|--------|-------------|----------|-------------|
|
||||||
|
| `cli.rs` | 59-152 | `Args` struct, CLI parsing | ~100 |
|
||||||
|
| `state.rs` | 154-370 | `AppStateInner`, all DTOs (`Esp32Frame`, `SensingUpdate`, `NodeInfo`, etc.), `SharedState` type alias | ~220 |
|
||||||
|
| `signal.rs` | 542-890 | `generate_signal_field()`, `estimate_breathing_rate_hz()`, `compute_subcarrier_variances()`, `extract_features_from_frame()`, `raw_classify()` | ~350 |
|
||||||
|
| `smoothing.rs` | 886-1060 | Classification smoothing, vital sign smoothing, `trimmed_mean()`, constants | ~180 |
|
||||||
|
| `routes_health.rs` | 1660-2005 | `/health/*`, `/api/v1/info` endpoints | ~350 |
|
||||||
|
| `routes_model.rs` | 2058-2230 | `/api/v1/models/*`, LoRA profiles, `scan_model_files()` | ~180 |
|
||||||
|
| `routes_recording.rs` | 2233-2440 | `/api/v1/recording/*`, `scan_recording_files()` | ~210 |
|
||||||
|
| `routes_training.rs` | 2443-2560 | `/api/v1/train/*`, `/api/v1/adaptive/*` | ~120 |
|
||||||
|
| `routes_sensing.rs` | 2562-2710 | Vital signs, edge vitals, WASM events, model info, SONA endpoints | ~150 |
|
||||||
|
| `routes_pose.rs` | 1701-1930, 2007-2055 | Pose estimation, `derive_single_person_pose()`, pose/stats/zones endpoints | ~280 |
|
||||||
|
| `websocket.rs` | 1492-1660 | WS upgrade handlers, `handle_ws_client()`, `handle_ws_pose_client()` | ~170 |
|
||||||
|
| `udp_receiver.rs` | 2725-2890 | UDP CSI frame receiver task, frame parsing | ~170 |
|
||||||
|
| `data_sources.rs` | 1063-1465, 2888-3020 | Windows WiFi task, simulated data task, `probe_windows_wifi()`, `parse_netsh_interfaces_output()` | ~400 |
|
||||||
|
| `router.rs` | (new) | `build_router()` function assembling all routes | ~80 |
|
||||||
|
|
||||||
|
### Extraction Order (6 Phases)
|
||||||
|
|
||||||
|
1. **Phase 1**: `cli.rs` + `state.rs` — Zero behavioral change, just move types
|
||||||
|
2. **Phase 2**: `signal.rs` + `smoothing.rs` — Pure functions, easy to test
|
||||||
|
3. **Phase 3**: `routes_health.rs` + `routes_model.rs` + `routes_recording.rs` — Stateless-ish handlers
|
||||||
|
4. **Phase 4**: `routes_training.rs` + `routes_sensing.rs` + `routes_pose.rs` — Remaining HTTP handlers
|
||||||
|
5. **Phase 5**: `websocket.rs` + `udp_receiver.rs` + `data_sources.rs` — Async tasks
|
||||||
|
6. **Phase 6**: `router.rs` — Assemble all routes, slim `main.rs` to ~250 lines
|
||||||
|
|
||||||
|
### State Refactoring
|
||||||
|
|
||||||
|
`AppStateInner` (37 fields) will be split into domain-specific sub-states:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
pub struct AppStateInner {
|
||||||
|
pub config: ServerConfig, // CLI args, ports, paths
|
||||||
|
pub sensing: SensingState, // CSI frames, features, classification
|
||||||
|
pub vitals: VitalsState, // Vital sign buffers, smoothing state
|
||||||
|
pub models: ModelState, // Active model, discovered models, LoRA
|
||||||
|
pub recording: RecordingState, // Active recording, file handles
|
||||||
|
pub training: TrainingState, // Training status, adaptive model
|
||||||
|
pub pose: PoseState, // Person detections, pose history
|
||||||
|
pub broadcast_tx: broadcast::Sender<SensingUpdate>,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
- Each module is independently unit-testable
|
||||||
|
- No file exceeds 500 lines
|
||||||
|
- Domain boundaries are explicit (state sub-structs)
|
||||||
|
- New developers can find code by domain
|
||||||
|
- Merge conflict surface reduced (parallel module edits)
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
- Large refactor with ~3,700 lines touched — high merge conflict risk
|
||||||
|
- `pub(crate)` visibility needed for cross-module state access
|
||||||
|
- Some functions share mutable state, requiring careful `&mut` threading
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
- No behavioral change — all endpoints, WebSocket, UDP behavior stays identical
|
||||||
|
- Existing integration tests (if any) continue to pass unchanged
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
1. Each phase is a separate commit for easy revert
|
||||||
|
2. Run `cargo test` and `cargo check` after each phase
|
||||||
|
3. Use `pub(crate)` for internal types, keep public API surface minimal
|
||||||
|
4. Add `#[cfg(test)] mod tests` to each new module with at least smoke tests
|
||||||
|
5. Consider adding `tower` middleware for auth (Sprint 1 remaining item) during Phase 3
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- ADR-050: Quality Engineering Response (Sprint 2 plan)
|
||||||
|
- Issue #170: Quality Engineering Analysis
|
||||||
|
- CLAUDE.md: 500-line file limit rule
|
||||||
Vendored
+1
-1
Submodule vendor/ruvector updated: fbe2268a7d...f8f2c600a7
Reference in New Issue
Block a user