6.1 KiB
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.
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
:latesttag 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)
cd ruview
CSI_SOURCE=simulated docker compose -f docker-compose.casaos.yml up -d
Then open the dashboard:
http://<host-ip>:3030/ui/index.html
The bare root
http://<host-ip>:3030/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:
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:
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/*:
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)
- CasaOS dashboard → App Store → Custom Install (the
+/ "Install a customized app"). - Switch to the Import / YAML view and paste the contents of
docker-compose.casaos.yml. - Install. The tile opens
http://<host-ip>:3030/ui/index.html.
Option B — CLI (CasaOS still detects the container)
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 & pushassets/ruview-icon.pngto themainbranch for the icon to resolve. Until then CasaOS shows a placeholder; everything else works. To use a fully local icon instead, replace bothicon:URLs (inlabels:andx-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.
- Flash the firmware from
firmware/esp32-csi-node/to an ESP32-S3 (8 MB or 4 MB). See the repoCLAUDE.md"ESP32 Firmware Build" section. - Provision Wi-Fi + the sink (this server's) IP:
Pointpython firmware/esp32-csi-node/provision.py --port /dev/ttyUSB0 \ --ssid "YourWiFi" --password "secret" --target-ip <host-ip>--target-ipat the host running this container; frames arrive on UDP 5005. - Start with
CSI_SOURCE=esp32(orauto).
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
# 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
autoand no ESP32 present it falls back tosimulated; logs printData 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:indocker-compose.casaos.yml.