get started

run it yourself

Clone the repository, run the gateway against the synthetic source, and read the API. No hardware is needed: the demo and the replay path run the same pipeline the sensors will. The questions people ask first are at the end of the page.

one gateway, several surfaces

Everything the gateway serves has already passed the consent gate and the caller's role. Nothing can show more than the space allowed.

  • HTTP APIbuilt

    Spaces, events, links and gateway health, as JSON.

  • WebSocketbuilt

    State every 0.5 s, plus events as they happen.

  • Prometheus /metricsbuilt

    Sensor and gateway health for Grafana.

  • Event log and replaybuilt

    Daily JSONL with retention. Recorded pcaps replay through the same pipeline, producing the same readings as the ingest path.

  • MQTT and Home Assistantplanned

    Retained occupancy per space, so lights and AC can follow it with no custom code.

  • Telegram and webhook alertsplanned

    Acknowledge, resolve and escalate. By default no health numbers leave campus.

run it

# no hardware: the synthetic source models the radio physics
python3 -m wifisense demo

# host DSP tests, then firmware (Docker is the only dependency)
edge/build.sh tests
edge/build.sh menuconfig        # role, channel, consent, gateway
PORT=/dev/ttyUSB0 edge/build.sh flash-monitor

# the gateway: API, WebSocket, /metrics, dashboard
cd rust
cargo run --release -p saans-gateway -- --config saans.toml

# replay a recording through the same pipeline
python3 -m wifisense replay run.pcap --node 3

http api

GET  /api/spaces             # every space: state, name, privacy, alerts
GET  /api/spaces/{id}        # one space and its last 50 events
GET  /api/events?space=&since=&limit=
GET  /api/links              # rate, loss, calibration per link
GET  /api/health             # the gateway's own health
GET  /metrics                # Prometheus text format
GET  /api/live               # WebSocket

# machines carry a token; what comes back depends on its role
curl -H "Authorization: Bearer $SAANS_TOKEN" \
     http://gateway:8080/api/spaces

live

const ws = new WebSocket("ws://gateway:8080/api/live");

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === "state") render(msg);   // every 0.5 s
  if (msg.type === "event") log(msg);      // as they happen
};

a space

// one space's state, as the API returns it (illustrative values)
{
  "space_id": "lab-214",
  "occupied": true,            // null = can't tell
  "still_for_s": 372.5,
  "motion_index": 0.81,
  "breathing": {                // null unless the space opted in
    "link": { "rx": 2, "tx": 1 },
    "bpm": 15.0,
    "confidence": 0.92,
    "band_rms": 0.0123,
    "noise_rms": 0.0031
  },
  "bpm_median_5min": 15.1,
  "bpm_iqr_5min": 0.8,
  "motion_bouts_last_hour": 3,
  "resting": true,
  "in_breathing_pause": false,
  "links_usable": 2,
  "links_total": 2,
  "vitals": true,
  "active_alerts": []
}

a few questions

What it sees, what it doesn't, and where the evidence stops.

Does it use a camera or a microphone at any point?

No. Sensors read radio amplitude and phase, compute features on the board, and send 68 bytes twice a second. There is no image or audio anywhere in the system that could leak.

Can it tell who is in a room, or take attendance?

No, by design. Device-free WiFi sensing cannot tell people apart, and Saans never tries to. It reports spaces, never individuals.

How accurate is it, really?

On held-out synthetic timelines, occupancy is 98–99.5% accurate and breathing is within 1 BPM 94–100% of the time, depending on the number of links. Real ESP32 noise, real rooms and real bodies have not been measured yet. That is phase S5, and it needs hardware.

Is it a medical device?

No. Breathing and heart outputs are engineering measurements. Alerts are advisory and never replace existing procedures, and each one records what it saw and how confident it was.

Why is heart rate off?

CSI amplitude is nonlinear in chest movement, so breathing harmonics and intermodulation products can be stronger than the cardiac peak. Gating on confidence makes the estimate right 97% of the time, but it then abstains on 39% of scenarios. It stays off until it has been measured against a reference.

Does it detect falls?

No. A possible-collapse detector exists and caught every simulated fall, and every sit-down too, because amplitude-only WiFi cannot see height. It ships off.

Does it slow down the WiFi?

It adds a little airtime. A dedicated TX board broadcasts a 12-byte ESP-NOW frame 50 times a second on one channel, so the sample rate is under Saans's control. It never joins or inspects the network's traffic.

Does it need the internet?

No. Sensors talk to a gateway on the campus network, and the API, dashboard and event log are all local. Nothing calls a cloud service.

Does it work through walls?

Radio passes through drywall, and a link can span two rooms, but Saans makes no through-wall claim until one has been measured.

What does it cost?

The software is MIT-licensed. A room needs two ESP32-S3 boards at about $6–10 each, and a building needs one gateway, such as a Raspberry Pi 5.

keep reading