This commit is contained in:
Lorenzo Argentieri 2026-05-28 23:26:50 +02:00 committed by GitHub
commit d969ee7079
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 299 additions and 0 deletions

View File

@ -78,6 +78,8 @@ RuView turns ordinary WiFi into a contactless sensor. A $9 ESP32 board reads the
docker pull ruvnet/wifi-densepose:latest
docker run -p 3000:3000 ruvnet/wifi-densepose:latest
# Open http://localhost:3000
# CasaOS / docker compose? See docs/DOCKER-CASAOS.md (ready-made
# docker-compose.yml with an app tile)
# Option 2a: Live sensing with ESP32-S3 hardware ($9)
# Flash firmware, provision WiFi, and start sensing:
@ -587,6 +589,7 @@ Verify the plugin structure: `bash plugins/ruview/scripts/smoke.sh`. Full detail
| Document | Description |
|----------|-------------|
| [User Guide](docs/user-guide.md) | Step-by-step guide: installation, first run, API usage, hardware setup, training |
| [Docker & CasaOS](docs/DOCKER-CASAOS.md) | Run the sensing server via Docker / `docker-compose.yml`, import as a CasaOS app tile, and connect ESP32-S3 nodes |
| [Build Guide](docs/build-guide.md) | Building from source (Rust and Python) |
| [**Home Assistant + Matter Integration**](docs/integrations/home-assistant.md) | **Works with Home Assistant** via MQTT auto-discovery + **Works with Matter** (Apple Home / Google Home / Alexa / SmartThings) — full entity catalog, 3 starter blueprints, Lovelace dashboards, privacy mode, threshold tuning ([ADR-115](docs/adr/ADR-115-home-assistant-integration.md)). |
| [**BFLD — Beamforming Feedback Layer for Detection**](v2/crates/wifi-densepose-bfld/README.md) | New privacy-gated WiFi sensing layer that measures + structurally prevents identity leakage from 802.11ac/ax Beamforming Feedback Information. Three type-enforced invariants (raw BFI never exits node, identity embedding is in-RAM-only, cross-site correlation cryptographically impossible via per-site BLAKE3 keyed hash + daily rotation). Ships full operator surface (`BfldPipeline`, `BfldPipelineHandle`, Soul Signature `SoulMatchOracle` integration), MQTT topic router + HA-DISCO + availability + LWT, 3 operator HA blueprints, two runnable examples, eclipse-mosquitto:2 CI service container. 327+ tests. [ADR-118](docs/adr/ADR-118-bfld-beamforming-feedback-layer-for-detection.md) umbrella + sub-ADRs [119](docs/adr/ADR-119-bfld-frame-format-and-wire-protocol.md)/[120](docs/adr/ADR-120-bfld-privacy-class-and-hash-rotation.md)/[121](docs/adr/ADR-121-bfld-identity-risk-scoring.md)/[122](docs/adr/ADR-122-bfld-ruview-ha-matter-exposure.md)/[123](docs/adr/ADR-123-bfld-capture-path-nexmon-and-esp32.md). Research dossier: [`docs/research/BFLD/`](docs/research/BFLD/) (11 files, 13,544 words). |

BIN
assets/ruview-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

122
docker-compose.yml Normal file
View File

