Server application for QRET's propulsion test stand. Discovers and communicates with ESP32 sensor/control devices over a custom binary TCP protocol, collects sensor data, controls valves, manages IP cameras, and exposes everything through a REST API and CLI.
The server is designed to run on a Raspberry Pi (or any Linux machine / WSL) as a headless hub between ESP32 devices and any number of clients.
flowchart LR
ESP1[ESP32<br>Sensors & Valves] -->|TCP :50000| Pi
ESP2[ESP32<br>Sensors & Valves] -->|TCP :50000| Pi
Cam[IP Cameras] -->|ONVIF / RTSP| Pi
Pi[Server<br>Raspberry Pi]
subgraph Clients
direction TB
GUI[Desktop GUI]
Web[Web Client]
API[REST / WebSocket]
end
Pi -->|FastAPI :8000| GUI
Pi -->|WebRTC / RTSP| Web
Pi -->|HTTP / WS| API
Here((YOU ARE HERE)) --> Pi:::youAreHere
classDef youAreHere stroke:red, stroke-width:6px;
linkStyle 5 stroke:red,stroke-width:4px
style Here fill:transparent,stroke:none,color:red;
| Service | Description |
|---|---|
| server | Main application — device discovery (SSDP), TCP listener, FastAPI, CLI |
| redis | Logging pub/sub and real-time data relay |
| media | MediaMTX RTSP/WebRTC relay for camera streams |
| logs | Log aggregator that reads from Redis channels |
| mockdevice | Mock client device (only available in development) |
docker compose -f compose.dev.yml upThis starts all necessary services with file watching — code changes in libqretprop/ and config.yaml trigger automatic restarts.
To also run the mock device for testing, add --profile mock
docker compose -f compose.prod.yml up -dPulls pre-built images from ghcr.io/queens-rocket-engineering-team/.
uv pip install -e . # core dependencies
uv pip install -e ".[gui]" # optional: GUI tools (PySide6)
make build-protocol # build qlcp library for binary protocol
start_server # start the serverRedis must be running separately for logging to work.
The server reads config.yaml for service connections and camera definitions:
accounts:
redis:
username: server
password: ...
camera:
username: propcam
password: ...
services:
redis:
ip: localhost
port: 6379
mediamtx:
ip: localhost
api_port: 9997
webrtc_port: 8889
cameras:
- ip: 192.168.1.5
onvif_port: 2020Override the path with the PROP_CONFIG environment variable (defaults to ./config.yaml).
ESP32 devices configure themselves — each device sends a JSON CONFIG packet on connection describing its sensors and controls.
| Command | Description |
|---|---|
start_server |
Start the main server |
see_logs |
View real-time logs from Redis (-e errors, -d debug, -s system) |
mock_device |
Simulate an ESP32 device for testing |
full_gui |
Full PySide6 control panel (requires gui extra) |
Once the server is running, an interactive CLI provides commands like discover, list, stream <device> <Hz>, control <device> <name> <state>, and estop.
Devices communicate using a custom binary protocol over TCP (port 50000) and UDP (port 50001). Devices are discovered via SSDP multicast on 239.255.255.250:1900. On discovery, the device opens a TCP connection to the server and sends its CONFIG. The server then time-syncs the device and normal operation begins (streaming, control commands, heartbeats).
For more information on protocol specifications, see ctl-qlcp-lib.
For the microcontroller side of this project, see prop-esp32-logger.
This project is intended to be opened in VSCode. Install the recommended extensions when prompted.