generated from CubeCraft-Creations/Tracehound
RemoteRig: Core infrastructure — MQTT subscriber, Pi deployment, ESP32 firmware, hardware design #5
+99
-57
@@ -1,10 +1,11 @@
|
|||||||
# RemoteRig — Project Context
|
# RemoteRig — Project Context
|
||||||
|
|
||||||
> **Last updated:** 2026-05-21
|
> **Last updated:** 2026-05-21 (evening — post-planning sync)
|
||||||
> **Repo:** `CubeCraft-Creations/remote-rig` | **Host:** `code.cubecraftcreations.com`
|
> **Repo:** `CubeCraft-Creations/remote-rig` | **Host:** `code.cubecraftcreations.com`
|
||||||
> **Local clone:** `/mnt/ai-storage/projects/remote-rig` | **Default branch:** `dev`
|
> **Local clone:** `/mnt/ai-storage/projects/remote-rig` | **Default branch:** `dev`
|
||||||
> **Discord:** `DISCORD_DEV_REMOTERIG_CHANNEL_ID`
|
> **Discord:** `DISCORD_DEV_REMOTERIG_CHANNEL_ID`
|
||||||
> **Linear Epic:** [CUB-198](https://linear.app/cubecraft-creations/issue/CUB-198)
|
> **Linear Epic:** [CUB-198](https://linear.app/cubecraft-creations/issue/CUB-198)
|
||||||
|
> **MQTT Contract:** [docs/MQTT_CONTRACT.md](./docs/MQTT_CONTRACT.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -33,35 +34,49 @@ RemoteRig is a **multi-camera remote monitoring system**. It provides a camera g
|
|||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
ESP32 Node (per camera)
|
┌──────────────────────────────────────────┐
|
||||||
│
|
│ Travel Router (self-contained LAN) │
|
||||||
├── HTTP POST /api/v1/cameras/:id/status (status push)
|
│ Subnet: 192.168.4.0/24 │
|
||||||
│
|
│ DHCP pool: .100-.200 │
|
||||||
└── MQTT ──→ Mosquitto Broker ──→ MQTT Subscriber (Go hub)
|
└──────┬──────────┬──────────┬──────────────┘
|
||||||
│
|
│ │ │
|
||||||
▼
|
┌───────────────┘ │ └───────────────┐
|
||||||
┌──────────────────────────────┐
|
▼ ▼ ▼
|
||||||
│ Go Central Hub (Pi Zero 2 W)│
|
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
|
||||||
│ ┌────────────────────┐ │
|
│ ESP32 #1 │ │ ESP32 #N │ │ Pi Zero 2 W │
|
||||||
│ │ SQLite Database │ │
|
│ DHCP addr │ │ DHCP addr │ │ 192.168.4.10 │
|
||||||
│ └────────────────────┘ │
|
│ │ │ │ │ (static IP) │
|
||||||
│ ┌────────────────────┐ │
|
│ STA→GoPro AP │ │ STA→GoPro AP │ │ │
|
||||||
│ │ SSE Hub │ │
|
│ STA→Router │ │ STA→Router │ │ Mosquitto :1883 │
|
||||||
│ └────────────────────┘ │
|
│ │ │ │ │ Go API :8080 │
|
||||||
└──────────────────────────────┘
|
│ MQTT→:1883 │ │ MQTT→:1883 │ │ React UI │
|
||||||
│
|
└──────┬───────┘ └──────┬───────┘ │ SQLite DB │
|
||||||
SSE /api/v1/events/stream
|
│ │ └──────────────────┘
|
||||||
│
|
▼ ▼ │
|
||||||
▼
|
┌──────────────┐ ┌──────────────┐ │
|
||||||
React Dashboard (Browser)
|
│ GoPro Hero 3 │ │ GoPro Hero 3 │ SSE /api/v1/events/stream
|
||||||
|
│ AP: 10.5.5.1 │ │ AP: 10.5.5.1 │ │
|
||||||
|
│ Wi-Fi only │ │ Wi-Fi only │ ▼
|
||||||
|
└──────────────┘ └──────────────┘ ┌──────────────────┐
|
||||||
|
│ User Device │
|
||||||
|
│ (laptop/kiosk) │
|
||||||
|
│ http://.4.10 │
|
||||||
|
└──────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key Architecture Decisions
|
**Network is fully self-contained — no internet dependency.** The travel router creates the LAN. All devices connect to it. The Pi runs all services (Mosquitto, Go API, React UI, SQLite). ESP32s bridge the GoPro's AP to the LAN via MQTT.
|
||||||
- **SQLite over PostgreSQL:** Single-node deployment on Pi Zero 2 W — no need for separate DB server
|
|
||||||
- **SSE over WebSocket:** Simpler server-side; unidirectional updates from hub → browser are sufficient
|
### Key Architecture Decisions (revised)
|
||||||
- **MQTT for ESP32 → Hub communication:** Lightweight, designed for IoT/embedded use
|
- **Closed travel router network** — No venue Wi-Fi dependency. User brings their own router. All devices on `192.168.4.0/24`.
|
||||||
- **API key auth:** Simple bearer token middleware; configurable key in `config.yaml`
|
- **ESP32 dual-STA** — One STA to GoPro AP (10.5.5.1), one STA to travel router. No channel-hopping concerns on closed network.
|
||||||
- **Idempotent migrations:** DB checks if tables exist before running migrations
|
- **ESP32 → GoPro over Wi-Fi** — Bacpac I²C route rejected (30-pin Herobus connector too complex). HTTP to GoPro AP is proven and reliable.
|
||||||
|
- **MQTT for ESP32 → Hub** — Lightweight, designed for IoT. Mosquitto on Pi. QoS 1 for status, QoS 2 for commands. Full contract: [docs/MQTT_CONTRACT.md](./docs/MQTT_CONTRACT.md)
|
||||||
|
- **SQLite over PostgreSQL** — Single-node Pi Zero 2 W deployment. WAL mode for concurrent read/write.
|
||||||
|
- **SSE over WebSocket** — Unidirectional hub → browser updates. Simpler, sufficient for status dashboard.
|
||||||
|
- **Chi router** — Lightweight Go HTTP router with middleware support.
|
||||||
|
- **Zustand over Redux** — Minimal boilerplate for camera status store.
|
||||||
|
- **API key auth** — Simple bearer token; closed LAN, not internet-facing.
|
||||||
|
- **Camera auto-discovery** — ESP32 publishes `announce` message on first MQTT connect. Hub auto-registers by MAC, assigns sequential `cam-NNN` ID.
|
||||||
|
|
||||||
## Directory Layout
|
## Directory Layout
|
||||||
|
|
||||||
@@ -194,11 +209,14 @@ read_timeout: 5s
|
|||||||
write_timeout: 10s
|
write_timeout: 10s
|
||||||
idle_timeout: 120s
|
idle_timeout: 120s
|
||||||
mqtt:
|
mqtt:
|
||||||
broker: "localhost:1883"
|
broker: "localhost:1883" # Mosquitto on Pi Zero 2 W
|
||||||
client_id: "remoterig-hub"
|
client_id: "remoterig-hub"
|
||||||
platform:
|
platform:
|
||||||
type: "pi-zero-2w"
|
type: "pi-zero-2w"
|
||||||
max_cameras: 16
|
max_cameras: 16
|
||||||
|
network:
|
||||||
|
subnet: "192.168.4.0/24" # Travel router subnet
|
||||||
|
hub_ip: "192.168.4.10" # Pi Zero 2 W static IP
|
||||||
```
|
```
|
||||||
|
|
||||||
## Frontend Component Tree
|
## Frontend Component Tree
|
||||||
@@ -233,29 +251,50 @@ Custom theme in `tailwind.config.js`:
|
|||||||
|
|
||||||
## Linear Issue Map
|
## Linear Issue Map
|
||||||
|
|
||||||
| CUB | Title | Status |
|
**Last synced:** 2026-05-21 (evening)
|
||||||
|-----|-------|--------|
|
|
||||||
| 198 | **Epic: Multi-camera remote monitoring system** | Backlog |
|
| CUB | Title | Status | Agent |
|
||||||
| 178 | UX/UI design: camera monitoring dashboard mockups | Backlog |
|
|-----|-------|--------|-------|
|
||||||
| 179 | Logging & persistence strategy | In Review |
|
| 198 | **Epic: Multi-camera remote monitoring system** | Backlog | — |
|
||||||
| 180 | Risk mitigation checklist | Done |
|
| 238 | Define MQTT message format contract | ✅ Done | Dex |
|
||||||
| 181 | Scaffold Go module, directory layout, config, main.go | Done |
|
| 228 | Add battery_calibration_offset to cameras table | Backlog | Hex |
|
||||||
| 182 | Scaffold Go module (dup of 181) | Backlog |
|
| 230 | ESP32 offline status buffering and replay | Backlog | Pip |
|
||||||
| 183 | SQLite schema migration + DB init | Backlog |
|
| 232 | Implement MQTT subscriber in Go hub | Backlog | Dex |
|
||||||
| 184 | API key auth middleware | Backlog |
|
| 229 | Design camera auto-discovery and registration flow | Backlog | Dex |
|
||||||
| 185 | Camera/StatusLog/RecordingEvent Go models | Backlog |
|
| 231 | Mosquitto MQTT broker setup on Pi Zero 2 W | Backlog | Dex |
|
||||||
| 186 | GET /api/v1/cameras (list with live status) | Backlog |
|
| 233 | Verify and harden SSE endpoint | Backlog | Dex |
|
||||||
| 187 | POST /api/v1/cameras/:id/start + MQTT publish | Done |
|
| 234 | Verify and harden all camera API endpoints | Backlog | Dex |
|
||||||
| 188 | POST /api/v1/cameras/:id/stop recording | Backlog |
|
| 235 | Implement GET /api/v1/cameras/:id with 24h history | Backlog | Dex |
|
||||||
| 189 | POST /api/v1/cameras (register new camera) | Backlog |
|
| 236 | Implement POST /api/v1/cameras registration | Backlog | Dex |
|
||||||
| 190 | GET /api/v1/cameras/:id (detail + history) | Backlog |
|
| 237 | Update CONTEXT.md to actual state | Backlog | Otto |
|
||||||
| 191 | POST /api/v1/cameras/:id/push-status (HTTP ingestion) | Backlog |
|
| — | — | — | — |
|
||||||
| 192 | MQTT subscriber for status ingestion + fan-out | Backlog |
|
| 173 | Confirm GoPro Hero 3 Wi‑Fi control API | ✅ Done | Otto |
|
||||||
| 193 | SSE /api/v1/events/stream endpoint | Backlog |
|
| 174 | ESP32 firmware baseline | ✅ Done | Pip |
|
||||||
| 194 | Scaffold Vite + React + TypeScript + Tailwind project | Done |
|
| 175 | Central hub backend (Go service) | ✅ Done | Dex |
|
||||||
| 195 | React SSE hook (useSSE.ts) | In Review |
|
| 177 | Database schema (cameras, events, status_logs) | ✅ Done | Hex |
|
||||||
| 196 | React CameraCard component with status display | Backlog |
|
| 180 | Risk mitigation checklist | ✅ Done | — |
|
||||||
| 197 | UX wireframe — main dashboard camera grid | In Review |
|
| 181 | Scaffold Go module, directory layout, config | ✅ Done | — |
|
||||||
|
| 187 | POST start recording + MQTT publish | ✅ Done | Dex |
|
||||||
|
| 194 | Scaffold Vite + React + TypeScript + Tailwind | ✅ Done | — |
|
||||||
|
| 195 | React SSE hook (useSSE.ts) + Zustand store | ✅ Done | Rex |
|
||||||
|
| 196 | CameraCard component + 16 unit tests | ✅ Done | Rex |
|
||||||
|
| 179 | Logging & persistence strategy | ✅ Done | — |
|
||||||
|
| 208 | Add README with project overview | ✅ Done | Hermes |
|
||||||
|
| 182 | ~~Duplicate of CUB-181~~ | ❌ Canceled | — |
|
||||||
|
| — | — | — | — |
|
||||||
|
| 183 | SQLite schema migration + DB init | Backlog | Hex |
|
||||||
|
| 184 | API key auth middleware | Backlog | Dex |
|
||||||
|
| 185 | Camera/StatusLog/RecordingEvent Go models | Backlog | Hex |
|
||||||
|
| 186 | GET /api/v1/cameras (list with live status) | Backlog | Dex |
|
||||||
|
| 188 | POST stop recording | Backlog | Dex |
|
||||||
|
| 189 | POST register new camera | Backlog | Dex |
|
||||||
|
| 190 | GET camera detail + history | Backlog | Dex |
|
||||||
|
| 191 | POST push-status (HTTP ingestion) | Backlog | Dex |
|
||||||
|
| 192 | MQTT subscriber | Backlog | Dex |
|
||||||
|
| 193 | SSE /api/v1/events/stream endpoint | Backlog | Dex |
|
||||||
|
| 178 | UX/UI design mockups | Backlog | Sketch |
|
||||||
|
| 197 | Dashboard camera grid wireframe | In Review | Sketch |
|
||||||
|
| 176 | Frontend umbrella (React + Tailwind) | Backlog | Rex |
|
||||||
|
|
||||||
## CI/CD Pipeline
|
## CI/CD Pipeline
|
||||||
|
|
||||||
@@ -287,11 +326,14 @@ Triggered by `workflow_dispatch`:
|
|||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
- MQTT subscriber implementation is still in Backlog (CUB-192). Currently, only HTTP status push is wired up.
|
- **MQTT subscriber not yet implemented** (CUB-232) — ESP32→hub communication backbone is designed (see [MQTT_CONTRACT.md](./docs/MQTT_CONTRACT.md)) but not built. Currently only HTTP status push is wired up.
|
||||||
- SSE endpoint implementation is in Backlog (CUB-193) — frontend SSE hook exists but backend SSE hub is placeholder.
|
- **SSE endpoint needs verification** (CUB-233) — Frontend SSE hook exists (merged PR #2), backend SSE hub code exists (140 lines) but needs heartbeat, reconnection, and integration testing.
|
||||||
- CameraCard component plan exists (`docs/plans/2026-05-21-cub-196-cameracard.md`) but implementation is pending.
|
- **No camera auto-discovery** (CUB-229) — Cameras must be manually registered. ESP32 announce protocol designed in MQTT contract but not implemented.
|
||||||
- CUB-182 is essentially a duplicate of CUB-181 (both scaffold Go module).
|
- **No battery calibration** (CUB-228) — GoPro Hero 3 reports raw byte; per-camera calibration offset column not yet added to schema.
|
||||||
- `remoterig.db` (SQLite DB file) is currently committed to the repo — should be in `.gitignore` for a production config.
|
- **No offline buffering on ESP32** (CUB-230) — If travel router Wi-Fi drops, status data is lost. SPIFFS buffer designed but not implemented.
|
||||||
|
- **CameraCard wireframe pending** (CUB-197) — Dashboard UI has live code but needs UX review/wireframe sign-off.
|
||||||
|
- **remoterig.db committed to repo** — Should be in `.gitignore` for production. Low priority (convenient for dev).
|
||||||
|
- **Time sync TBD** — ESP32s need accurate timestamps without internet. Options: Pi as NTP server, GPS module, or HTTP time endpoint. See MQTT contract open questions.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user