Files
remote-rig/firmware
Joshua King 7929d1d969
Build (Dev) / build (push) Failing after 16s
CI / quality (push) Failing after 0s
CI / quality (pull_request) Successful in 11s
registration: self-assigned camera IDs (Option B) + tolerate clockless status
Auto-registration never completed: the firmware announced on the wrong
topic, the hub never replied, and an unregistered node couldn't receive a
reply anyway. Switch to self-assigned IDs:

firmware (esp32-mqtt-bridge.cpp):
- camera_id defaults to the device id (clientID, e.g. rig-86d978)
- always subscribe to <id>/command; announce on the contract topic
  remoterig/cameras/<id>/announce (was the unmatched announce-<id> form)
- drop the bogus numeric timestamp from status (node has no clock)

hub (subscriber.go):
- handleAnnounce registers new cameras under the node's self-assigned id
  (no cam-NNN, no registered reply)
- handleStatus tolerates an empty/invalid timestamp and stamps server-side
  (previously rejected the status outright)

docs/MQTT_CONTRACT.md updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 12:14:00 -04:00
..

RemoteRig — Dual-Board Camera Node Firmware

Platform: PlatformIO (esp8266-camera + esp32-mqtt) MQTT Contract: docs/MQTT_CONTRACT.md Hardware: hardware/README.md

Architecture

Each camera node uses two boards connected via UART — zero network switching:

┌─────────────────────┐     UART      ┌─────────────────────┐
│   ESP8266 D1 Mini   │  TX──────→RX  │   ESP32 Dev Board   │
│   (Camera Bridge)   │  RX←──────TX  │   (MQTT Bridge)      │
│                     │    115200     │                      │
│  STA → GoPro AP     │    8N1        │  STA → Travel Router │
│  HTTP → 10.5.5.1    │               │  MQTT → 192.168.8.56│
│  Start/stop/status  │               │  Hub registration   │
└─────────────────────┘               └──────────────────────┘
Board Job Network Protocol
ESP8266 Camera control GoPro AP only (10.5.5.1) HTTP → UART JSON
ESP32 Hub relay Travel router only (192.168.8.x) UART JSON → MQTT

Quick Start

pip install platformio
cd firmware

# Build both
pio run -e esp8266-camera
pio run -e esp32-mqtt

# Upload to boards (connect one at a time via USB)
pio run -e esp8266-camera --target upload
pio run -e esp32-mqtt --target upload

# Upload configs (each board needs its own)
# ESP8266: copy esp8266-config.json to data/config.json, then:
pio run -e esp8266-camera --target uploadfs
# ESP32: copy esp32-config.json to data/config.json, then:
pio run -e esp32-mqtt --target uploadfs

UART Protocol (ESP8266 ↔ ESP32)

JSON-per-line at 115200 8N1. GPIO16 on both boards.

Direction Type Format Purpose
ESP8266 → ESP32 status {"type":"status","battery_raw":217,...} Camera poll result
ESP8266 → ESP32 ack {"type":"ack","cmd":"start_recording"} Command confirmation
ESP8266 → ESP32 pong {"type":"pong","uptime_ms":12345} Ping response
ESP8266 → ESP32 error {"type":"error","msg":"camera unreachable"} Error report
ESP32 → ESP8266 cmd {"type":"cmd","command":"start_recording"} Hub command
ESP32 → ESP8266 cmd {"type":"cmd","command":"ping"} Link health check

Configuration

ESP8266 (data/esp8266-config.json)

Key Default Description
camera_ssid "GOPRO-BP-" GoPro Wi-Fi AP name
camera_password "goprohero" GoPro Wi-Fi password
camera_ip "10.5.5.1" Camera IP (change for Akaso to 192.168.1.1)
poll_interval_sec 30 How often to poll camera

ESP32 (data/esp32-config.json)

Key Default Description
wifi_ssid "RemoteRig" Travel router SSID
wifi_password "" Travel router password
mqtt_broker "192.168.8.56" Pi Zero 2 W IP
mqtt_port 1883 Mosquitto port
camera_id "" Assigned by hub on first announce (leave empty)
heartbeat_interval_sec 60 MQTT heartbeat frequency

Wiring

ESP8266 D1 Mini          ESP32 Dev Board
┌────────────┐           ┌────────────┐
│            │           │            │
│  TX (GPIO1)│──────────→│ RX (GPIO16)│
│  RX (GPIO3)│←──────────│ TX (GPIO17)│
│  GND       │───────────│ GND        │
│  3.3V      │           │ 3.3V       │
│            │           │            │
└────────────┘           └────────────┘
         │                      │
         └────────┬─────────────┘
                  │
           LiPo → 3.3V Buck
           (shared power)

Boot Sequence

  1. ESP8266: Connect to GoPro AP → wait for UART commands
  2. ESP32: Connect to travel router → connect MQTT → announce if new
  3. ESP8266: Poll camera every 30s → send status over UART
  4. ESP32: Receive status → publish MQTT
  5. Hub → MQTT command → ESP32 → UART → ESP8266 → HTTP → GoPro

Camera Compatibility

Camera camera_ip Protocol Status
GoPro Hero 3 10.5.5.1 HTTP GET /bacpac/SH Full support
Akaso Brave 7 192.168.1.1 Varies 🔬 Set camera_ip, test

For non-GoPro cameras: only the ESP8266 firmware needs changes — the ESP32 stays the same.

LED Status (ESP8266)

LED Meaning
Solid on Connected to camera AP, camera responding
Slow blink (500ms) Connected to AP but camera not responding
Off Wi-Fi disconnected

Troubleshooting

Symptom Check
No UART communication Verify TX→RX crossover. Both boards at 115200. Shared GND.
ESP8266 can't connect GoPro must be ON with Wi-Fi enabled. Default password: goprohero
ESP32 can't connect MQTT systemctl status mosquitto on Pi. Port 1883 open.
Camera never registers Watch ESP32 serial for "Announced" message. Check hub logs.