# RuView — WiFi CSI spatial-intelligence nodes (Phase 2)

Real upstream project: **[github.com/ruvnet/ruview](https://github.com/ruvnet/ruview)**
— a WiFi Channel-State-Information (CSI) platform that detects presence, tracks
movement/pose, and infers semantic room states (see §2 below) through walls,
without a camera. **This repo does not reimplement any of RuView's CSI
firmware or signal processing** — that's genuine DSP research code (Rust +
ESP-IDF, running on-device), and fabricating it from scratch rather than
integrating the real thing would be exactly the kind of guess this project's own
conventions exist to avoid. What lives in this directory is a thin, honest wrapper
around RuView's own tooling, matching how this repo already treats Frigate/
Zigbee2MQTT/Grocy — integrated, not forked.

This is a different device from `firmware/esphome-ble-proxy/` — separate
hardware, separate job, per `docs/project-plan.md` §1.5's "separate hardware from
RuView nodes" note. BLE proxies resolve *who* (via Bermuda/Private BLE Device);
RuView nodes sense *room activity/vitals*, camera-free.

## 1. Hardware

Per RuView's own README (confirmed via the link above, not guessed):

| Board | Price | Role |
|---|---|---|
| **ESP32-S3** | ~€9 | Primary target — CSI capture + edge processing |
| ESP32-C6 | €6–10 | Research variant, WiFi 6 + dual-band |
| Intel 5300 / Atheros AR9580 (research NICs) | €50–100 | Higher-fidelity research hardware, not a household pick |
| Cognitum Seed (optional) | ~€140 | Persistent storage / vector search / witness-chain, not required for basic presence |

**ESP32-C3 and the original ESP32 are explicitly NOT supported** (RuView's own
README: "single-core, insufficient for CSI DSP") — this updates
`docs/project-plan.md` §1.6's original "ESP32-S3 dev board" pick from a general
recommendation to a confirmed hard requirement.

## 2. What it publishes — and why that's more sensitive than plain presence

RuView ships **21 MQTT entities per node** via its own `HA-DISCO` MQTT
auto-discovery publisher: 11 raw signals plus 10 inferred semantic states —
`someone-sleeping`, `possible-distress`, `room-active`, `elderly-inactivity-
anomaly`, `meeting-in-progress`, `bathroom-occupied`, `fall-risk-elevated`,
`bed-exit`, `no-movement`, `multi-room-transition`. It can also estimate
breathing/heart rate.

**This is a meaningfully bigger privacy surface than the plain occupancy sensor
`docs/project-plan.md`'s original Phase 2 sketch assumed.** Bathroom-occupancy,
sleep state, and vitals-adjacent inference are the kind of data this project has
otherwise been careful about (see `identity/README.md`'s "Anti-spoofing" and
"People without a device" sections for the same care applied to identity/consent).
**Nothing in this repo currently gives household members a way to opt out of a
specific room's RuView sensing, or restricts who these MQTT topics are visible
to beyond the same trust boundary as every other entity on this network.** Treat
this as an explicit open decision (`docs/project-plan.md` §4) before wiring
automations against the more sensitive semantic states, not something silently
safe by default just because the network is local.

## 3. Build + flash — RuView's own tooling, not this repo's

This repo does not vendor RuView's source. Clone and build it yourself per its own
README:

```sh
git clone https://github.com/ruvnet/ruview ~/ruview
cd ~/ruview
# Rust 1.85+ and the ESP-IDF toolchain are prerequisites — see RuView's own docs
idf.py set-target esp32s3   # or esp32c6 for that variant
idf.py build
python -m esptool --chip esp32s3 --port /dev/ttyUSB0 --baud 460800 write_flash ...
```

**VERIFY the exact build/flash command against whatever version you actually
clone** — the commands above are transcribed from RuView's own README as fetched
during this session, not independently run against real hardware from within this
project; upstream commands/flags can and do change between releases.

## 4. Provisioning per room — `provision-room.sh`

Once a node is flashed, it needs Wi-Fi + this stack's MQTT broker credentials.
RuView ships its own `firmware/esp32-csi-node/provision.py` for this;
`provision-room.sh` in this directory is a **thin wrapper** that fills in this
project's own settings (same Mosquitto broker every other service already uses,
Phase 1) so you don't retype them per node:

```sh
cp rooms.env.example rooms.env    # fill in RUVIEW_REPO_DIR, Wi-Fi, MQTT_BROKER_HOST
chmod 600 rooms.env
./provision-room.sh living-room /dev/ttyUSB0
```

Only `--port`/`--ssid`/`--password`/`--mqtt` are passed by the wrapper — those
four flags are the ones confirmed against RuView's own README during this
session. **Anything else `provision.py` might need in your specific installed
version (MQTT auth flags, a node-naming flag, etc.) is NOT guessed here** — pass
it as an extra argument to `provision-room.sh` after checking
`python3 ~/ruview/firmware/esp32-csi-node/provision.py --help` against your real
checkout first.

