ruvnet / ruvnet/RuView

⭐ Tutorial: Windows WiFi Sensing Quick Start (ADR-013)

Open
#36 29 comments 6 reactions 1 assignee View on GitHub

@ruvnet is already working on this.

Since Feb 28, 2026.

documentation
Dominant language
Rust
Stars
94.4k
Forks
12.5k
Avg merge
21h 27m
Merged PRs (30d)
43

Description

Windows WiFi Sensing Quick Start (ADR-013) — current as of 2026-05-19

⚠️ Updated 2026-05-19 — original tutorial referenced paths and a repo name that no longer match. Updated for the current state of ruvnet/RuView (note: the repo was renamed from wifi-densepose to RuView).

What changed vs the original: repo name, v1/src/...archive/v1/src/... (the v1 Python codebase was archived but is still runnable), updated release links, added the ./verify deterministic proof check.

Zero-cost presence and motion detection using your existing Windows WiFi — no special hardware needed.

This is the easier path. Reads real RSSI from your laptop's WiFi adapter via netsh, extracts spectral and statistical features, and classifies presence/motion in real-time. No ESP32, no firmware build, no soldering.

For higher-fidelity sensing (breathing rate, heart rate, multi-person, through-wall), use the ESP32-S3 CSI tutorial in #34 instead.


What you need
Item Notes
Windows 10/11 laptop Any WiFi adapter works
Connected WiFi network Must be actively associated with an AP
Python 3.10+ With pip
~5 minutes No hardware mods, no drivers, no root
What you'll get
Capability Works? How
Presence detection ✅ Yes RSSI variance threshold
Motion detection (still/active) ✅ Yes Spectral band power
Breathing detection ❌ No RSSI resolution too coarse (netsh is 1 dBm-quantized)
Heart rate ❌ No Not possible with RSSI alone
Pose estimation ❌ No Requires CSI — see #34
Through-wall sensing ❌ Limited RSSI is too coarse; CSI handles this

Step 1: Clone and install
git clone https://github.com/ruvnet/RuView.git
cd RuView
pip install numpy scipy

📁 The Python v1 code now lives under archive/v1/, not v1/. The original code is still functional and runnable; it was archived to make room for the v2 Rust workspace as the primary codebase, but all the v1 demos in this tutorial still work.

Step 2: Verify WiFi is connected
netsh wlan show interfaces

You should see State: connected and a Signal: value (e.g. 94%). If disconnected:

netsh wlan connect name="YourNetworkName"
Step 3: Run a single RSSI sample
# Quick test — run from the repo root
python -c "
import sys; sys.path.insert(0, 'archive/v1')
from src.sensing.rssi_collector import WindowsWifiCollector
c = WindowsWifiCollector(interface='Wi-Fi')
s = c.collect_once()
print(f'RSSI: {s.rssi_dbm} dBm, Quality: {s.link_quality:.0%}')
"

Expected output:

RSSI: -39.0 dBm, Quality: 94%
Step 4: Run the full pipeline (feature extraction + classification)
python -c "
import sys, time; sys.path.insert(0, 'archive/v1')
from src.sensing.rssi_collector import WindowsWifiCollector
from src.sensing.feature_extractor import RssiFeatureExtractor
from src.sensing.classifier import PresenceClassifier

collector = WindowsWifiCollector(interface='Wi-Fi', sample_rate_hz=2.0)
extractor = RssiFeatureExtractor(window_seconds=15.0)
classifier = PresenceClassifier(presence_variance_threshold=0.3)

collector.start()
print('Collecting 15 seconds of RSSI data...')
time.sleep(15)
collector.stop()

samples = collector.get_samples()
features = extractor.extract(samples)
result = classifier.classify(features)

print(f'Samples:   {len(samples)}')
print(f'RSSI mean: {features.mean:.1f} dBm')
print(f'Variance:  {features.variance:.4f}')
print(f'Motion:    {features.motion_band_power:.4f}')
print(f'Verdict:   {result.motion_level.value} ({result.confidence:.0%})')
"
Step 5: Live monitoring (walk around to test)
# From repo root
$env:PYTHONPATH = "archive/v1"
python archive/v1/tests/integration/live_sense_monitor.py

This prints a live dashboard every 3 seconds:

[14:00:05] RSSI= -37.0dBm var=0.000 motion_e=0.0000 => absent         (100%)
[14:00:08] RSSI= -37.0dBm var=0.000 motion_e=0.0000 => absent         (100%)
[14:00:26] RSSI= -37.1dBm var=0.120 motion_e=0.0016 => absent          (76%)  ← RSSI changing!
[14:00:32] RSSI= -41.3dBm var=4.850 motion_e=1.2300 => active          (95%)  ← MOTION DETECTED

