Files
ruvnet--RuView/python
Dragan Spiridonov 3ed43e9a2f fix(python): ship SOTA bindings in release wheels; make parity tests arch-portable
Three coupled defects, all found by building the wheel and running the real
suite on Apple Silicon rather than trusting green CI.

1. THE P6 SOTA BINDINGS NEVER REACHED USERS (release blocker).
   `pip-release.yml`'s cibuildwheel built the DEFAULT feature set, so published
   wheels contained none of aether/mat/meridian. `pip install
   wifi-densepose[aether]` then raised ImportError — and the extra is empty, so
   its own error message ("install the [aether] extra") sent users in a circle.
   A pip extra cannot enable a Rust cargo feature on an already-built wheel, so
   the only way P6 reaches PyPI is to compile it in.

   Fix: the RELEASE build opts in via `MATURIN_PEP517_ARGS="--features sota"`
   (per-platform, since CIBW_ENVIRONMENT_LINUX overrides CIBW_ENVIRONMENT).
   `default = []` in Cargo.toml, the RuView#1387-default-wheel-budget-config
   fix-marker, and the wheel-size-budget job are all left UNTOUCHED — they keep
   guarding the small base compile. Measured published wheel: 1.68 MiB, well
   under the ADR-117 §5.4 5 MiB budget. Proven: built via the exact PEP517 path,
   `import wifi_densepose.aether/mat/meridian` all succeed.

2. THE WHEEL SMOKE TEST COULD NOT SEE #1.
   CIBW_TEST_COMMAND only asserted `hello()` and PRINTED `__build_features__`.
   The one signal that would reveal missing bindings was dumped to stdout and
   ignored, so a featureless wheel published green. It now ASSERTS the p6
   features are present and imports the three modules. Proven red→green: fails
   on the old featureless wheel ("missing SOTA bindings: [...]"), passes on the
   fixed one.

3. THE AETHER PARITY TESTS WERE NOT PORTABLE ACROSS THE WHEEL MATRIX.
   `test_aether.py` and the native `aether_parity.rs`/`aether_weights_parity.rs`
   hashed the raw f32 embedding bytes (SHA-256) against a committed golden. The
   embedding is pure f32 with transcendental ops (ln/sqrt/cos) that are not
   bit-reproducible across CPUs/libm, so the hash only ever matched the one arch
   that generated it. This passed in python-ci (x86) but fails on the aarch64 /
   macOS-arm wheels this same project ships — latent until #1 is fixed and the
   bindings actually load. Every tolerance/behavioral assertion already passed;
   only the two byte-hash tests failed, which is the signature of a non-portable
   golden, not a logic bug.

   Fix: compare to a committed golden VECTOR within tolerance
   (atol=rtol=1e-4 — ~100x cross-arch f32 drift, ~100x under any real algorithm
   change), on both the Python and native sides against the SAME golden. Native
   ≈ golden and binding ≈ golden together prove binding ≈ native, portably.
   `.sha256` goldens replaced by `.json` vectors.

Also: the aether/mat/meridian import shims told users to `pip install
wifi-densepose[<x>]` on a missing feature — an empty extra that cannot help.
Corrected to name the real fix (rebuild with `--features <x>`); message tests
updated to assert the honest message and forbid the misleading one.

Verified on aarch64/macOS: full `python/tests/` suite 227 passed against a wheel
built with the new mechanism; `cargo check --tests --features aether` clean.
The native `.rs` parity tests were converted by inspection and cargo-checked but
not executed — they link against the PyO3 crate and no workflow runs them today
(a pre-existing gap; wiring `cd python && cargo test --features sota` into
python-ci would make the native anchor actually run).

Co-Authored-By: Ruflo & AQE
2026-07-24 10:45:00 +02:00
..

wifi-densepose

PyPI version Python License: MIT

Detect human presence, count people, read breathing and heart rate, and estimate skeletal pose — using only the WiFi signal already in your home.

No cameras. No wearables. Works through walls and in the dark.

wifi-densepose is the Python binding for the RuView sensing stack: a Rust core that turns the Channel State Information (CSI) emitted by ordinary WiFi chips into ambient-intelligence signals. The wheel ships compiled DSP for fast offline analysis, plus an opt-in Python client for talking to a live RuView sensing-server over WebSocket or MQTT.