@ -0,0 +1,122 @@
# RuView — WiFi DensePose sensing server, CasaOS-ready compose.
#
# Uses the prebuilt image from Docker Hub, so the host does NOT need to compile
# the Rust workspace. (The published `:latest` tag is amd64; on arm64 hosts build
# locally first: `docker compose -f docker/docker-compose.yml build`.) The server
# hosts the REST API + web UI on one port, a WebSocket stream, and a UDP listener
# for ESP32-S3 CSI nodes.
#
# Import into CasaOS: App Store → Custom Install → paste this file, OR
# docker compose -f docker-compose.casaos.yml up -d
#
# Open the dashboard at: http://<host-ip>:3000/ui/index.html
# (the bare http://<host-ip>:3000/ root is just an API index — the visual
# dashboards live under /ui/: index.html, observatory.html, pose-fusion.html)
#
# If host ports 3000/3001 are already taken on your machine, change the
# `published:` values below (and `port_map` / `webui_port` to match the new UI port).
#
# Data source (CSI_SOURCE):
# auto probe UDP 5005 for an ESP32, else fall back to simulation (default)
# esp32 require real CSI frames from an ESP32-S3 node on UDP 5005
# simulated synthetic CSI, no hardware needed (good for first evaluation)
name: ruview
services:
ruview:
image: ruvnet/wifi-densepose:latest
container_name: ruview
hostname: ruview
labels:
icon: https://cdn.jsdelivr.net/gh/ruvnet/RuView@main/assets/ruview-icon.png
ports:
- mode: ingress
target: 3000
published: "3000"
protocol: tcp
- mode: ingress
target: 3001
published: "3001"
protocol: tcp
- mode: ingress
target: 5005
published: "5005"
protocol: udp
environment:
- RUST_LOG=info
# auto | esp32 | wifi | simulated (see header)
- CSI_SOURCE=${CSI_SOURCE:-auto}
- MODELS_DIR=/app/models
# Optional bearer-token auth on /api/v1/*. Leave empty for LAN-only use;
# set a token to require `Authorization: Bearer <token>`:
# RUVIEW_API_TOKEN=$(openssl rand -hex 32)
- RUVIEW_API_TOKEN=${RUVIEW_API_TOKEN:-}
volumes:
# Drop .rvf model files here to make them visible to the API.
- ./data/models:/app/models
restart: unless-stopped
networks:
default: null
networks:
default:
name: ruview_default
x-casaos:
architectures:
- amd64
main: ruview
author: self
developer: ruvnet
category: HomeAutomation
hostname: ""
icon: https://cdn.jsdelivr.net/gh/ruvnet/RuView@main/assets/ruview-icon.png
index: /ui/index.html
is_uncontrolled: false
port_map: "3000"
webui_port: 3000
scheme: http
tagline:
en_us: See through walls with WiFi — contactless presence, breathing & pose sensing
description:
en_us: |
RuView (WiFi DensePose) turns ordinary WiFi into a contactless spatial
sensor. Using Channel State Information (CSI) from low-cost ESP32-S3 nodes,
it detects people through walls, estimates breathing and heart rate, tracks
motion and falls, and runs 17-keypoint pose estimation — no cameras, no
wearables. This image runs the Rust sensing server with its web dashboard.
With CSI_SOURCE=simulated it works with synthetic data and no hardware;
point one or more ESP32-S3 CSI nodes at UDP 5005 for live sensing.
title:
en_us: RuView
thumbnail: https://cdn.jsdelivr.net/gh/ruvnet/RuView@main/assets/ruview-icon.png
screenshot_link:
- https://cdn.jsdelivr.net/gh/ruvnet/RuView@main/assets/ruview-icon.png
envs:
- container: CSI_SOURCE
description:
en_us: "Data source: auto (default) | esp32 | simulated. 'simulated' needs no hardware."
- container: RUVIEW_API_TOKEN
description:
en_us: "(Optional) bearer token to protect /api/v1/*. Leave empty for LAN-only use."
- container: MODELS_DIR
description:
en_us: "In-container path scanned for .rvf model files (default /app/models)."
- container: RUST_LOG
description:
en_us: "Log level: info (default), debug, warn, error."
ports:
- container: "3000"
description:
en_us: "Web UI + REST API (HTTP)."
- container: "3001"
description:
en_us: "WebSocket sensing stream."
- container: "5005"
description:
en_us: "ESP32-S3 CSI ingest (UDP)."
volumes:
- container: /app/models
description:
en_us: "Holds .rvf model files exposed via /api/v1/models."

174
docs/DOCKER-CASAOS.md Normal file
View File