To trigger detection: walk between your laptop and the WiFi router. This causes 3–10+ dBm RSSI swings that the classifier picks up as ACTIVE motion.

Press Ctrl+C to stop and see a summary.

Step 6: Use the CommodityBackend API
import sys; sys.path.insert(0, 'archive/v1')
from src.sensing.backend import CommodityBackend, Capability
from src.sensing.rssi_collector import WindowsWifiCollector

collector = WindowsWifiCollector(interface="Wi-Fi", sample_rate_hz=2.0)
backend = CommodityBackend(collector=collector)

print(backend.get_capabilities())
# {<Capability.PRESENCE>, <Capability.MOTION>}

backend.start()
# ... wait for data collection ...
result = backend.get_result()
print(result.motion_level)   # MotionLevel.ABSENT / PRESENT_STILL / ACTIVE
print(result.confidence)     # 0.0 to 1.0
backend.stop()
Step 7: Run the tests
# Unit tests (36 tests, no WiFi needed — uses SimulatedCollector)
$env:PYTHONPATH = "archive/v1"
python -m pytest archive/v1/tests/unit/test_sensing.py -v -o "addopts="

# Live integration tests (5 tests, requires connected WiFi)
python -m pytest archive/v1/tests/integration/test_windows_live_sensing.py -v -o "addopts=" -s
Step 8: (Optional) Run the deterministic proof

While you're set up, also verify the signal-processing pipeline is real (not mocked):

./verify

Should print RESULT: PASS. This is the ADR-028 trust kill switch: a 100-frame deterministic replay through the production CSI pipeline whose SHA-256 hash matches a pinned expected value. If anyone claims "the project is mocked", ./verify is how you check.


How it works
Windows WiFi (netsh)          Feature Extraction              Classification
┌─────────────────┐     ┌───────────────────────┐     ┌──────────────────┐
│ netsh wlan show │     │ Hann-windowed FFT     │     │ Variance > 0.3?  │
│ interfaces      │────▶│ Band power analysis   │────▶│  → PRESENT       │
│                 │     │ CUSUM change-point    │     │ Motion energy?   │
│ RSSI: -39 dBm   │     │ Rolling statistics    │     │  → STILL/ACTIVE  │
└─────────────────┘     └───────────────────────┘     └──────────────────┘

Pipeline: WindowsWifiCollectorRssiFeatureExtractor (FFT, CUSUM, spectral bands) → PresenceClassifier (rule-based, interpretable)

Limitations (honest assessment)
Limitation Why
RSSI quantized to 1 dBm netsh reports integers; sub-dBm variation invisible
~2 Hz max sample rate netsh takes 200–400 ms per call
No breathing/heartbeat Requires sub-dBm resolution (use ESP32 CSI instead)
Best for coarse motion Person must cross the WiFi signal path for large RSSI swings
Single receiver only Multi-receiver fusion requires multiple machines
When to upgrade to ESP32 CSI

If you need any of:

  • Breathing / heart rate (vitals)
  • Multi-person discrimination
  • Through-wall sensing
  • Pose detection (eventually — see #509)
  • Real-time positional tracking (multistatic)

...follow the ESP32-S3 CSI tutorial in #34 instead. Hardware cost is ~$9 per node, 3-node setup runs ~$30 + a Raspberry Pi as the aggregator (or any existing PC).

The current firmware release is v0.6.5-esp32 with flash-ready binaries.


Verified on
  • OS: Windows 11 Home 10.0.26200
  • Adapter: Intel Wi-Fi 7 BE201 320MHz (any Windows-compatible adapter should work)
  • Network: WPA2-Personal, 5 GHz 802.11ax
  • RSSI observed: -37 to -40 dBm in 5 GHz, similar range in 2.4 GHz
  • Tests: 36 unit + 5 integration = 41 passed
  • Python: 3.13, numpy, scipy
Related
  • ADR-013: Feature-level sensing on commodity gear
  • ADR-012: ESP32 CSI sensor mesh (the upgrade path)
  • ADR-028: Trust kill switch (the ./verify proof)
  • #34: ESP32 CSI end-to-end tutorial
  • User Guide: All deployment modes
  • cognitum.one/ruview: Cognitum Seed integration (persistent memory + AI)

If anything in this tutorial breaks against current main, open a new issue — these tutorials track the code as it evolves.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.