Features

  • 17-keypoint pose — full-body skeletal estimate from WiFi CSI, no camera
  • Vital signs — respiratory rate (630 BPM) and heart rate (40120 BPM) with a confidence score and clinical-grade / degraded / unreliable status
  • Presence, person count, fall detection, motion — fused outputs from the same CSI stream
  • 10 semantic primitives (HA-MIND) — someone-sleeping, possible-distress, room-active, bathroom-occupied, fall-risk-elevated, bed-exit, … — ready to wire into Home Assistant or Apple Home automations
  • Beamforming Feedback (BFLD) support — 802.11ac/ax/be compressed feedback matrices on top of the receiver-side CSI path
  • GIL-releasing DSP — extract loops run with the GIL released, so a tokio-backed web server can call into the pipeline without stalling its event loop
  • Tiny wheel — ~240 KB compiled (one binary per OS/arch covers Python 3.10+ via the stable ABI)

Install

pip install wifi-densepose                 # core DSP only
pip install "wifi-densepose[client]"       # + WebSocket/MQTT clients

Wheels are published for Linux (x86_64, aarch64), macOS (x86_64, arm64), and Windows (amd64).

SOTA extras (ADR-185)

Three optional subsystems bind the Rust SOTA modules as compiled-feature wheels. Each raises a clear ImportError if you import it without the extra:

Extra Module What it adds
[aether] wifi_densepose.aether Contrastive CSI embeddings / re-identification (ADR-024) — EmbeddingExtractor, cosine_similarity, info_nce_loss
[meridian] wifi_densepose.meridian Cross-environment domain generalization (ADR-027) — HardwareNormalizer, GeometryEncoder, RapidAdaptation, CrossDomainEvaluator
[mat] wifi_densepose.mat Mass-Casualty Assessment disaster-survivor detection + START triage — DisasterResponse, Survivor, TriageStatus
[sota] all three Convenience superset
pip install "wifi-densepose[aether]"       # re-identification embeddings
pip install "wifi-densepose[meridian]"     # cross-room calibration
pip install "wifi-densepose[mat]"          # disaster triage
pip install "wifi-densepose[sota]"         # all three

Runnable examples: examples/reid_from_csi.py, examples/cross_room_calibrate.py, examples/mat_triage.py.

Usage

Extract breathing rate from a CSI stream

from wifi_densepose import BreathingExtractor

br = BreathingExtractor.esp32_default()     # 56 subcarriers @ 100 Hz, 30s window

for residuals, weights in your_csi_source:  # one frame at a time
    est = br.extract(residuals=residuals, weights=weights)
    if est is not None:
        print(f"{est.value_bpm:.1f} BPM  (confidence={est.confidence:.2f})")

Heart rate is the same shape — HeartRateExtractor.esp32_default() with a 0.82.0 Hz band-pass and a 15-second window.

Subscribe to a live sensing-server

import asyncio
from wifi_densepose.client import SensingClient, EdgeVitalsMessage

async def main():
    async with SensingClient("ws://your-ruview-node:8765/ws/sensing") as c:
        async for msg in c.stream():
            if isinstance(msg, EdgeVitalsMessage):
                print(msg.presence, msg.breathing_rate_bpm, msg.heartrate_bpm)

asyncio.run(main())

React to Home Assistant semantic primitives

from wifi_densepose.client import (
    RuViewMqttClient, SemanticPrimitive, SemanticPrimitiveListener,
)

listener = SemanticPrimitiveListener()
listener.on(SemanticPrimitive.BedExit, lambda e: print("bed exit:", e.node_id))
listener.on(SemanticPrimitive.PossibleDistress, lambda e: alert(e))

client = RuViewMqttClient(broker_host="homeassistant.local")
client.on_message(
    "homeassistant/+/wifi_densepose_+/+/state",
    listener.handle_mqtt_message,
)
client.start()
client.wait_connected()

Decode 802.11ax beamforming feedback

import numpy as np
from wifi_densepose import BfldFrame, BfldKind

# Parse compressed BFR from a Wireshark capture into a Complex64 ndarray ...
fb = np.zeros((2, 1, 996), dtype=np.complex64)  # Nr=2 Nc=1 Nsc=996 for HE80

frame = BfldFrame.from_compressed_feedback(
    timestamp_ms=ts,
    sounding_index=seq,
    sta_mac="aa:bb:cc:dd:ee:ff",
    kind=BfldKind.CompressedHE80,
    feedback_matrix=fb,
)
print(frame.n_subcarriers, frame.mean_amplitude)

Hardware

Works with any WiFi chip that exposes CSI. Reference setups (ESP-IDF firmware, build scripts, witness-verified test bundles) are in the RuView repo:

Device Cost Role
ESP32-S3 (8MB flash) ~$9 WiFi CSI sensing node
ESP32-S3 SuperMini (4MB) ~$6 WiFi CSI (compact)
ESP32-C6 + Seeed MR60BHA2 ~$15 mmWave HR/BR/presence add-on

The legacy v1 line (Wi-Pose-style FastAPI server) is end-of-life; wifi-densepose==1.99.0 is a tombstone that raises ImportError pointing to v2 with a migration URL.

License

MIT.