@ -0,0 +1,174 @@
# Running RuView with Docker (and CasaOS)
This guide covers running the RuView **sensing server** (the Rust + Axum service
that hosts the REST API, WebSocket stream, and web dashboard) as a Docker
container, and importing it into [CasaOS](https://casaos.io/).
It uses the prebuilt image `ruvnet/wifi-densepose:latest` from Docker Hub, so the
host does **not** need to compile the Rust workspace.
> **Architecture note:** the published `:latest` tag currently ships an **amd64**
> layer only. On an amd64 host (e.g. an x86 mini-PC / NUC / Ryzen box) it runs as
> is. On arm64 (Raspberry Pi, etc.) build locally first:
> `docker compose -f docker/docker-compose.yml build`.
---
## 1. Quick start (no hardware)
```bash
cd ruview
CSI_SOURCE=simulated docker compose -f docker-compose.yml up -d
```
Then open the dashboard:
```
http://<host-ip>:3000/ui/index.html
```
> The bare root `http://<host-ip>:3000/` is only an **API index** (a plain list
> of endpoints) — the visual dashboards live under `/ui/`:
> `index.html` (main), `observatory.html` (live feed), `pose-fusion.html`
> (webcam + CSI), `viz.html` (3D).
`CSI_SOURCE=simulated` feeds the pipeline with synthetic CSI so you can explore
the dashboard, API, and vital-sign/pose visualizations without any hardware.
Stop / remove:
```bash
docker compose -f docker-compose.yml down
```
---
## 2. Ports
The compose file (`docker-compose.yml`) publishes these host ports:
| Service | Container | Host | Notes |
|------------------------|-----------|------|-------|
| REST API + web UI | 3000/tcp | **3000** | Dashboard lives here (`/`, `/ui/...`) |
| WebSocket sensing feed | 3001/tcp | **3001** | `ws://host:3001/ws/sensing` |
| ESP32 CSI ingest | 5005/udp | **5005** | ESP32-S3 nodes stream CSI frames here |
If a host port clashes on your machine, edit the `published:` values in
`docker-compose.yml` (and update `port_map` / `webui_port` in the
`x-casaos` block to match the new UI port). The dashboard's WebSocket URL is
derived from the page host, so keep the API and WS ports reachable from the same
hostname.
Verified endpoints (all return `200` once running):
```
/ /ui/index.html /ui/observatory.html
/api/v1/status /api/v1/sensing/latest /api/v1/models
```
---
## 3. Data source modes (`CSI_SOURCE`)
| Value | Behaviour |
|-------------|-----------|
| `auto` | (default) Probe UDP 5005 for an ESP32 node; fall back to `simulated`. |
| `esp32` | Require real CSI frames from an ESP32-S3 node on UDP 5005. |
| `simulated` | Synthetic CSI — no hardware. Best for first evaluation. |
| `wifi` | Host Wi-Fi RSSI/scan (Windows `netsh`) — **not** available inside a Linux container. |
Set it inline (`CSI_SOURCE=esp32 docker compose ... up -d`) or via a `.env` file
next to the compose, or in the CasaOS environment-variable UI.
### Models
Drop `.rvf` model files into `./data/models/` (mounted to `/app/models`); the API
exposes them under `/api/v1/models`. Pretrained weights:
```bash
pip install huggingface_hub
huggingface-cli download ruvnet/wifi-densepose-pretrained --local-dir data/models/wifi-densepose-pretrained
```
### Optional API auth
Leave `RUVIEW_API_TOKEN` empty for LAN-only use. Set it to require
`Authorization: Bearer <token>` on `/api/v1/*`:
```bash
RUVIEW_API_TOKEN=$(openssl rand -hex 32) docker compose -f docker-compose.yml up -d
```
---
## 4. Importing into CasaOS
The compose file includes an `x-casaos:` metadata block (icon, title, category,
description, port map), so CasaOS shows it as a proper app tile.
**Option A — CasaOS UI (Custom Install)**
1. CasaOS dashboard → **App Store****Custom Install** (the `+` / "Install a
customized app").
2. Switch to the **Import** / YAML view and paste the contents of
`docker-compose.yml`.
3. Install. The tile opens `http://<host-ip>:3000/ui/index.html`.
**Option B — CLI (CasaOS still detects the container)**
```bash
cd ruview
docker compose -f docker-compose.yml up -d
```
> **Icon:** the manifest points at
> `https://cdn.jsdelivr.net/gh/ruvnet/RuView@main/assets/ruview-icon.png`
> (jsDelivr serves `assets/ruview-icon.png` straight from the repo). To use a
> different or fully local icon, replace both `icon:` URLs (in `labels:` and
> `x-casaos:`) with another URL or a file path served by your own host.
---
## 5. Connecting live ESP32-S3 CSI nodes
RuView's full capability set (presence through walls, breathing/heart rate, fall
detection, pose) needs **Channel State Information** from a CSI-capable node.
1. Flash the firmware from `firmware/esp32-csi-node/` to an **ESP32-S3**
(8 MB or 4 MB). See the repo `CLAUDE.md` "ESP32 Firmware Build" section.
2. Provision Wi-Fi + the sink (this server's) IP:
```bash
python firmware/esp32-csi-node/provision.py --port /dev/ttyUSB0 \
--ssid "YourWiFi" --password "secret" --target-ip <host-ip>
```
Point `--target-ip` at the host running this container; frames arrive on
**UDP 5005**.
3. Start with `CSI_SOURCE=esp32` (or `auto`).
> **Supported chips:** ESP32-**S3** (dual-core) and ESP32-**C6**. The original
> ESP32 and ESP32-**C3** are **single-core** and cannot run the CSI DSP pipeline.
---
## 6. Operations
```bash
# Logs
docker logs ruview -f --tail 100
# Restart / update to the latest image
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d
# Status of the running server
curl -s http://<host-ip>:3000/api/v1/status
```
**Troubleshooting**
- *Dashboard loads but no data:* check the data source — with `auto` and no ESP32
present it falls back to `simulated`; logs print `Data source: ...`.
- *Multiple ESP32 nodes on Docker Desktop for Windows:* multi-source UDP collapses
to one source IP at the WSL boundary. Use the host relay (see
`docs/TROUBLESHOOTING.md §9`). Native Linux/CasaOS hosts are unaffected.
- *Port clash on 3000/3001:* edit `published:` in `docker-compose.yml`.