docs(casaos): add CasaOS-ready docker compose, icon, and Docker guide

- docker-compose.casaos.yml: prebuilt-image compose with x-casaos app
  metadata; host ports 3030/3031/5005 to avoid local clashes
- assets/ruview-icon.png: 512x512 square app icon
- docs/DOCKER-CASAOS.md: Docker + CasaOS run/import guide, ESP32-S3 setup
- README: link the new guide from Quick Start and the docs table

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lorenzo Argentieri 2026-05-23 00:21:33 +02:00
parent 68abb385ae
commit 296370d4b4
4 changed files with 274 additions and 0 deletions

View File

@ -79,6 +79,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.casaos.yml with an app tile)
# Option 2: Live sensing with ESP32-S3 hardware ($9)
# Flash firmware, provision WiFi, and start sensing:
@ -561,6 +563,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.casaos.yml`, import as a CasaOS app tile, and connect ESP32-S3 nodes |
| [Build Guide](docs/build-guide.md) | Building from source (Rust and Python) |
| [Claude Code / Codex Plugin](plugins/ruview/README.md) | The `ruview` plugin + marketplace — skills, `/ruview-*` commands, agents, and the Codex prompt mirror |
| [Architecture Decisions](docs/adr/README.md) | 96 ADRs — why each technical choice was made, organized by domain (hardware, signal processing, ML, platform, infrastructure) |

BIN
assets/ruview-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

101
docker-compose.casaos.yml Normal file
View File

@ -0,0 +1,101 @@
# RuView — WiFi DensePose sensing server, CasaOS-ready compose.
#
# Uses the prebuilt image (amd64) from Docker Hub, so the CasaOS host does NOT
# need to compile the Rust workspace. (This server is amd64. For arm64 hosts the
# published tag has no arm64 layer yet — build locally with the dev compose:
# `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.
#
# Host ports were chosen to avoid clashes on this server (3000/3001 are already
# in use): the UI is published on 3030, the WebSocket on 3031, ESP32 CSI on 5005/udp.
#
# Import into CasaOS: App Store → Custom Install → paste this file, OR
# cd /DATA/AppData/ruview && docker compose -f docker-compose.casaos.yml up -d
#
# Open the dashboard at: http://192.168.1.177:3030
#
# 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/Aiacos/ruview@main/assets/ruview-icon.png
ports:
- mode: ingress
target: 3000
published: "3030"
protocol: tcp
- mode: ingress
target: 3001
published: "3031"
protocol: tcp
- 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/Aiacos/ruview@main/assets/ruview-icon.png
index: /
is_uncontrolled: false
port_map: "3030"
scheme: http
tagline:
en_us: See through walls with WiFi — contactless presence, breathing & pose sensing
custom: Vedere attraverso i muri con il WiFi — presenza, respiro e posa senza contatto
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.
custom: |
RuView (WiFi DensePose) trasforma il normale WiFi in un sensore spaziale
senza contatto. Usando le Channel State Information (CSI) di nodi ESP32-S3
a basso costo rileva le persone attraverso i muri, stima respiro e battito
cardiaco, traccia movimento e cadute ed esegue la stima della posa a 17
punti — niente telecamere, niente dispositivi indossabili. Questa immagine
avvia il server Rust con la dashboard web. Con CSI_SOURCE=simulated funziona
con dati sintetici senza hardware; per il sensing dal vivo invia le CSI di
uno o più nodi ESP32-S3 sulla porta UDP 5005.
title:
en_us: RuView
custom: RuView
thumbnail: https://cdn.jsdelivr.net/gh/Aiacos/ruview@main/assets/ruview-icon.png

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

@ -0,0 +1,170 @@
# 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.casaos.yml up -d
```
Then open the dashboard:
```
http://<host-ip>:3030
```
`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.casaos.yml down
```
---
## 2. Ports
The compose file (`docker-compose.casaos.yml`) publishes **non-default host
ports** because 3000/3001 are commonly already in use:
| Service | Container | Host (this compose) | Notes |
|------------------------|-----------|---------------------|-------|
| REST API + web UI | 3000/tcp | **3030** | Dashboard lives here (`/`, `/ui/...`) |
| WebSocket sensing feed | 3001/tcp | **3031** | `ws://host:3031/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.casaos.yml`. 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.casaos.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.casaos.yml`.
3. Install. The tile opens `http://<host-ip>:3030`.
**Option B — CLI (CasaOS still detects the container)**
```bash
cd /DATA/AppData/ruview
docker compose -f docker-compose.casaos.yml up -d
```
> **Icon:** the manifest points at
> `https://cdn.jsdelivr.net/gh/Aiacos/ruview@main/assets/ruview-icon.png`.
> jsDelivr serves it from the GitHub repo, so commit & push `assets/ruview-icon.png`
> to the `main` branch for the icon to resolve. Until then CasaOS shows a
> placeholder; everything else works. To use a fully local icon instead, replace
> both `icon:` URLs (in `labels:` and `x-casaos:`) with 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.casaos.yml pull
docker compose -f docker-compose.casaos.yml up -d
# Status of the running server
curl -s http://<host-ip>:3030/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 3030/3031:* edit `published:` in `docker-compose.casaos.yml`.