## 5. Automations built on RuView's semantic states

You've confirmed you want these wired up despite §2's privacy note — the concrete
rules requested, all in `automations.yaml.example` (paste whichever ones you want
into your own HA config, same "nothing under this repo merges into your HA config
for you" convention as identity's own worked `rest_command` example):

1. **Someone asleep → dim that room's lights.** Straightforward state trigger →
   `light.turn_on` at low brightness/warm color temp.
2. **Possible distress → alert everyone home.** Mapped to RuView's own
   `possible-distress` semantic state — **this is RuView's closest documented
   inference to "a heart attack," there is no literal heart-attack-detection
   entity, and this repo does not build its own medical-anomaly detection on top
   of RuView's raw signals.** The automation bridges that state to an urgent
   `ntfy` push (via a `rest_command:`, same pattern as every other ntfy-posting
   service in this stack) plus a whole-house TTS announcement across every
   `media_player` you list, plus flashing every light red as a visual backup.
   Whatever RuView's real accuracy turns out to be is entirely upstream's, not
   something this bridge changes — **do not treat this as a substitute for an
   actual medical alert device/service.**
3. **Two people's heart rate elevated concurrently in the same room → red/
   magenta/violet lighting.** Approximated as "both above an elevated threshold
   at the same time" rather than a true rate-of-change trigger (deliberately —
   derivative triggers on noisy CSI-derived vitals are far more false-trigger-
   prone than a plain threshold). **This is the single most uncertain rule in
   this file**: RuView's fetched README doesn't confirm whether one node can
   actually distinguish and report two distinct people's heart rates
   concurrently at all — multi-target vital-sign separation from WiFi CSI is a
   genuinely hard, actively-researched problem. Confirm you have two real
   per-person heart-rate entities for a room before trusting this can fire as
   described; if there's only one aggregate entity per node, this rule needs a
   different design once you know that, not a guess made now.
4. **Bathroom occupied → an external indicator outside the door.** You mentioned
   you'll likely add a dedicated light/actor for this — the automation targets a
   placeholder `switch.bathroom_door_indicator`; swap it for whatever you end up
   choosing (worth adding to `components.md`'s Zigbee list once picked, same as
   every other Zigbee actuator in this project).

**Every `entity_id` in `automations.yaml.example` is a placeholder** — RuView's
README documents semantic-state *names*, not their exact post-MQTT-discovery HA
`entity_id`s (domain, underscore-vs-hyphen, per-node naming). Confirm every one
against Developer Tools → States on a real HA instance after provisioning a real
node before relying on any of this.

## 6. Home Assistant integration — likely nothing to build, but unverified

RuView's `HA-DISCO` publisher uses MQTT auto-discovery against the **same
Mosquitto broker** every other service in this stack already connects to (Phase 1)
— if that's accurate, entities should appear in HA automatically once a node is
provisioned and online, no manual entity/automation setup required to just *see*
the data. RuView's own docs reportedly include `docs/integrations/home-assistant.md`
and three starter HA Blueprints (per its README) for turning the semantic states
into actual automations — **none of that has been read in detail or verified from
within this project**, only the top-level README summary this section is built
from. Confirm the real doc before wiring anything beyond "the entities show up."

Same "nothing under this repo builds the HA side" convention as every entry in
`docs/project-plan.md`'s HA-integrations catalog (§2) — automations against
RuView's semantic states are a decision for you to make deliberately, especially
given §2's privacy note above, not something this repo pre-wires.

## Manual verification still outstanding

1. Nothing here has been run against real hardware, a real RuView checkout, or a
   real MQTT broker from within this project — §3's build commands and §4's
   `provision.py` flags are transcribed from RuView's own README, not
   independently confirmed.
2. `docs/integrations/home-assistant.md` / RuView's HA Blueprints (§6) — described
   secondhand from the top-level README, not read directly.
3. The privacy/consent gap in §2 — the household-level decision has been made
   (you want this data and the automations built on it), but there is still no
   technical opt-out for a specific person/room, and no access restriction on
   these MQTT topics beyond this network's normal trust boundary. Worth revisiting
   if anyone who isn't fully on board with being sensed this way ever stays over.
4. `docs/project-plan.md` §1.6/§2's RuView entries — updated this session to
   match §1 above (ESP32-C3/original-ESP32 unsupported, real hardware tiers), but
   the phased implementation plan (Phase 2) itself still describes RuView only at
   the "deploy nodes per room" level of detail from before this integration pass.
5. **`automations.yaml.example`'s entity_ids are ALL placeholders** — none of
   §5's four automations have been run against real RuView entities; in
   particular rule 3 (concurrent two-person heart rate) rests on an unconfirmed
   assumption that a single node can even report two people's heart rates at
   once, see that automation's own prominent warning comment.
